Great PowerPC emulation code resynchronisation and improvments:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 7 Mar 2007 08:32:30 +0000 (08:32 +0000)
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
Wed, 7 Mar 2007 08:32:30 +0000 (08:32 +0000)
- Add status file to make regression tracking easier
- Move all micro-operations helpers definitions into a separate header:
  should never be seen outside of op.c
- Update copyrights
- Add new / missing PowerPC CPU definitions
- Add definitions for PowerPC BookE
- Add support for PowerPC 6xx/7xx software driven TLBs
  Allow use of PowerPC 603 as an example
- Add preliminary code for POWER, POWER2, PowerPC 403, 405, 440, 601, 602
  and BookE support
- Avoid compiling priviledged only resources support for user-mode emulation
- Remove unused helpers / micro-ops / dead code
- Add instructions usage statistics dump: useful to figure which instructions
  need strong optimizations.
- Micro-operation fixes:
  * add missing RETURN in some micro-ops
  * fix prototypes
  * use softfloat routines for all floating-point operations
  * fix tlbie instruction
  * move some huge micro-operations into helpers
- emulation fixes:
  * fix inverted opcodes for fcmpo / fcmpu
  * condition register update is always to be done after the whole
    instruction has completed
  * add missing NIP updates when calling helpers that may generate an
    exception
- optimizations and improvments:
  * optimize very often used instructions (li, mr, rlwixx...)
  * remove specific micro-ops for rarely used instructions
  * add routines for addresses computations to avoid bugs due to multiple
    different implementations
  * fix TB linking: do not reset T0 at the end of every TB.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2473 c046a42c-6fe2-441c-8c8c-71466251a162

19 files changed:
cpu-all.h
gdbstub.c
hw/ppc.c
linux-user/main.c
monitor.c
target-ppc/STATUS [new file with mode: 0644]
target-ppc/cpu.h
target-ppc/exec.h
target-ppc/helper.c
target-ppc/mfrom_table.c [new file with mode: 0644]
target-ppc/mfrom_table_gen.c [new file with mode: 0644]
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_helper.h [new file with mode: 0644]
target-ppc/op_helper_mem.h
target-ppc/op_mem.h
target-ppc/op_template.h
target-ppc/translate.c
target-ppc/translate_init.c

index 0ad50e8..86acc36 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -759,6 +759,9 @@ CPUState *cpu_copy(CPUState *env);
 void cpu_dump_state(CPUState *env, FILE *f, 
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags);
+void cpu_dump_statistics (CPUState *env, FILE *f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags);
 
 void cpu_abort(CPUState *env, const char *fmt, ...);
 extern CPUState *first_cpu;
index d1f1044..57d97e3 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -307,7 +307,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     registers[98] = tswapl(tmp);
     registers[99] = tswapl(env->lr);
     registers[100] = tswapl(env->ctr);
-    registers[101] = tswapl(do_load_xer(env));
+    registers[101] = tswapl(ppc_load_xer(env));
     registers[102] = 0;
 
     return 103 * 4;
@@ -335,7 +335,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
         env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
     env->lr = tswapl(registers[99]);
     env->ctr = tswapl(registers[100]);
-    do_store_xer(env, tswapl(registers[101]));
+    ppc_store_xer(env, tswapl(registers[101]));
 }
 #elif defined (TARGET_SPARC)
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
index b0865c1..c910cb9 100644 (file)
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -1,7 +1,7 @@
 /*
  * QEMU generic PPC hardware System Emulator
  * 
- * Copyright (c) 2003-2004 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@ static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
 {
     /* TB time in tb periods */
     return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
-                   tb_env->tb_freq, ticks_per_sec);
+                    tb_env->tb_freq, ticks_per_sec);
 }
 
 uint32_t cpu_ppc_load_tbl (CPUState *env)
@@ -52,14 +52,14 @@ uint32_t cpu_ppc_load_tbl (CPUState *env)
     tb = cpu_ppc_get_tb(tb_env);
 #ifdef DEBUG_TB
     {
-         static int last_time;
-        int now;
-        now = time(NULL);
-        if (last_time != now) {
-            last_time = now;
-            printf("%s: tb=0x%016lx %d %08lx\n",
-                    __func__, tb, now, tb_env->tb_offset);
-        }
+        static int last_time;
+        int now;
+        now = time(NULL);
+        if (last_time != now) {
+            last_time = now;
+            printf("%s: tb=0x%016lx %d %08lx\n",
+                   __func__, tb, now, tb_env->tb_offset);
+        }
     }
 #endif
 
@@ -75,6 +75,7 @@ uint32_t cpu_ppc_load_tbu (CPUState *env)
 #ifdef DEBUG_TB
     printf("%s: tb=0x%016lx\n", __func__, tb);
 #endif
+
     return tb >> 32;
 }
 
@@ -117,6 +118,7 @@ uint32_t cpu_ppc_load_decr (CPUState *env)
 #if defined(DEBUG_TB)
     printf("%s: 0x%08x\n", __func__, decr);
 #endif
+
     return decr;
 }
 
@@ -146,7 +148,7 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
     if (is_excp)
         next += tb_env->decr_next - now;
     if (next == now)
-       next++;
+        next++;
     tb_env->decr_next = next;
     /* Adjust timer */
     qemu_mod_timer(tb_env->decr_timer, next);
@@ -154,7 +156,7 @@ static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
      * raise an exception.
      */
     if ((value & 0x80000000) && !(decr & 0x80000000))
-       cpu_ppc_decr_excp(env);
+        cpu_ppc_decr_excp(env);
 }
 
 void cpu_ppc_store_decr (CPUState *env, uint32_t value)
@@ -177,20 +179,64 @@ ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
         return NULL;
     env->tb_env = tb_env;
     if (tb_env->tb_freq == 0 || 1) {
-       tb_env->tb_freq = freq;
-       /* Create new timer */
-       tb_env->decr_timer =
+        tb_env->tb_freq = freq;
+        /* Create new timer */
+        tb_env->decr_timer =
             qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
-       /* There is a bug in  2.4 kernels:
-        * if a decrementer exception is pending when it enables msr_ee,
-        * it's not ready to handle it...
-        */
-       _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+        /* There is a bug in Linux 2.4 kernels:
+         * if a decrementer exception is pending when it enables msr_ee,
+         * it's not ready to handle it...
+         */
+        _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
     }
 
     return tb_env;
 }
 
+/* Specific helpers for POWER & PowerPC 601 RTC */
+ppc_tb_t *cpu_ppc601_rtc_init (CPUState *env)
+{
+    return cpu_ppc_tb_init(env, 7812500);
+}
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+__attribute__ (( alias ("cpu_ppc_store_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
+{
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/* Embedded PowerPC timers */
+target_ulong load_40x_pit (CPUState *env)
+{
+    /* XXX: TODO */
+    return 0;
+}
+
+void store_40x_pit (CPUState *env, target_ulong val)
+{
+    /* XXX: TODO */
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val)
+{
+    /* XXX: TODO */
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val)
+{
+    /* XXX: TODO */
+}
+
 #if 0
 /*****************************************************************************/
 /* Handle system reset (for now, just stop emulation) */
@@ -264,6 +310,7 @@ uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
     tmp |= m48t59_read(nvram, addr + 1) << 16;
     tmp |= m48t59_read(nvram, addr + 2) << 8;
     tmp |= m48t59_read(nvram, addr + 3);
+
     return tmp;
 }
 
@@ -316,10 +363,10 @@ uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
     odd = count & 1;
     count &= ~1;
     for (i = 0; i != count; i++) {
-       crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
     }
     if (odd) {
-       crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
     }
 
     return crc;
index 3671384..702c3b9 100644 (file)
@@ -670,18 +670,23 @@ void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
 {
     cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
 }
-  
-uint32_t cpu_ppc_load_decr (CPUState *env)
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+__attribute__ (( alias ("cpu_ppc_store_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
 {
-    /* TO FIX */
-    return -1;
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
 }
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 {
-    /* TO FIX */
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
 }
+
 void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
index 43ebe01..de0783b 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -331,6 +331,17 @@ static void do_info_history (void)
     }
 }
 
+#if defined(TARGET_PPC)
+/* XXX: not implemented in other targets */
+static void do_info_cpu_stats (void)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+    cpu_dump_statistics(env, NULL, &monitor_fprintf, 0);
+}
+#endif
+
 static void do_quit(void)
 {
     exit(0);
@@ -1303,6 +1314,10 @@ static term_cmd_t info_cmds[] = {
       "", "show which guest mouse is receiving events" },
     { "vnc", "", do_info_vnc,
       "", "show the vnc server status"},
+#if defined(TARGET_PPC)
+    { "cpustats", "", do_info_cpu_stats,
+      "", "show CPU statistics", },
+#endif
     { NULL, NULL, },
 };
 
diff --git a/target-ppc/STATUS b/target-ppc/STATUS
new file mode 100644 (file)
index 0000000..d5089f7
--- /dev/null
@@ -0,0 +1,91 @@
+PowerPC emulation status.
+The goal of this file is to provide a reference status to avoid regressions.
+
+===============================================================================
+PowerPC core emulation status
+
+PowerPC CPU known to work (ie booting at least Linux 2.4):
+* main stream PowerPC cores
+- PowerPC 603 & derivatives
+- PowerPC 604 & derivatives
+- PowerPC 740 & derivatives
+- PowerPC 750 & derivatives
+
+PowerPC that should work but are not supported by standard Linux kernel
+(then remain mostly untested)
+- PowerPC 745
+- PowerPC 755
+
+Work in progress:
+* embedded PowerPC cores
+- PowerPC 405
+- BookE PowerPC
+- e500 core (Freescale PowerQUICC)
+* main stream PowerPC cores
+- PowerPC 601
+- PowerPC 602
+
+TODO:
+* embedded PowerPC cores
+- PowerPC 401
+- PowerPC 403
+- PowerPC 440
+- PowerPC 460
+* main stream PowerPC cores
+- PowerPC 7400 (aka G4)
+- PowerPC 7410
+- PowerPC 7450
+- PowerPC 7455
+- PowerPC 7457
+- PowerPC 7457A
+* original POWER
+- POWER
+- POWER2
+* 64 bits PowerPC cores
+- PowerPC 620
+- PowerPC 630 (aka POWER3)
+- PowerPC 631 (aka POWER3+)
+- POWER4
+- POWER4+
+- POWER5
+- POWER5+
+- PowerPC 970
+* RS64 series
+- RS64
+- RS64-II
+- RS64-III
+- RS64-IV
+
+===============================================================================
+PowerPC microcontrollers emulation status
+
+TODO:
+- PowerPC 40x microcontrollers emulation
+- PowerQUICC microcontrollers emulation
+
+===============================================================================
+PowerPC based platforms emulation status
+
+* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* mac99 platform (white and blue PowerMac, ...)
+- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
+- Debian Linux woody - boots from CDROM and HDD
+- Mandrake Linux 9 - boots from CDROM, freezes during install
+
+TODO:
+- MCA based RS/6000 emulation
+- CHRP emulation (not PowerMac)
+- PPAR emulation
+- misc PowerPC reference boards emulation
+
+===============================================================================
+(to be completed)
index b294e31..8abb324 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation cpu definitions for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #define __CPU_PPC_H__
 
 #include "config.h"
+#include <stdint.h>
 
+#if defined (TARGET_PPC64)
+typedef uint64_t ppc_gpr_t;
+#define TARGET_LONG_BITS 64
+#define REGX "%016" PRIx64
+#elif defined(TARGET_E500)
+/* GPR are 64 bits: used by vector extension */
+typedef uint64_t ppc_gpr_t;
 #define TARGET_LONG_BITS 32
+#define REGX "%08" PRIx32
+#else
+typedef uint32_t ppc_gpr_t;
+#define TARGET_LONG_BITS 32
+#define REGX "%08" PRIx32
+#endif
 
 #include "cpu-defs.h"
 
 
 #define TARGET_HAS_ICE 1
 
-#define ELF_MACHINE    EM_PPC
+#if defined (TARGET_PPC64)
+#define ELF_MACHINE     EM_PPC64
+#else
+#define ELF_MACHINE     EM_PPC
+#endif
 
 /* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
  *                              have different cache line sizes
@@ -42,6 +60,7 @@
 
 /* XXX: put this in a common place */
 #define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
 
 /*****************************************************************************/
 /* PVR definitions for most known PowerPC */
@@ -54,72 +73,155 @@ enum {
     CPU_PPC_401E2     = 0x00250000,
     CPU_PPC_401F2     = 0x00260000,
     CPU_PPC_401G2     = 0x00270000,
-    CPU_PPC_IOP480    = 0x40100000,
+#define CPU_PPC_401 CPU_PPC_401G2
+    CPU_PPC_IOP480    = 0x40100000, /* 401B2 ? */
+    CPU_PPC_COBRA     = 0x10100000, /* IBM Processor for Network Resources */
     /* PowerPC 403 cores */
-    CPU_PPC_403GA     = 0x00200000,
+    CPU_PPC_403GA     = 0x00200011,
     CPU_PPC_403GB     = 0x00200100,
     CPU_PPC_403GC     = 0x00200200,
     CPU_PPC_403GCX    = 0x00201400,
+#define CPU_PPC_403 CPU_PPC_403GCX
     /* PowerPC 405 cores */
-    CPU_PPC_405       = 0x40110000,
-    CPU_PPC_405EP     = 0x51210000,
-    CPU_PPC_405GPR    = 0x50910000,
+    CPU_PPC_405CR     = 0x40110145,
+#define CPU_PPC_405GP CPU_PPC_405CR
+    CPU_PPC_405EP     = 0x51210950,
+    CPU_PPC_405GPR    = 0x50910951,
     CPU_PPC_405D2     = 0x20010000,
     CPU_PPC_405D4     = 0x41810000,
-    CPU_PPC_NPE405H   = 0x41410000,
-    CPU_PPC_NPE405L   = 0x41610000,
+#define CPU_PPC_405 CPU_PPC_405D4
+    CPU_PPC_NPE405H   = 0x414100C0,
+    CPU_PPC_NPE405H2  = 0x41410140,
+    CPU_PPC_NPE405L   = 0x416100C0,
+    /* XXX: missing 405LP, LC77700 */
+    /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */
+#if 0
+    CPU_PPC_STB01000  = xxx,
+#endif
 #if 0
-    CPU_PPC_STB02     = xxx,
+    CPU_PPC_STB01010  = xxx,
+#endif
+#if 0
+    CPU_PPC_STB0210   = xxx,
 #endif
     CPU_PPC_STB03     = 0x40310000,
 #if 0
-    CPU_PPC_STB04     = xxx,
+    CPU_PPC_STB043    = xxx,
 #endif
-    CPU_PPC_STB25     = 0x51510000,
+#if 0
+    CPU_PPC_STB045    = xxx,
+#endif
+    CPU_PPC_STB25     = 0x51510950,
 #if 0
     CPU_PPC_STB130    = xxx,
 #endif
+    /* Xilinx cores */
+    CPU_PPC_X2VP4     = 0x20010820,
+#define CPU_PPC_X2VP7 CPU_PPC_X2VP4
+    CPU_PPC_X2VP20    = 0x20010860,
+#define CPU_PPC_X2VP50 CPU_PPC_X2VP20
     /* PowerPC 440 cores */
-    CPU_PPC_440EP     = 0x42220000,
-    CPU_PPC_440GP     = 0x40120400,
-    CPU_PPC_440GX     = 0x51B20000,
-    /* PowerPC MPC 8xx cores */
-    CPU_PPC_8540      = 0x80200000,
+    CPU_PPC_440EP     = 0x422218D3,
+#define CPU_PPC_440GR CPU_PPC_440EP
+    CPU_PPC_440GP     = 0x40120481,
+    CPU_PPC_440GX     = 0x51B21850,
+    CPU_PPC_440GXc    = 0x51B21892,
+    CPU_PPC_440GXf    = 0x51B21894,
+    CPU_PPC_440SP     = 0x53221850,
+    CPU_PPC_440SP2    = 0x53221891,
+    CPU_PPC_440SPE    = 0x53421890,
+    /* XXX: missing 440GRX */
+    /* PowerPC 460 cores - TODO */
+    /* PowerPC MPC 5xx cores */
+    CPU_PPC_5xx       = 0x00020020,
+    /* PowerPC MPC 8xx cores (aka PowerQUICC) */
     CPU_PPC_8xx       = 0x00500000,
-    CPU_PPC_8240      = 0x00810100,
-    CPU_PPC_8245      = 0x00811014,
+    /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */
+    CPU_PPC_82xx_HIP3 = 0x00810101,
+    CPU_PPC_82xx_HIP4 = 0x80811014,
+    CPU_PPC_827x      = 0x80822013,
+    /* eCores */
+    CPU_PPC_e200      = 0x81120000,
+    CPU_PPC_e500v110  = 0x80200010,
+    CPU_PPC_e500v120  = 0x80200020,
+    CPU_PPC_e500v210  = 0x80210010,
+    CPU_PPC_e500v220  = 0x80210020,
+#define CPU_PPC_e500 CPU_PPC_e500v220
+    CPU_PPC_e600      = 0x80040010,
     /* PowerPC 6xx cores */
-    CPU_PPC_601       = 0x00010000,
-    CPU_PPC_602       = 0x00050000,
-    CPU_PPC_603       = 0x00030000,
-    CPU_PPC_603E      = 0x00060000,
-    CPU_PPC_603EV     = 0x00070000,
-    CPU_PPC_603R      = 0x00071000,
-    CPU_PPC_G2        = 0x80810000,
-    CPU_PPC_G2LE      = 0x80820000,
+    CPU_PPC_601       = 0x00010001,
+    CPU_PPC_602       = 0x00050100,
+    CPU_PPC_603       = 0x00030100,
+    CPU_PPC_603E      = 0x00060101,
+    CPU_PPC_603P      = 0x00070000,
+    CPU_PPC_603E7v    = 0x00070100,
+    CPU_PPC_603E7v2   = 0x00070201,
+    CPU_PPC_603E7     = 0x00070200,
+    CPU_PPC_603R      = 0x00071201,
+    CPU_PPC_G2        = 0x00810011,
+    CPU_PPC_G2H4      = 0x80811010,
+    CPU_PPC_G2gp      = 0x80821010,
+    CPU_PPC_G2ls      = 0x90810010,
+    CPU_PPC_G2LE      = 0x80820010,
+    CPU_PPC_G2LEgp    = 0x80822010,
+    CPU_PPC_G2LEls    = 0xA0822010,
     CPU_PPC_604       = 0x00040000,
-    CPU_PPC_604E      = 0x00090000,
-    CPU_PPC_604R      = 0x000a0000,
+    CPU_PPC_604E      = 0x00090100, /* Also 2110 & 2120 */
+    CPU_PPC_604R      = 0x000a0101,
     /* PowerPC 74x/75x cores (aka G3) */
     CPU_PPC_74x       = 0x00080000,
-    CPU_PPC_755       = 0x00083000,
+    CPU_PPC_740E      = 0x00080100,
+    CPU_PPC_750E      = 0x00080200,
+    CPU_PPC_755_10    = 0x00083100,
+    CPU_PPC_755_11    = 0x00083101,
+    CPU_PPC_755_20    = 0x00083200,
+    CPU_PPC_755D      = 0x00083202,
+    CPU_PPC_755E      = 0x00083203,
+#define CPU_PPC_755 CPU_PPC_755E
     CPU_PPC_74xP      = 0x10080000,
-    CPU_PPC_750CXE22  = 0x00082202,
+    CPU_PPC_750CXE21  = 0x00082201,
+    CPU_PPC_750CXE22  = 0x00082212,
+    CPU_PPC_750CXE23  = 0x00082203,
     CPU_PPC_750CXE24  = 0x00082214,
     CPU_PPC_750CXE24b = 0x00083214,
     CPU_PPC_750CXE31  = 0x00083211,
     CPU_PPC_750CXE31b = 0x00083311,
 #define CPU_PPC_750CXE CPU_PPC_750CXE31b
-    CPU_PPC_750FX     = 0x70000000,
-    CPU_PPC_750GX     = 0x70020000,
+    CPU_PPC_750CXR    = 0x00083410,
+    CPU_PPC_750FX10   = 0x70000100,
+    CPU_PPC_750FX20   = 0x70000200,
+    CPU_PPC_750FX21   = 0x70000201,
+    CPU_PPC_750FX22   = 0x70000202,
+    CPU_PPC_750FX23   = 0x70000203,
+#define CPU_PPC_750FX CPU_PPC_750FX23
+    CPU_PPC_750FL     = 0x700A0203,
+    CPU_PPC_750GX10   = 0x70020100,
+    CPU_PPC_750GX11   = 0x70020101,
+    CPU_PPC_750GX12   = 0x70020102,
+#define CPU_PPC_750GX CPU_PPC_750GX12
+    CPU_PPC_750GL     = 0x70020102,
+    CPU_PPC_750L30    = 0x00088300,
+    CPU_PPC_750L32    = 0x00088302,
+    CPU_PPC_750CL     = 0x00087200,
     /* PowerPC 74xx cores (aka G4) */
-    CPU_PPC_7400      = 0x000C0000,
-    CPU_PPC_7410      = 0x800C0000,
-    CPU_PPC_7441      = 0x80000200,
-    CPU_PPC_7450      = 0x80000000,
+    CPU_PPC_7400      = 0x000C0100,
+    CPU_PPC_7410C     = 0x800C1102,
+    CPU_PPC_7410D     = 0x800C1103,
+    CPU_PPC_7410E     = 0x800C1104,
+    CPU_PPC_7441      = 0x80000210,
+    CPU_PPC_7445      = 0x80010100,
+    CPU_PPC_7447      = 0x80020100,
+    CPU_PPC_7447A     = 0x80030101,
+    CPU_PPC_7448      = 0x80040100,
+    CPU_PPC_7450      = 0x80000200,
+    CPU_PPC_7450b     = 0x80000201,
     CPU_PPC_7451      = 0x80000203,
-    CPU_PPC_7455      = 0x80010000,
-    CPU_PPC_7457      = 0x80020000,
+    CPU_PPC_7451G     = 0x80000210,
+    CPU_PPC_7455      = 0x80010201,
+    CPU_PPC_7455F     = 0x80010303,
+    CPU_PPC_7455G     = 0x80010304,
+    CPU_PPC_7457      = 0x80020101,
+    CPU_PPC_7457C     = 0x80020102,
     CPU_PPC_7457A     = 0x80030000,
     /* 64 bits PowerPC */
     CPU_PPC_620       = 0x00140000,
@@ -130,7 +232,21 @@ enum {
     CPU_PPC_POWER5    = 0x003A0000,
     CPU_PPC_POWER5P   = 0x003B0000,
     CPU_PPC_970       = 0x00390000,
-    CPU_PPC_970FX     = 0x003C0000,
+    CPU_PPC_970FX10   = 0x00391100,
+    CPU_PPC_970FX20   = 0x003C0200,
+    CPU_PPC_970FX21   = 0x003C0201,
+    CPU_PPC_970FX30   = 0x003C0300,
+    CPU_PPC_970FX31   = 0x003C0301,
+#define CPU_PPC_970FX CPU_PPC_970FX31
+    CPU_PPC_970MP10   = 0x00440100,
+    CPU_PPC_970MP11   = 0x00440101,
+#define CPU_PPC_970MP CPU_PPC_970MP11
+    CPU_PPC_CELL10    = 0x00700100,
+    CPU_PPC_CELL20    = 0x00700400,
+    CPU_PPC_CELL30    = 0x00700500,
+    CPU_PPC_CELL31    = 0x00700501,
+#define CPU_PPC_CELL32 CPU_PPC_CELL31
+#define CPU_PPC_CELL CPU_PPC_CELL32
     CPU_PPC_RS64      = 0x00330000,
     CPU_PPC_RS64II    = 0x00340000,
     CPU_PPC_RS64III   = 0x00360000,
@@ -147,12 +263,28 @@ enum {
 #endif
 };
 
-/* System version register (used on MPC 8xx) */
+/* System version register (used on MPC 8xxx) */
 enum {
     PPC_SVR_8540      = 0x80300000,
-    PPC_SVR_8541E     = 0x807A0000,
-    PPC_SVR_8555E     = 0x80790000,
-    PPC_SVR_8560      = 0x80700000,
+    PPC_SVR_8541E     = 0x807A0010,
+    PPC_SVR_8543v10   = 0x80320010,
+    PPC_SVR_8543v11   = 0x80320011,
+    PPC_SVR_8543v20   = 0x80320020,
+    PPC_SVR_8543Ev10  = 0x803A0010,
+    PPC_SVR_8543Ev11  = 0x803A0011,
+    PPC_SVR_8543Ev20  = 0x803A0020,
+    PPC_SVR_8545      = 0x80310220,
+    PPC_SVR_8545E     = 0x80390220,
+    PPC_SVR_8547E     = 0x80390120,
+    PPC_SCR_8548v10   = 0x80310010,
+    PPC_SCR_8548v11   = 0x80310011,
+    PPC_SCR_8548v20   = 0x80310020,
+    PPC_SVR_8548Ev10  = 0x80390010,
+    PPC_SVR_8548Ev11  = 0x80390011,
+    PPC_SVR_8548Ev20  = 0x80390020,
+    PPC_SVR_8555E     = 0x80790010,
+    PPC_SVR_8560v10   = 0x80700010,
+    PPC_SVR_8560v20   = 0x80700020,
 };
 
 /*****************************************************************************/
@@ -197,7 +329,7 @@ enum {
     /* Time base support                           */
     PPC_TB          = 0x00002000,
     /* Embedded PowerPC dedicated instructions     */
-    PPC_4xx_COMMON  = 0x00004000,
+    PPC_EMB_COMMON  = 0x00004000,
     /* PowerPC 40x exception model                 */
     PPC_40x_EXCP    = 0x00008000,
     /* PowerPC 40x specific instructions           */
@@ -225,12 +357,20 @@ enum {
     PPC_64H         = 0x02000000,
     /* 64 bits PowerPC "bridge" features           */
     PPC_64_BRIDGE   = 0x04000000,
+    /* BookE (embedded) PowerPC specification      */
+    PPC_BOOKE       = 0x08000000,
+    /* eieio */
+    PPC_MEM_EIEIO   = 0x10000000,
+    /* e500 vector instructions */
+    PPC_E500_VECTOR = 0x20000000,
+    /* PowerPC 4xx dedicated instructions     */
+    PPC_4xx_COMMON  = 0x40000000,
 };
 
 /* CPU run-time flags (MMU and exception model) */
 enum {
     /* MMU model */
-#define PPC_FLAGS_MMU_MASK (0x0000000F)
+    PPC_FLAGS_MMU_MASK     = 0x0000000F,
     /* Standard 32 bits PowerPC MMU */
     PPC_FLAGS_MMU_32B      = 0x00000000,
     /* Standard 64 bits PowerPC MMU */
@@ -243,8 +383,10 @@ enum {
     PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
     /* PowerPC 403 MMU */
     PPC_FLAGS_MMU_403      = 0x00000005,
+    /* Freescale e500 MMU model */
+    PPC_FLAGS_MMU_e500     = 0x00000006,
     /* Exception model */
-#define PPC_FLAGS_EXCP_MASK (0x000000F0)
+    PPC_FLAGS_EXCP_MASK    = 0x000000F0,
     /* Standard PowerPC exception model */
     PPC_FLAGS_EXCP_STD     = 0x00000000,
     /* PowerPC 40x exception model */
@@ -277,32 +419,42 @@ enum {
 #define PPC_FLAGS_TODO (0x00000000)
 
 /* PowerPC 40x instruction set */
-#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON)
+#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_EMB_COMMON)
 /* PowerPC 401 */
 #define PPC_INSNS_401 (PPC_INSNS_TODO)
 #define PPC_FLAGS_401 (PPC_FLAGS_TODO)
 /* PowerPC 403 */
-#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA |         \
-                       PPC_40x_EXCP | PPC_40x_SPEC)
+#define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO |         \
+                       PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP |        \
+                       PPC_40x_SPEC)
 #define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x)
 /* PowerPC 405 */
-#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT |         \
-                       PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \
+#define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO |         \
+                       PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB |               \
+                       PPC_4xx_COMMON | PPC_40x_SPEC |  PPC_40x_EXCP |        \
                        PPC_405_MAC)
 #define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
 /* PowerPC 440 */
-#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC |          \
-                       PPC_440_SPEC)
+#define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE |            \
+                       PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC)
 #define PPC_FLAGS_440 (PPC_FLAGS_TODO)
+/* Generic BookE PowerPC */
+#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO |          \
+                         PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT)
+#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
+/* e500 core */
+#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO |           \
+                        PPC_CACHE_OPT | PPC_E500_VECTOR)
+#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
 /* Non-embedded PowerPC */
 #define PPC_INSNS_COMMON  (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC |        \
-                           PPC_SEGMENT | PPC_MEM_TLBIE)
+                            PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE)
 /* PowerPC 601 */
 #define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR)
 #define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601)
 /* PowerPC 602 */
 #define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |       \
-                       PPC_MEM_TLBSYNC | PPC_TB)
+                       PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC)
 #define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602)
 /* PowerPC 603 */
 #define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |       \
@@ -348,13 +500,17 @@ typedef struct ppc_tb_t ppc_tb_t;
 typedef struct ppc_spr_t ppc_spr_t;
 typedef struct ppc_dcr_t ppc_dcr_t;
 typedef struct ppc_avr_t ppc_avr_t;
+typedef struct ppc_tlb_t ppc_tlb_t;
+
 
 /* SPR access micro-ops generations callbacks */
 struct ppc_spr_t {
     void (*uea_read)(void *opaque, int spr_num);
     void (*uea_write)(void *opaque, int spr_num);
+#if !defined(CONFIG_USER_ONLY)
     void (*oea_read)(void *opaque, int spr_num);
     void (*oea_write)(void *opaque, int spr_num);
+#endif
     const unsigned char *name;
 };
 
@@ -364,46 +520,42 @@ struct ppc_avr_t {
 };
 
 /* Software TLB cache */
-typedef struct ppc_tlb_t ppc_tlb_t;
 struct ppc_tlb_t {
-    /* Physical page number */
-    target_phys_addr_t RPN;
-    /* Virtual page number */
-    target_ulong VPN;
-    /* Page size */
-    target_ulong size;
-    /* Protection bits */
-    int prot;
-    int is_user;
-    uint32_t private;
-    uint32_t flags;
+    target_ulong pte0;
+    target_ulong pte1;
+    target_ulong EPN;
+    target_ulong PID;
+    int size;
 };
 
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
-#define MSR_SF   63 /* Sixty-four-bit mode                                   */
+#define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
 #define MSR_ISF  61 /* Sixty-four-bit interrupt mode on 630                  */
-#define MSR_HV   60 /* hypervisor state                                      */
-#define MSR_VR   25 /* altivec available                                     */
-#define MSR_AP   23 /* Access privilege state on 602                         */
-#define MSR_SA   22 /* Supervisor access mode on 602                         */
+#define MSR_HV   60 /* hypervisor state                               hflags */
+#define MSR_UCLE 26 /* User-mode cache lock enable on e500                   */
+#define MSR_VR   25 /* altivec available                              hflags */
+#define MSR_SPE  25 /* SPE enable on e500                             hflags */
+#define MSR_AP   23 /* Access privilege state on 602                  hflags */
+#define MSR_SA   22 /* Supervisor access mode on 602                  hflags */
 #define MSR_KEY  19 /* key bit on 603e                                       */
 #define MSR_POW  18 /* Power management                                      */
 #define MSR_WE   18 /* Wait state enable on embedded PowerPC                 */
 #define MSR_TGPR 17 /* TGPR usage on 602/603                                 */
-#define MSR_TLB  17 /* TLB on ?                                              */
+#define MSR_TLB  17 /* TLB update on ?                                       */
 #define MSR_CE   17 /* Critical interrupt enable on embedded PowerPC         */
 #define MSR_ILE  16 /* Interrupt little-endian mode                          */
 #define MSR_EE   15 /* External interrupt enable                             */
-#define MSR_PR   14 /* Problem state                                         */
-#define MSR_FP   13 /* Floating point available                              */
+#define MSR_PR   14 /* Problem state                                  hflags */
+#define MSR_FP   13 /* Floating point available                       hflags */
 #define MSR_ME   12 /* Machine check interrupt enable                        */
-#define MSR_FE0  11 /* Floating point exception mode 0                       */
-#define MSR_SE   10 /* Single-step trace enable                              */
+#define MSR_FE0  11 /* Floating point exception mode 0                hflags */
+#define MSR_SE   10 /* Single-step trace enable                       hflags */
 #define MSR_DWE  10 /* Debug wait enable on 405                              */
-#define MSR_BE   9  /* Branch trace enable                                   */
+#define MSR_UBLE 10 /* User BTB lock enable on e500                          */
+#define MSR_BE   9  /* Branch trace enable                            hflags */
 #define MSR_DE   9  /* Debug interrupts enable on embedded PowerPC           */
-#define MSR_FE1  8  /* Floating point exception mode 1                       */
+#define MSR_FE1  8  /* Floating point exception mode 1                hflags */
 #define MSR_AL   7  /* AL bit on POWER                                       */
 #define MSR_IP   6  /* Interrupt prefix                                      */
 #define MSR_IR   5  /* Instruction relocate                                  */
@@ -415,42 +567,45 @@ struct ppc_tlb_t {
 #define MSR_PX   2  /* Protection exclusive on 403                           */
 #define MSR_PMM  2  /* Performance monitor mark on POWER                     */
 #define MSR_RI   1  /* Recoverable interrupt                                 */
-#define MSR_LE   0  /* Little-endian mode                                    */
+#define MSR_LE   0  /* Little-endian mode                             hflags */
 #define msr_sf   env->msr[MSR_SF]
 #define msr_isf  env->msr[MSR_ISF]
 #define msr_hv   env->msr[MSR_HV]
+#define msr_ucle env->msr[MSR_UCLE]
 #define msr_vr   env->msr[MSR_VR]
+#define msr_spe  env->msr[MSR_SPE]
 #define msr_ap   env->msr[MSR_AP]
 #define msr_sa   env->msr[MSR_SA]
 #define msr_key  env->msr[MSR_KEY]
-#define msr_pow env->msr[MSR_POW]
+#define msr_pow  env->msr[MSR_POW]
 #define msr_we   env->msr[MSR_WE]
 #define msr_tgpr env->msr[MSR_TGPR]
 #define msr_tlb  env->msr[MSR_TLB]
 #define msr_ce   env->msr[MSR_CE]
-#define msr_ile env->msr[MSR_ILE]
-#define msr_ee  env->msr[MSR_EE]
-#define msr_pr  env->msr[MSR_PR]
-#define msr_fp  env->msr[MSR_FP]
-#define msr_me  env->msr[MSR_ME]
-#define msr_fe0 env->msr[MSR_FE0]
-#define msr_se  env->msr[MSR_SE]
+#define msr_ile  env->msr[MSR_ILE]
+#define msr_ee   env->msr[MSR_EE]
+#define msr_pr   env->msr[MSR_PR]
+#define msr_fp   env->msr[MSR_FP]
+#define msr_me   env->msr[MSR_ME]
+#define msr_fe0  env->msr[MSR_FE0]
+#define msr_se   env->msr[MSR_SE]
 #define msr_dwe  env->msr[MSR_DWE]
-#define msr_be  env->msr[MSR_BE]
+#define msr_uble env->msr[MSR_UBLE]
+#define msr_be   env->msr[MSR_BE]
 #define msr_de   env->msr[MSR_DE]
-#define msr_fe1 env->msr[MSR_FE1]
+#define msr_fe1  env->msr[MSR_FE1]
 #define msr_al   env->msr[MSR_AL]
-#define msr_ip  env->msr[MSR_IP]
-#define msr_ir  env->msr[MSR_IR]
+#define msr_ip   env->msr[MSR_IP]
+#define msr_ir   env->msr[MSR_IR]
 #define msr_is   env->msr[MSR_IS]
-#define msr_dr  env->msr[MSR_DR]
+#define msr_dr   env->msr[MSR_DR]
 #define msr_ds   env->msr[MSR_DS]
 #define msr_pe   env->msr[MSR_PE]
 #define msr_ep   env->msr[MSR_EP]
 #define msr_px   env->msr[MSR_PX]
 #define msr_pmm  env->msr[MSR_PMM]
-#define msr_ri  env->msr[MSR_RI]
-#define msr_le  env->msr[MSR_LE]
+#define msr_ri   env->msr[MSR_RI]
+#define msr_le   env->msr[MSR_LE]
 
 /*****************************************************************************/
 /* The whole PowerPC CPU context */
@@ -465,7 +620,7 @@ struct CPUPPCState {
     target_ulong t0, t1, t2;
 #endif
     /* general purpose registers */
-    target_ulong gpr[32];
+    ppc_gpr_t gpr[32];
     /* LR */
     target_ulong lr;
     /* CTR */
@@ -482,10 +637,10 @@ struct CPUPPCState {
     /* machine state register */
     uint8_t msr[64];
     /* temporary general purpose registers */
-    target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+    ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */
 
     /* Floating point execution context */
-     /* temporary float registers */
+    /* temporary float registers */
     float64 ft0;
     float64 ft1;
     float64 ft2;
@@ -529,9 +684,12 @@ struct CPUPPCState {
     ppc_dcr_t *dcr_env;
 
     /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
-    int nb_tlb;
-    int nb_ways, last_way;
-    ppc_tlb_t tlb[128];
+    int nb_tlb;      /* Total number of TLB                                  */
+    int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
+    int nb_ways;     /* Number of ways in the TLB set                        */
+    int last_way;    /* Last used way used to allocate TLB in a LRU way      */
+    int id_tlbs;     /* If 1, MMU has separated TLBs for instructions & data */
+    ppc_tlb_t *tlb;  /* TLB is optional. Allocate them only if needed        */
     /* Callbacks for specific checks on some implementations */
     int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot,
                           target_ulong vaddr, int rw, int acc_type,
@@ -568,6 +726,16 @@ struct CPUPPCState {
     int (*osi_call)(struct CPUPPCState *env);
 };
 
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+    target_phys_addr_t raddr;      /* Real address              */
+    int prot;                      /* Protection bits           */
+    target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+    target_ulong ptem;             /* Virtual segment ID | API  */
+    int key;                       /* Access key                */
+};
+
 /*****************************************************************************/
 CPUPPCState *cpu_ppc_init(void);
 int cpu_ppc_exec(CPUPPCState *s);
@@ -583,6 +751,7 @@ void cpu_loop_exit(void);
 
 void dump_stack (CPUPPCState *env);
 
+#if !defined(CONFIG_USER_ONLY)
 target_ulong do_load_ibatu (CPUPPCState *env, int nr);
 target_ulong do_load_ibatl (CPUPPCState *env, int nr);
 void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
@@ -591,23 +760,17 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr);
 target_ulong do_load_dbatl (CPUPPCState *env, int nr);
 void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
 void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
-
-target_ulong do_load_nip (CPUPPCState *env);
-void do_store_nip (CPUPPCState *env, target_ulong value);
 target_ulong do_load_sdr1 (CPUPPCState *env);
 void do_store_sdr1 (CPUPPCState *env, target_ulong value);
 target_ulong do_load_asr (CPUPPCState *env);
 void do_store_asr (CPUPPCState *env, target_ulong value);
 target_ulong do_load_sr (CPUPPCState *env, int srnum);
 void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
-uint32_t do_load_cr (CPUPPCState *env);
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask);
-uint32_t do_load_xer (CPUPPCState *env);
-void do_store_xer (CPUPPCState *env, uint32_t value);
+#endif
+uint32_t ppc_load_xer (CPUPPCState *env);
+void ppc_store_xer (CPUPPCState *env, uint32_t value);
 target_ulong do_load_msr (CPUPPCState *env);
 void do_store_msr (CPUPPCState *env, target_ulong value);
-float64 do_load_fpscr (CPUPPCState *env);
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask);
 
 void do_compute_hflags (CPUPPCState *env);
 
@@ -645,261 +808,294 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
 #define xer_bc env->xer[0]
 
 /* SPR definitions */
-#define SPR_MQ         (0x000)
-#define SPR_XER        (0x001)
-#define SPR_601_VRTCU  (0x004)
-#define SPR_601_VRTCL  (0x005)
-#define SPR_601_UDECR  (0x006)
-#define SPR_LR         (0x008)
-#define SPR_CTR        (0x009)
-#define SPR_DSISR      (0x012)
-#define SPR_DAR        (0x013)
-#define SPR_601_RTCU   (0x014)
-#define SPR_601_RTCL   (0x015)
-#define SPR_DECR       (0x016)
-#define SPR_SDR1       (0x019)
-#define SPR_SRR0       (0x01A)
-#define SPR_SRR1       (0x01B)
-#define SPR_440_PID    (0x030)
-#define SPR_440_DECAR  (0x036)
-#define SPR_CSRR0      (0x03A)
-#define SPR_CSRR1      (0x03B)
-#define SPR_440_DEAR   (0x03D)
-#define SPR_440_ESR    (0x03E)
-#define SPR_440_IVPR   (0x03F)
-#define SPR_8xx_EIE    (0x050)
-#define SPR_8xx_EID    (0x051)
-#define SPR_8xx_NRE    (0x052)
-#define SPR_58x_CMPA   (0x090)
-#define SPR_58x_CMPB   (0x091)
-#define SPR_58x_CMPC   (0x092)
-#define SPR_58x_CMPD   (0x093)
-#define SPR_58x_ICR    (0x094)
-#define SPR_58x_DER    (0x094)
-#define SPR_58x_COUNTA (0x096)
-#define SPR_58x_COUNTB (0x097)
-#define SPR_58x_CMPE   (0x098)
-#define SPR_58x_CMPF   (0x099)
-#define SPR_58x_CMPG   (0x09A)
-#define SPR_58x_CMPH   (0x09B)
-#define SPR_58x_LCTRL1 (0x09C)
-#define SPR_58x_LCTRL2 (0x09D)
-#define SPR_58x_ICTRL  (0x09E)
-#define SPR_58x_BAR    (0x09F)
-#define SPR_VRSAVE     (0x100)
-#define SPR_USPRG0     (0x100)
-#define SPR_USPRG4     (0x104)
-#define SPR_USPRG5     (0x105)
-#define SPR_USPRG6     (0x106)
-#define SPR_USPRG7     (0x107)
-#define SPR_VTBL       (0x10C)
-#define SPR_VTBU       (0x10D)
-#define SPR_SPRG0      (0x110)
-#define SPR_SPRG1      (0x111)
-#define SPR_SPRG2      (0x112)
-#define SPR_SPRG3      (0x113)
-#define SPR_SPRG4      (0x114)
-#define SPR_SCOMC      (0x114)
-#define SPR_SPRG5      (0x115)
-#define SPR_SCOMD      (0x115)
-#define SPR_SPRG6      (0x116)
-#define SPR_SPRG7      (0x117)
-#define SPR_ASR        (0x118)
-#define SPR_EAR        (0x11A)
-#define SPR_TBL        (0x11C)
-#define SPR_TBU        (0x11D)
-#define SPR_SVR        (0x11E)
-#define SPR_440_PIR    (0x11E)
-#define SPR_PVR        (0x11F)
-#define SPR_HSPRG0     (0x130)
-#define SPR_440_DBSR   (0x130)
-#define SPR_HSPRG1     (0x131)
-#define SPR_440_DBCR0  (0x134)
-#define SPR_IBCR       (0x135)
-#define SPR_440_DBCR1  (0x135)
-#define SPR_DBCR       (0x136)
-#define SPR_HDEC       (0x136)
-#define SPR_440_DBCR2  (0x136)
-#define SPR_HIOR       (0x137)
-#define SPR_MBAR       (0x137)
-#define SPR_RMOR       (0x138)
-#define SPR_440_IAC1   (0x138)
-#define SPR_HRMOR      (0x139)
-#define SPR_440_IAC2   (0x139)
-#define SPR_HSSR0      (0x13A)
-#define SPR_440_IAC3   (0x13A)
-#define SPR_HSSR1      (0x13B)
-#define SPR_440_IAC4   (0x13B)
-#define SPR_LPCR       (0x13C)
-#define SPR_440_DAC1   (0x13C)
-#define SPR_LPIDR      (0x13D)
-#define SPR_DABR2      (0x13D)
-#define SPR_440_DAC2   (0x13D)
-#define SPR_440_DVC1   (0x13E)
-#define SPR_440_DVC2   (0x13F)
-#define SPR_440_TSR    (0x150)
-#define SPR_440_TCR    (0x154)
-#define SPR_440_IVOR0  (0x190)
-#define SPR_440_IVOR1  (0x191)
-#define SPR_440_IVOR2  (0x192)
-#define SPR_440_IVOR3  (0x193)
-#define SPR_440_IVOR4  (0x194)
-#define SPR_440_IVOR5  (0x195)
-#define SPR_440_IVOR6  (0x196)
-#define SPR_440_IVOR7  (0x197)
-#define SPR_440_IVOR8  (0x198)
-#define SPR_440_IVOR9  (0x199)
-#define SPR_440_IVOR10 (0x19A)
-#define SPR_440_IVOR11 (0x19B)
-#define SPR_440_IVOR12 (0x19C)
-#define SPR_440_IVOR13 (0x19D)
-#define SPR_440_IVOR14 (0x19E)
-#define SPR_440_IVOR15 (0x19F)
-#define SPR_IBAT0U     (0x210)
-#define SPR_IBAT0L     (0x211)
-#define SPR_IBAT1U     (0x212)
-#define SPR_IBAT1L     (0x213)
-#define SPR_IBAT2U     (0x214)
-#define SPR_IBAT2L     (0x215)
-#define SPR_IBAT3U     (0x216)
-#define SPR_IBAT3L     (0x217)
-#define SPR_DBAT0U     (0x218)
-#define SPR_DBAT0L     (0x219)
-#define SPR_DBAT1U     (0x21A)
-#define SPR_DBAT1L     (0x21B)
-#define SPR_DBAT2U     (0x21C)
-#define SPR_DBAT2L     (0x21D)
-#define SPR_DBAT3U     (0x21E)
-#define SPR_DBAT3L     (0x21F)
-#define SPR_IBAT4U     (0x230)
-#define SPR_IBAT4L     (0x231)
-#define SPR_IBAT5U     (0x232)
-#define SPR_IBAT5L     (0x233)
-#define SPR_IBAT6U     (0x234)
-#define SPR_IBAT6L     (0x235)
-#define SPR_IBAT7U     (0x236)
-#define SPR_IBAT7L     (0x237)
-#define SPR_DBAT4U     (0x238)
-#define SPR_DBAT4L     (0x239)
-#define SPR_DBAT5U     (0x23A)
-#define SPR_DBAT5L     (0x23B)
-#define SPR_DBAT6U     (0x23C)
-#define SPR_DBAT6L     (0x23D)
-#define SPR_DBAT7U     (0x23E)
-#define SPR_DBAT7L     (0x23F)
-#define SPR_440_INV0   (0x370)
-#define SPR_440_INV1   (0x371)
-#define SPR_440_INV2   (0x372)
-#define SPR_440_INV3   (0x373)
-#define SPR_440_IVT0   (0x374)
-#define SPR_440_IVT1   (0x375)
-#define SPR_440_IVT2   (0x376)
-#define SPR_440_IVT3   (0x377)
-#define SPR_440_DNV0   (0x390)
-#define SPR_440_DNV1   (0x391)
-#define SPR_440_DNV2   (0x392)
-#define SPR_440_DNV3   (0x393)
-#define SPR_440_DVT0   (0x394)
-#define SPR_440_DVT1   (0x395)
-#define SPR_440_DVT2   (0x396)
-#define SPR_440_DVT3   (0x397)
-#define SPR_440_DVLIM  (0x398)
-#define SPR_440_IVLIM  (0x399)
-#define SPR_440_RSTCFG (0x39B)
-#define SPR_440_DCBTRL (0x39C)
-#define SPR_440_DCBTRH (0x39D)
-#define SPR_440_ICBTRL (0x39E)
-#define SPR_440_ICBTRH (0x39F)
-#define SPR_UMMCR0     (0x3A8)
-#define SPR_UPMC1      (0x3A9)
-#define SPR_UPMC2      (0x3AA)
-#define SPR_USIA       (0x3AB)
-#define SPR_UMMCR1     (0x3AC)
-#define SPR_UPMC3      (0x3AD)
-#define SPR_UPMC4      (0x3AE)
-#define SPR_USDA       (0x3AF)
-#define SPR_40x_ZPR    (0x3B0)
-#define SPR_40x_PID    (0x3B1)
-#define SPR_440_MMUCR  (0x3B2)
-#define SPR_4xx_CCR0   (0x3B3)
-#define SPR_405_IAC3   (0x3B4)
-#define SPR_405_IAC4   (0x3B5)
-#define SPR_405_DVC1   (0x3B6)
-#define SPR_405_DVC2   (0x3B7)
-#define SPR_MMCR0      (0x3B8)
-#define SPR_PMC1       (0x3B9)
-#define SPR_40x_SGR    (0x3B9)
-#define SPR_PMC2       (0x3BA)
-#define SPR_40x_DCWR   (0x3BA)
-#define SPR_SIA        (0x3BB)
-#define SPR_405_SLER   (0x3BB)
-#define SPR_MMCR1      (0x3BC)
-#define SPR_405_SU0R   (0x3BC)
-#define SPR_PMC3       (0x3BD)
-#define SPR_405_DBCR1  (0x3BD)
-#define SPR_PMC4       (0x3BE)
-#define SPR_SDA        (0x3BF)
-#define SPR_403_VTBL   (0x3CC)
-#define SPR_403_VTBU   (0x3CD)
-#define SPR_DMISS      (0x3D0)
-#define SPR_DCMP       (0x3D1)
-#define SPR_DHASH1     (0x3D2)
-#define SPR_DHASH2     (0x3D3)
-#define SPR_4xx_ICDBDR (0x3D3)
-#define SPR_IMISS      (0x3D4)
-#define SPR_40x_ESR    (0x3D4)
-#define SPR_ICMP       (0x3D5)
-#define SPR_40x_DEAR   (0x3D5)
-#define SPR_RPA        (0x3D6)
-#define SPR_40x_EVPR   (0x3D6)
-#define SPR_403_CDBCR  (0x3D7)
-#define SPR_TCR        (0x3D8)
-#define SPR_40x_TSR    (0x3D8)
-#define SPR_IBR        (0x3DA)
-#define SPR_40x_TCR    (0x3DA)
-#define SPR_ESASR      (0x3DB)
-#define SPR_40x_PIT    (0x3DB)
-#define SPR_403_TBL    (0x3DC)
-#define SPR_403_TBU    (0x3DD)
-#define SPR_SEBR       (0x3DE)
-#define SPR_40x_SRR2   (0x3DE)
-#define SPR_SER        (0x3DF)
-#define SPR_40x_SRR3   (0x3DF)
-#define SPR_HID0       (0x3F0)
-#define SPR_40x_DBSR   (0x3F0)
-#define SPR_HID1       (0x3F1)
-#define SPR_IABR       (0x3F2)
-#define SPR_40x_DBCR0  (0x3F2)
-#define SPR_601_HID2   (0x3F2)
-#define SPR_HID2       (0x3F3)
-#define SPR_440_DBDR   (0x3F3)
-#define SPR_40x_IAC1   (0x3F4)
-#define SPR_DABR       (0x3F5)
+#define SPR_MQ           (0x000)
+#define SPR_XER          (0x001)
+#define SPR_601_VRTCU    (0x004)
+#define SPR_601_VRTCL    (0x005)
+#define SPR_601_UDECR    (0x006)
+#define SPR_LR           (0x008)
+#define SPR_CTR          (0x009)
+#define SPR_DSISR        (0x012)
+#define SPR_DAR          (0x013)
+#define SPR_601_RTCU     (0x014)
+#define SPR_601_RTCL     (0x015)
+#define SPR_DECR         (0x016)
+#define SPR_SDR1         (0x019)
+#define SPR_SRR0         (0x01A)
+#define SPR_SRR1         (0x01B)
+#define SPR_BOOKE_PID    (0x030)
+#define SPR_BOOKE_DECAR  (0x036)
+#define SPR_CSRR0        (0x03A)
+#define SPR_CSRR1        (0x03B)
+#define SPR_BOOKE_DEAR   (0x03D)
+#define SPR_BOOKE_ESR    (0x03E)
+#define SPR_BOOKE_EVPR   (0x03F)
+#define SPR_8xx_EIE      (0x050)
+#define SPR_8xx_EID      (0x051)
+#define SPR_8xx_NRE      (0x052)
+#define SPR_58x_CMPA     (0x090)
+#define SPR_58x_CMPB     (0x091)
+#define SPR_58x_CMPC     (0x092)
+#define SPR_58x_CMPD     (0x093)
+#define SPR_58x_ICR      (0x094)
+#define SPR_58x_DER      (0x094)
+#define SPR_58x_COUNTA   (0x096)
+#define SPR_58x_COUNTB   (0x097)
+#define SPR_58x_CMPE     (0x098)
+#define SPR_58x_CMPF     (0x099)
+#define SPR_58x_CMPG     (0x09A)
+#define SPR_58x_CMPH     (0x09B)
+#define SPR_58x_LCTRL1   (0x09C)
+#define SPR_58x_LCTRL2   (0x09D)
+#define SPR_58x_ICTRL    (0x09E)
+#define SPR_58x_BAR      (0x09F)
+#define SPR_VRSAVE       (0x100)
+#define SPR_USPRG0       (0x100)
+#define SPR_USPRG4       (0x104)
+#define SPR_USPRG5       (0x105)
+#define SPR_USPRG6       (0x106)
+#define SPR_USPRG7       (0x107)
+#define SPR_VTBL         (0x10C)
+#define SPR_VTBU         (0x10D)
+#define SPR_SPRG0        (0x110)
+#define SPR_SPRG1        (0x111)
+#define SPR_SPRG2        (0x112)
+#define SPR_SPRG3        (0x113)
+#define SPR_SPRG4        (0x114)
+#define SPR_SCOMC        (0x114)
+#define SPR_SPRG5        (0x115)
+#define SPR_SCOMD        (0x115)
+#define SPR_SPRG6        (0x116)
+#define SPR_SPRG7        (0x117)
+#define SPR_ASR          (0x118)
+#define SPR_EAR          (0x11A)
+#define SPR_TBL          (0x11C)
+#define SPR_TBU          (0x11D)
+#define SPR_SVR          (0x11E)
+#define SPR_BOOKE_PIR    (0x11E)
+#define SPR_PVR          (0x11F)
+#define SPR_HSPRG0       (0x130)
+#define SPR_BOOKE_DBSR   (0x130)
+#define SPR_HSPRG1       (0x131)
+#define SPR_BOOKE_DBCR0  (0x134)
+#define SPR_IBCR         (0x135)
+#define SPR_BOOKE_DBCR1  (0x135)
+#define SPR_DBCR         (0x136)
+#define SPR_HDEC         (0x136)
+#define SPR_BOOKE_DBCR2  (0x136)
+#define SPR_HIOR         (0x137)
+#define SPR_MBAR         (0x137)
+#define SPR_RMOR         (0x138)
+#define SPR_BOOKE_IAC1   (0x138)
+#define SPR_HRMOR        (0x139)
+#define SPR_BOOKE_IAC2   (0x139)
+#define SPR_HSSR0        (0x13A)
+#define SPR_BOOKE_IAC3   (0x13A)
+#define SPR_HSSR1        (0x13B)
+#define SPR_BOOKE_IAC4   (0x13B)
+#define SPR_LPCR         (0x13C)
+#define SPR_BOOKE_DAC1   (0x13C)
+#define SPR_LPIDR        (0x13D)
+#define SPR_DABR2        (0x13D)
+#define SPR_BOOKE_DAC2   (0x13D)
+#define SPR_BOOKE_DVC1   (0x13E)
+#define SPR_BOOKE_DVC2   (0x13F)
+#define SPR_BOOKE_TSR    (0x150)
+#define SPR_BOOKE_TCR    (0x154)
+#define SPR_BOOKE_IVOR0  (0x190)
+#define SPR_BOOKE_IVOR1  (0x191)
+#define SPR_BOOKE_IVOR2  (0x192)
+#define SPR_BOOKE_IVOR3  (0x193)
+#define SPR_BOOKE_IVOR4  (0x194)
+#define SPR_BOOKE_IVOR5  (0x195)
+#define SPR_BOOKE_IVOR6  (0x196)
+#define SPR_BOOKE_IVOR7  (0x197)
+#define SPR_BOOKE_IVOR8  (0x198)
+#define SPR_BOOKE_IVOR9  (0x199)
+#define SPR_BOOKE_IVOR10 (0x19A)
+#define SPR_BOOKE_IVOR11 (0x19B)
+#define SPR_BOOKE_IVOR12 (0x19C)
+#define SPR_BOOKE_IVOR13 (0x19D)
+#define SPR_BOOKE_IVOR14 (0x19E)
+#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_E500_SPEFSCR (0x200)
+#define SPR_E500_BBEAR   (0x201)
+#define SPR_E500_BBTAR   (0x202)
+#define SPR_BOOKE_ATBL   (0x20E)
+#define SPR_BOOKE_ATBU   (0x20F)
+#define SPR_IBAT0U       (0x210)
+#define SPR_E500_IVOR32  (0x210)
+#define SPR_IBAT0L       (0x211)
+#define SPR_E500_IVOR33  (0x211)
+#define SPR_IBAT1U       (0x212)
+#define SPR_E500_IVOR34  (0x212)
+#define SPR_IBAT1L       (0x213)
+#define SPR_E500_IVOR35  (0x213)
+#define SPR_IBAT2U       (0x214)
+#define SPR_IBAT2L       (0x215)
+#define SPR_E500_L1CFG0  (0x215)
+#define SPR_IBAT3U       (0x216)
+#define SPR_E500_L1CFG1  (0x216)
+#define SPR_IBAT3L       (0x217)
+#define SPR_DBAT0U       (0x218)
+#define SPR_DBAT0L       (0x219)
+#define SPR_DBAT1U       (0x21A)
+#define SPR_DBAT1L       (0x21B)
+#define SPR_DBAT2U       (0x21C)
+#define SPR_DBAT2L       (0x21D)
+#define SPR_DBAT3U       (0x21E)
+#define SPR_DBAT3L       (0x21F)
+#define SPR_IBAT4U       (0x230)
+#define SPR_IBAT4L       (0x231)
+#define SPR_IBAT5U       (0x232)
+#define SPR_IBAT5L       (0x233)
+#define SPR_IBAT6U       (0x234)
+#define SPR_IBAT6L       (0x235)
+#define SPR_IBAT7U       (0x236)
+#define SPR_IBAT7L       (0x237)
+#define SPR_DBAT4U       (0x238)
+#define SPR_DBAT4L       (0x239)
+#define SPR_DBAT5U       (0x23A)
+#define SPR_E500_MCSRR0  (0x23A)
+#define SPR_DBAT5L       (0x23B)
+#define SPR_E500_MCSRR1  (0x23B)
+#define SPR_DBAT6U       (0x23C)
+#define SPR_E500_MCSR    (0x23C)
+#define SPR_DBAT6L       (0x23D)
+#define SPR_E500_MCAR    (0x23D)
+#define SPR_DBAT7U       (0x23E)
+#define SPR_DBAT7L       (0x23F)
+#define SPR_E500_MAS0    (0x270)
+#define SPR_E500_MAS1    (0x271)
+#define SPR_E500_MAS2    (0x272)
+#define SPR_E500_MAS3    (0x273)
+#define SPR_E500_MAS4    (0x274)
+#define SPR_E500_MAS6    (0x276)
+#define SPR_E500_PID1    (0x279)
+#define SPR_E500_PID2    (0x27A)
+#define SPR_E500_TLB0CFG (0x2B0)
+#define SPR_E500_TLB1CFG (0x2B1)
+#define SPR_440_INV0     (0x370)
+#define SPR_440_INV1     (0x371)
+#define SPR_440_INV2     (0x372)
+#define SPR_440_INV3     (0x373)
+#define SPR_440_IVT0     (0x374)
+#define SPR_440_IVT1     (0x375)
+#define SPR_440_IVT2     (0x376)
+#define SPR_440_IVT3     (0x377)
+#define SPR_440_DNV0     (0x390)
+#define SPR_440_DNV1     (0x391)
+#define SPR_440_DNV2     (0x392)
+#define SPR_440_DNV3     (0x393)
+#define SPR_440_DVT0     (0x394)
+#define SPR_440_DVT1     (0x395)
+#define SPR_440_DVT2     (0x396)
+#define SPR_440_DVT3     (0x397)
+#define SPR_440_DVLIM    (0x398)
+#define SPR_440_IVLIM    (0x399)
+#define SPR_440_RSTCFG   (0x39B)
+#define SPR_440_DCBTRL   (0x39C)
+#define SPR_440_DCBTRH   (0x39D)
+#define SPR_440_ICBTRL   (0x39E)
+#define SPR_440_ICBTRH   (0x39F)
+#define SPR_UMMCR0       (0x3A8)
+#define SPR_UPMC1        (0x3A9)
+#define SPR_UPMC2        (0x3AA)
+#define SPR_USIA         (0x3AB)
+#define SPR_UMMCR1       (0x3AC)
+#define SPR_UPMC3        (0x3AD)
+#define SPR_UPMC4        (0x3AE)
+#define SPR_USDA         (0x3AF)
+#define SPR_40x_ZPR      (0x3B0)
+#define SPR_E500_MAS7    (0x3B0)
+#define SPR_40x_PID      (0x3B1)
+#define SPR_440_MMUCR    (0x3B2)
+#define SPR_4xx_CCR0     (0x3B3)
+#define SPR_405_IAC3     (0x3B4)
+#define SPR_405_IAC4     (0x3B5)
+#define SPR_405_DVC1     (0x3B6)
+#define SPR_405_DVC2     (0x3B7)
+#define SPR_MMCR0        (0x3B8)
+#define SPR_PMC1         (0x3B9)
+#define SPR_40x_SGR      (0x3B9)
+#define SPR_PMC2         (0x3BA)
+#define SPR_40x_DCWR     (0x3BA)
+#define SPR_SIA          (0x3BB)
+#define SPR_405_SLER     (0x3BB)
+#define SPR_MMCR1        (0x3BC)
+#define SPR_405_SU0R     (0x3BC)
+#define SPR_PMC3         (0x3BD)
+#define SPR_405_DBCR1    (0x3BD)
+#define SPR_PMC4         (0x3BE)
+#define SPR_SDA          (0x3BF)
+#define SPR_403_VTBL     (0x3CC)
+#define SPR_403_VTBU     (0x3CD)
+#define SPR_DMISS        (0x3D0)
+#define SPR_DCMP         (0x3D1)
+#define SPR_HASH1        (0x3D2)
+#define SPR_HASH2        (0x3D3)
+#define SPR_4xx_ICDBDR   (0x3D3)
+#define SPR_IMISS        (0x3D4)
+#define SPR_40x_ESR      (0x3D4)
+#define SPR_ICMP         (0x3D5)
+#define SPR_40x_DEAR     (0x3D5)
+#define SPR_RPA          (0x3D6)
+#define SPR_40x_EVPR     (0x3D6)
+#define SPR_403_CDBCR    (0x3D7)
+#define SPR_TCR          (0x3D8)
+#define SPR_40x_TSR      (0x3D8)
+#define SPR_IBR          (0x3DA)
+#define SPR_40x_TCR      (0x3DA)
+#define SPR_ESASR        (0x3DB)
+#define SPR_40x_PIT      (0x3DB)
+#define SPR_403_TBL      (0x3DC)
+#define SPR_403_TBU      (0x3DD)
+#define SPR_SEBR         (0x3DE)
+#define SPR_40x_SRR2     (0x3DE)
+#define SPR_SER          (0x3DF)
+#define SPR_40x_SRR3     (0x3DF)
+#define SPR_HID0         (0x3F0)
+#define SPR_40x_DBSR     (0x3F0)
+#define SPR_HID1         (0x3F1)
+#define SPR_IABR         (0x3F2)
+#define SPR_40x_DBCR0    (0x3F2)
+#define SPR_601_HID2     (0x3F2)
+#define SPR_E500_L1CSR0  (0x3F2)
+#define SPR_HID2         (0x3F3)
+#define SPR_E500_L1CSR1  (0x3F3)
+#define SPR_440_DBDR     (0x3F3)
+#define SPR_40x_IAC1     (0x3F4)
+#define SPR_E500_MMUCSR0 (0x3F4)
+#define SPR_DABR         (0x3F5)
 #define DABR_MASK (~(target_ulong)0x7)
-#define SPR_40x_IAC2   (0x3F5)
-#define SPR_601_HID5   (0x3F5)
-#define SPR_40x_DAC1   (0x3F6)
-#define SPR_40x_DAC2   (0x3F7)
-#define SPR_L2PM       (0x3F8)
-#define SPR_750_HID2   (0x3F8)
-#define SPR_L2CR       (0x3F9)
-#define SPR_IABR2      (0x3FA)
-#define SPR_40x_DCCR   (0x3FA)
-#define SPR_ICTC       (0x3FB)
-#define SPR_40x_ICCR   (0x3FB)
-#define SPR_THRM1      (0x3FC)
-#define SPR_403_PBL1   (0x3FC)
-#define SPR_SP         (0x3FD)
-#define SPR_THRM2      (0x3FD)
-#define SPR_403_PBU1   (0x3FD)
-#define SPR_LT         (0x3FE)
-#define SPR_THRM3      (0x3FE)
-#define SPR_FPECR      (0x3FE)
-#define SPR_403_PBL2   (0x3FE)
-#define SPR_PIR        (0x3FF)
-#define SPR_403_PBU2   (0x3FF)
-#define SPR_601_HID15  (0x3FF)
+#define SPR_E500_BUCSR   (0x3F5)
+#define SPR_40x_IAC2     (0x3F5)
+#define SPR_601_HID5     (0x3F5)
+#define SPR_40x_DAC1     (0x3F6)
+#define SPR_40x_DAC2     (0x3F7)
+#define SPR_E500_MMUCFG  (0x3F7)
+#define SPR_L2PM         (0x3F8)
+#define SPR_750_HID2     (0x3F8)
+#define SPR_L2CR         (0x3F9)
+#define SPR_IABR2        (0x3FA)
+#define SPR_40x_DCCR     (0x3FA)
+#define SPR_ICTC         (0x3FB)
+#define SPR_40x_ICCR     (0x3FB)
+#define SPR_THRM1        (0x3FC)
+#define SPR_403_PBL1     (0x3FC)
+#define SPR_SP           (0x3FD)
+#define SPR_THRM2        (0x3FD)
+#define SPR_403_PBU1     (0x3FD)
+#define SPR_LT           (0x3FE)
+#define SPR_THRM3        (0x3FE)
+#define SPR_FPECR        (0x3FE)
+#define SPR_403_PBL2     (0x3FE)
+#define SPR_PIR          (0x3FF)
+#define SPR_403_PBU2     (0x3FF)
+#define SPR_601_HID15    (0x3FF)
+#define SPR_E500_SVR     (0x3FF)
 
+/*****************************************************************************/
 /* Memory access type :
  * may be needed for precise access rights control and precise exceptions.
  */
@@ -977,7 +1173,7 @@ enum {
 #define EXCP_PPC_MAX       0x4000
 /* Qemu exceptions: special cases we want to stop translation                */
 #define EXCP_MTMSR         0x11000 /* mtmsr instruction:                     */
-                                /* may change privilege level       */
+                                   /* may change privilege level             */
 #define EXCP_BRANCH        0x11001 /* branch instruction                     */
 #define EXCP_SYSCALL_USER  0x12000 /* System call in user mode only          */
 #define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ                      */
index 89171f9..25e060f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation definitions for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include "dyngen-exec.h"
 
-#define TARGET_LONG_BITS 32
+#include "cpu.h"
+#include "exec-all.h"
 
 register struct CPUPPCState *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-register uint32_t T2 asm(AREG3);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+#else
+/* This may be more efficient if HOST_LONG_BITS > TARGET_LONG_BITS
+ * To be set to one when we'll be sure it does not cause bugs....
+ */
+#if 0
+register unsigned long T0 asm(AREG1);
+register unsigned long T1 asm(AREG2);
+register unsigned long T2 asm(AREG3);
+#else
+register target_ulong T0 asm(AREG1);
+register target_ulong T1 asm(AREG2);
+register target_ulong T2 asm(AREG3);
+#endif
+#endif
 
+/* XXX: to clean: remove this mess */
 #define PARAM(n) ((uint32_t)PARAM##n)
 #define SPARAM(n) ((int32_t)PARAM##n)
+
 #define FT0 (env->ft0)
 #define FT1 (env->ft1)
 #define FT2 (env->ft2)
@@ -43,14 +62,28 @@ register uint32_t T2 asm(AREG3);
 # define RETURN() __asm__ __volatile__("" : : : "memory");
 #endif
 
-#include "cpu.h"
-#include "exec-all.h"
+static inline target_ulong rotl8 (target_ulong i, int n)
+{
+    return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n)));
+}
+
+static inline target_ulong rotl16 (target_ulong i, int n)
+{
+    return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n)));
+}
 
-static inline uint32_t rotl (uint32_t i, int n)
+static inline target_ulong rotl32 (target_ulong i, int n)
 {
-    return ((i << n) | (i >> (32 - n)));
+    return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n)));
 }
 
+#if defined(TARGET_PPC64)
+static inline target_ulong rotl64 (target_ulong i, int n)
+{
+    return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n)));
+}
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 #include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -58,23 +91,14 @@ static inline uint32_t rotl (uint32_t i, int n)
 void do_raise_exception_err (uint32_t exception, int error_code);
 void do_raise_exception (uint32_t exception);
 
-void do_sraw(void);
-
-void do_fctiw (void);
-void do_fctiwz (void);
-void do_fnmadd (void);
-void do_fnmsub (void);
-void do_fsqrt (void);
-void do_fres (void);
-void do_frsqrte (void);
-void do_fsel (void);
-void do_fcmpu (void);
-void do_fcmpo (void);
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr,
+                          int rw, int access_type, int check_BATs);
 
-void do_check_reservation (void);
-void do_icbi (void);
-void do_tlbia (void);
-void do_tlbie (void);
+void ppc6xx_tlb_invalidate_all (CPUState *env);
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+                                 int is_code);
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1);
 
 static inline void env_to_regs(void)
 {
@@ -84,7 +108,7 @@ static inline void regs_to_env(void)
 {
 }
 
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu);
 
 #endif /* !defined (__PPC_H__) */
index 70b0a49..f4f692d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation helpers for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
 
 //#define DEBUG_MMU
 //#define DEBUG_BATS
+//#define DEBUG_SOFTWARE_TLB
 //#define DEBUG_EXCEPTIONS
 //#define FLUSH_ALL_TLBS
 
@@ -55,26 +56,307 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
     }
     env->exception_index = exception;
     env->error_code = error_code;
+
     return 1;
 }
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+
+target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
     return addr;
 }
 #else
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid (target_ulong pte0)
+{
+    return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate (target_ulong *pte0)
+{
+    *pte0 &= ~0x80000000;
+}
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+
+static int pte_check (mmu_ctx_t *ctx,
+                      target_ulong pte0, target_ulong pte1, int h, int rw)
+{
+    int access, ret;
+
+    access = 0;
+    ret = -1;
+    /* Check validity and table match */
+    if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) {
+        /* Check vsid & api */
+        if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) {
+            if (ctx->raddr != (target_ulong)-1) {
+                /* all matches should have equal RPN, WIMG & PP */
+                if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) {
+                    if (loglevel > 0)
+                        fprintf(logfile, "Bad RPN/WIMG/PP\n");
+                    return -3;
+                }
+            }
+            /* Compute access rights */
+            if (ctx->key == 0) {
+                access = PAGE_READ;
+                if ((pte1 & 0x00000003) != 0x3)
+                    access |= PAGE_WRITE;
+            } else {
+                switch (pte1 & 0x00000003) {
+                case 0x0:
+                    access = 0;
+                    break;
+                case 0x1:
+                case 0x3:
+                    access = PAGE_READ;
+                    break;
+                case 0x2:
+                    access = PAGE_READ | PAGE_WRITE;
+                    break;
+                }
+            }
+            /* Keep the matching PTE informations */
+            ctx->raddr = pte1;
+            ctx->prot = access;
+            if ((rw == 0 && (access & PAGE_READ)) ||
+                (rw == 1 && (access & PAGE_WRITE))) {
+                /* Access granted */
+#if defined (DEBUG_MMU)
+                if (loglevel > 0)
+                    fprintf(logfile, "PTE access granted !\n");
+#endif
+                ret = 0;
+            } else {
+                /* Access right violation */
+#if defined (DEBUG_MMU)
+                if (loglevel > 0)
+                    fprintf(logfile, "PTE access rejected\n");
+#endif
+                ret = -2;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
+                             int ret, int rw)
+{
+    int store = 0;
+
+    /* Update page flags */
+    if (!(*pte1p & 0x00000100)) {
+        /* Update accessed flag */
+        *pte1p |= 0x00000100;
+        store = 1;
+    }
+    if (!(*pte1p & 0x00000080)) {
+        if (rw == 1 && ret == 0) {
+            /* Update changed flag */
+            *pte1p |= 0x00000080;
+            store = 1;
+        } else {
+            /* Force page fault for first write access */
+            ctx->prot &= ~PAGE_WRITE;
+        }
+    }
+
+    return store;
+}
+
+/* Software driven TLB helpers */
+static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
+                              int way, int is_code)
+{
+    int nr;
+
+    /* Select TLB num in a way from address */
+    nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+    /* Select TLB way */
+    nr += env->tlb_per_way * way;
+    /* 6xx have separate TLBs for instructions and data */
+    if (is_code && env->id_tlbs == 1)
+        nr += env->nb_tlb;
+
+    return nr;
+}
+
+void ppc6xx_tlb_invalidate_all (CPUState *env)
+{
+    ppc_tlb_t *tlb;
+    int nr, max;
+
+#if defined (DEBUG_SOFTWARE_TLB) && 0
+    if (loglevel != 0) {
+        fprintf(logfile, "Invalidate all TLBs\n");
+    }
+#endif
+    /* Invalidate all defined software TLB */
+    max = env->nb_tlb;
+    if (env->id_tlbs == 1)
+        max *= 2;
+    for (nr = 0; nr < max; nr++) {
+        tlb = &env->tlb[nr];
+#if !defined(FLUSH_ALL_TLBS)
+        tlb_flush_page(env, tlb->EPN);
+#endif
+        pte_invalidate(&tlb->pte0);
+    }
+#if defined(FLUSH_ALL_TLBS)
+    tlb_flush(env, 1);
+#endif
+}
+
+static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
+                                                 target_ulong eaddr,
+                                                 int is_code, int match_epn)
+{
+    ppc_tlb_t *tlb;
+    int way, nr;
+
+#if !defined(FLUSH_ALL_TLBS)
+    /* Invalidate ITLB + DTLB, all ways */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+        tlb = &env->tlb[nr];
+        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "TLB invalidate %d/%d %08x\n",
+                        nr, env->nb_tlb, eaddr);
+            }
+#endif
+            pte_invalidate(&tlb->pte0);
+            tlb_flush_page(env, tlb->EPN);
+        }
+    }
+#else
+    /* XXX: PowerPC specification say this is valid as well */
+    ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+                                 int is_code)
+{
+    __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1)
+{
+    ppc_tlb_t *tlb;
+    int nr;
+
+    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+    tlb = &env->tlb[nr];
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "Set TLB %d/%d EPN %08lx PTE0 %08lx PTE1 %08lx\n",
+                nr, env->nb_tlb, (unsigned long)EPN,
+                (unsigned long)pte0, (unsigned long)pte1);
+    }
+#endif
+    /* Invalidate any pending reference in Qemu for this virtual address */
+    __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+    tlb->pte0 = pte0;
+    tlb->pte1 = pte1;
+    tlb->EPN = EPN;
+    tlb->PID = 0;
+    tlb->size = 1;
+    /* Store last way for LRU mechanism */
+    env->last_way = way;
+}
+
+static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
+                             target_ulong eaddr, int rw, int access_type)
+{
+    ppc_tlb_t *tlb;
+    int nr, best, way;
+    int ret;
+    
+    best = -1;
+    ret = -1; /* No TLB found */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way,
+                               access_type == ACCESS_CODE ? 1 : 0);
+        tlb = &env->tlb[nr];
+        /* This test "emulates" the PTE index match for hardware TLBs */
+        if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "TLB %d/%d %s [%08x %08x] <> %08x\n",
+                        nr, env->nb_tlb,
+                        pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                        tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+            }
+#endif
+            continue;
+        }
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "TLB %d/%d %s %08x <> %08x %08x %c %c\n",
+                    nr, env->nb_tlb,
+                    pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                    tlb->EPN, eaddr, tlb->pte1,
+                    rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+        }
+#endif
+        switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
+        case -3:
+            /* TLB inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            best = nr;
+            break;
+        case -1:
+        default:
+            /* No match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all TLBs consistency
+             *      but we can speed-up the whole thing as the
+             *      result would be undefined if TLBs are not consistent.
+             */
+            ret = 0;
+            best = nr;
+            goto done;
+        }
+    }
+    if (best != -1) {
+    done:
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel > 0) {
+            fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
+                    ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+        }
+#endif
+        /* Update page flags */
+        pte_update_flags(ctx, &env->tlb[best].pte1, ret, rw);
+    }
+
+    return ret;
+}
+
 /* Perform BAT hit & translation */
-static int get_bat (CPUState *env, uint32_t *real, int *prot,
-                    uint32_t virtual, int rw, int type)
+static int get_bat (CPUState *env, mmu_ctx_t *ctx,
+                    target_ulong virtual, int rw, int type)
 {
-    uint32_t *BATlt, *BATut, *BATu, *BATl;
-    uint32_t base, BEPIl, BEPIu, bl;
+    target_ulong *BATlt, *BATut, *BATu, *BATl;
+    target_ulong base, BEPIl, BEPIu, bl;
     int i;
     int ret = -1;
 
 #if defined (DEBUG_BATS)
     if (loglevel > 0) {
         fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
-               type == ACCESS_CODE ? 'I' : 'D', virtual);
+                type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
 #endif
     switch (type) {
@@ -90,7 +372,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
 #if defined (DEBUG_BATS)
     if (loglevel > 0) {
         fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
-               type == ACCESS_CODE ? 'I' : 'D', virtual);
+                type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
 #endif
     base = virtual & 0xFFFC0000;
@@ -113,18 +395,18 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
             if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
                 (msr_pr == 1 && (*BATu & 0x00000001))) {
                 /* Get physical address */
-                *real = (*BATl & 0xF0000000) |
+                ctx->raddr = (*BATl & 0xF0000000) |
                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
                     (virtual & 0x0001F000);
                 if (*BATl & 0x00000001)
-                    *prot = PAGE_READ;
+                    ctx->prot = PAGE_READ;
                 if (*BATl & 0x00000002)
-                    *prot = PAGE_WRITE | PAGE_READ;
+                    ctx->prot = PAGE_WRITE | PAGE_READ;
 #if defined (DEBUG_BATS)
                 if (loglevel > 0) {
                     fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
-                            i, *real, *prot & PAGE_READ ? 'R' : '-',
-                            *prot & PAGE_WRITE ? 'W' : '-');
+                            i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+                            ctx->prot & PAGE_WRITE ? 'W' : '-');
                 }
 #endif
                 ret = 0;
@@ -153,189 +435,154 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
 }
 
 /* PTE table lookup */
-static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
-                     int h, int key, int rw)
+static int find_pte (mmu_ctx_t *ctx, int h, int rw)
 {
-    uint32_t pte0, pte1, keep = 0, access = 0;
-    int i, good = -1, store = 0;
-    int ret = -1; /* No entry found */
+    target_ulong base, pte0, pte1;
+    int i, good = -1;
+    int ret;
 
+    ret = -1; /* No entry found */
+    base = ctx->pg_addr[h];
     for (i = 0; i < 8; i++) {
         pte0 = ldl_phys(base + (i * 8));
         pte1 =  ldl_phys(base + (i * 8) + 4);
 #if defined (DEBUG_MMU)
         if (loglevel > 0) {
-           fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
-                   "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
-                   pte0 >> 31, h, (pte0 >> 6) & 1, va);
-       }
-#endif
-        /* Check validity and table match */
-        if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
-            /* Check vsid & api */
-            if ((pte0 & 0x7FFFFFBF) == va) {
-                if (good == -1) {
-                    good = i;
-                    keep = pte1;
-                } else {
-                    /* All matches should have equal RPN, WIMG & PP */
-                    if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
-                       if (loglevel > 0)
-                           fprintf(logfile, "Bad RPN/WIMG/PP\n");
-                        return -1;
-                    }
-                }
-                /* Check access rights */
-                if (key == 0) {
-                    access = PAGE_READ;
-                    if ((pte1 & 0x00000003) != 0x3)
-                        access |= PAGE_WRITE;
-                } else {
-                    switch (pte1 & 0x00000003) {
-                    case 0x0:
-                        access = 0;
-                        break;
-                    case 0x1:
-                    case 0x3:
-                        access = PAGE_READ;
-                        break;
-                    case 0x2:
-                        access = PAGE_READ | PAGE_WRITE;
-                        break;
-                    }
-                }
-                if (ret < 0) {
-                   if ((rw == 0 && (access & PAGE_READ)) ||
-                       (rw == 1 && (access & PAGE_WRITE))) {
-#if defined (DEBUG_MMU)
-                       if (loglevel > 0)
-                           fprintf(logfile, "PTE access granted !\n");
-#endif
-                        good = i;
-                        keep = pte1;
-                        ret = 0;
-                   } else {
-                       /* Access right violation */
-                        ret = -2;
-#if defined (DEBUG_MMU)
-                       if (loglevel > 0)
-                           fprintf(logfile, "PTE access rejected\n");
+            fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
+                    "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
+                    pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem);
+        }
 #endif
-                    }
-                   *prot = access;
-               }
-            }
+        switch (pte_check(ctx, pte0, pte1, h, rw)) {
+        case -3:
+            /* PTE inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            good = i;
+            break;
+        case -1:
+        default:
+            /* No PTE match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all PTEs consistency
+             *      but if we can speed-up the whole thing as the
+             *      result would be undefined if PTEs are not consistent.
+             */
+            ret = 0;
+            good = i;
+            goto done;
         }
     }
     if (good != -1) {
-        *RPN = keep & 0xFFFFF000;
+    done:
 #if defined (DEBUG_MMU)
         if (loglevel > 0) {
-           fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
-               *RPN, *prot, ret);
-       }
+            fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
+                    ctx->raddr, ctx->prot, ret);
+        }
 #endif
         /* Update page flags */
-        if (!(keep & 0x00000100)) {
-           /* Access flag */
-            keep |= 0x00000100;
-            store = 1;
-        }
-        if (!(keep & 0x00000080)) {
-           if (rw && ret == 0) {
-               /* Change flag */
-                keep |= 0x00000080;
-                store = 1;
-           } else {
-               /* Force page fault for first write access */
-               *prot &= ~PAGE_WRITE;
-            }
-        }
-        if (store) {
-           stl_phys_notdirty(base + (good * 8) + 4, keep);
-       }
+        pte1 = ctx->raddr;
+        if (pte_update_flags(ctx, &pte1, ret, rw) == 1)
+            stl_phys_notdirty(base + (good * 8) + 4, pte1);
     }
 
     return ret;
 }
 
-static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
+static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
+                                             target_phys_addr_t hash,
+                                             target_phys_addr_t mask)
 {
     return (sdr1 & 0xFFFF0000) | (hash & mask);
 }
 
 /* Perform segment based translation */
-static int get_segment (CPUState *env, uint32_t *real, int *prot,
-                        uint32_t virtual, int rw, int type)
+static int get_segment (CPUState *env, mmu_ctx_t *ctx,
+                        target_ulong eaddr, int rw, int type)
 {
-    uint32_t pg_addr, sdr, ptem, vsid, pgidx;
-    uint32_t hash, mask;
-    uint32_t sr;
-    int key;
+    target_phys_addr_t sdr, hash, mask;
+    target_ulong sr, vsid, pgidx;
     int ret = -1, ret2;
 
-    sr = env->sr[virtual >> 28];
+    sr = env->sr[eaddr >> 28];
 #if defined (DEBUG_MMU)
     if (loglevel > 0) {
-       fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
-               "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
-               virtual, virtual >> 28, sr, env->nip,
-               env->lr, msr_ir, msr_dr, msr_pr, rw, type);
+        fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
+                "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
+                eaddr, eaddr >> 28, sr, env->nip,
+                env->lr, msr_ir, msr_dr, msr_pr, rw, type);
     }
 #endif
-    key = (((sr & 0x20000000) && msr_pr == 1) ||
-        ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
+    ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
+                ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
     if ((sr & 0x80000000) == 0) {
 #if defined (DEBUG_MMU)
-    if (loglevel > 0) 
-           fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
-                   key, sr & 0x10000000);
+        if (loglevel > 0) 
+            fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
+                    ctx->key, sr & 0x10000000);
 #endif
         /* Check if instruction fetch is allowed, if needed */
         if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
             /* Page address translation */
+            pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF;
             vsid = sr & 0x00FFFFFF;
-            pgidx = (virtual >> 12) & 0xFFFF;
-            sdr = env->sdr1;
             hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
+            /* Primary table address */
+            sdr = env->sdr1;
             mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
-            pg_addr = get_pgaddr(sdr, hash, mask);
-            ptem = (vsid << 7) | (pgidx >> 10);
+            ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask);
+            /* Secondary table address */
+            hash = (~hash) & 0x01FFFFC0;
+            ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask);
+            ctx->ptem = (vsid << 7) | (pgidx >> 10);
+            /* Initialize real address with an invalid value */
+            ctx->raddr = (target_ulong)-1;
+            if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+                /* Software TLB search */
+                ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+            } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+                /* XXX: TODO */
+            } else {
 #if defined (DEBUG_MMU)
-           if (loglevel > 0) {
-               fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
-                       "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash,
-                       pg_addr);
-           }
+                if (loglevel > 0) {
+                    fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
+                            "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx,
+                            hash, ctx->pg_addr[0]);
+                }
 #endif
-            /* Primary table lookup */
-            ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
-            if (ret < 0) {
-                /* Secondary table lookup */
-                hash = (~hash) & 0x01FFFFC0;
-                pg_addr = get_pgaddr(sdr, hash, mask);
+                /* Primary table lookup */
+                ret = find_pte(ctx, 0, rw);
+                if (ret < 0) {
+                    /* Secondary table lookup */
 #if defined (DEBUG_MMU)
-               if (virtual != 0xEFFFFFFF && loglevel > 0) {
-                   fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
-                           "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx,
-                           hash, pg_addr);
-               }
+                    if (eaddr != 0xEFFFFFFF && loglevel > 0) {
+                        fprintf(logfile,
+                                "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
+                                "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid,
+                                pgidx, hash, ctx->pg_addr[1]);
+                    }
 #endif
-                ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
-                if (ret2 != -1)
-                    ret = ret2;
+                    ret2 = find_pte(ctx, 1, rw);
+                    if (ret2 != -1)
+                        ret = ret2;
+                }
             }
         } else {
 #if defined (DEBUG_MMU)
-           if (loglevel > 0)
-               fprintf(logfile, "No access allowed\n");
+            if (loglevel > 0)
+                fprintf(logfile, "No access allowed\n");
 #endif
-           ret = -3;
+            ret = -3;
         }
     } else {
 #if defined (DEBUG_MMU)
         if (loglevel > 0)
-           fprintf(logfile, "direct store...\n");
+            fprintf(logfile, "direct store...\n");
 #endif
         /* Direct-store segment : absolutely *BUGGY* for now */
         switch (type) {
@@ -356,7 +603,7 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
             /* Should make the instruction do no-op.
              * As it already do no-op, it's quite easy :-)
              */
-            *real = virtual;
+            ctx->raddr = eaddr;
             return 0;
         case ACCESS_EXT:
             /* eciwx or ecowx */
@@ -370,8 +617,8 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
                    "address translation\n");
             return -4;
         }
-        if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
-            *real = virtual;
+        if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+            ctx->raddr = eaddr;
             ret = 2;
         } else {
             ret = -2;
@@ -381,8 +628,44 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
     return ret;
 }
 
-static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
-                                 uint32_t address, int rw, int access_type)
+static int check_physical (CPUState *env, mmu_ctx_t *ctx,
+                           target_ulong eaddr, int rw)
+{
+    int in_plb, ret;
+        
+    ctx->raddr = eaddr;
+    ctx->prot = PAGE_READ;
+    ret = 0;
+    if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) {
+        /* 403 family add some particular protections,
+         * using PBL/PBU registers for accesses with no translation.
+         */
+        in_plb =
+            /* Check PLB validity */
+            (env->pb[0] < env->pb[1] &&
+             /* and address in plb area */
+             eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+            (env->pb[2] < env->pb[3] &&
+             eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+        if (in_plb ^ msr_px) {
+            /* Access in protected area */
+            if (rw == 1) {
+                /* Access is not allowed */
+                ret = -2;
+            }
+        } else {
+            /* Read-write access is allowed */
+            ctx->prot |= PAGE_WRITE;
+        }
+    } else {
+        ctx->prot |= PAGE_WRITE;
+    }
+
+    return ret;
+}
+
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+                          int rw, int access_type, int check_BATs)
 {
     int ret;
 #if 0
@@ -393,46 +676,46 @@ static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
     if ((access_type == ACCESS_CODE && msr_ir == 0) ||
         (access_type != ACCESS_CODE && msr_dr == 0)) {
         /* No address translation */
-        *physical = address & ~0xFFF;
-        *prot = PAGE_READ | PAGE_WRITE;
-        ret = 0;
+        ret = check_physical(env, ctx, eaddr, rw);
     } else {
         /* Try to find a BAT */
-        ret = get_bat(env, physical, prot, address, rw, access_type);
+        ret = -1;
+        if (check_BATs)
+            ret = get_bat(env, ctx, eaddr, rw, access_type);
         if (ret < 0) {
             /* We didn't match any BAT entry */
-            ret = get_segment(env, physical, prot, address, rw, access_type);
+            ret = get_segment(env, ctx, eaddr, rw, access_type);
         }
     }
 #if 0
     if (loglevel > 0) {
-        fprintf(logfile, "%s address %08x => %08x\n",
-               __func__, address, *physical);
+        fprintf(logfile, "%s address %08x => %08lx\n",
+                __func__, eaddr, ctx->raddr);
     }
-#endif    
+#endif
+    
     return ret;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
-    uint32_t phys_addr;
-    int prot;
+    mmu_ctx_t ctx;
 
-    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
         return -1;
-    return phys_addr;
+
+    return ctx.raddr & TARGET_PAGE_MASK;
 }
 
 /* Perform address translation */
 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                               int is_user, int is_softmmu)
 {
-    uint32_t physical;
-    int prot;
+    mmu_ctx_t ctx;
     int exception = 0, error_code = 0;
     int access_type;
     int ret = 0;
-
+    
     if (rw == 2) {
         /* code access */
         rw = 0;
@@ -444,35 +727,39 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
         access_type = ACCESS_INT;
         //        access_type = env->access_type;
     }
-    if (env->user_mode_only) {
-        /* user mode only emulation */
-        ret = -2;
-        goto do_fault;
-    }
-    ret = get_physical_address(env, &physical, &prot,
-                               address, rw, access_type);
+    ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
     if (ret == 0) {
-       ret = tlb_set_page(env, address & ~0xFFF, physical, prot,
-                          is_user, is_softmmu);
+        ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
+                           ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+                           is_user, is_softmmu);
     } else if (ret < 0) {
-    do_fault:
 #if defined (DEBUG_MMU)
-       if (loglevel > 0)
-           cpu_dump_state(env, logfile, fprintf, 0);
+        if (loglevel > 0)
+            cpu_dump_state(env, logfile, fprintf, 0);
 #endif
         if (access_type == ACCESS_CODE) {
             exception = EXCP_ISI;
             switch (ret) {
             case -1:
-                /* No matches in page tables */
-                error_code = 0x40000000;
+                /* No matches in page tables or TLB */
+                if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+                    exception = EXCP_I_TLBMISS;
+                    env->spr[SPR_IMISS] = address;
+                    env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+                    error_code = 1 << 18;
+                    goto tlb_miss;
+                } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+                    /* XXX: TODO */
+                } else {
+                    error_code = 0x40000000;
+                }
                 break;
             case -2:
                 /* Access rights violation */
                 error_code = 0x08000000;
                 break;
             case -3:
-               /* No execute protection violation */
+                /* No execute protection violation */
                 error_code = 0x10000000;
                 break;
             case -4:
@@ -490,8 +777,28 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             exception = EXCP_DSI;
             switch (ret) {
             case -1:
-                /* No matches in page tables */
-                error_code = 0x40000000;
+                /* No matches in page tables or TLB */
+                if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+                    if (rw == 1) {
+                        exception = EXCP_DS_TLBMISS;
+                        error_code = 1 << 16;
+                    } else {
+                        exception = EXCP_DL_TLBMISS;
+                        error_code = 0;
+                    }
+                    env->spr[SPR_DMISS] = address;
+                    env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+                tlb_miss:
+                    error_code |= ctx.key << 19;
+                    env->spr[SPR_HASH1] = ctx.pg_addr[0];
+                    env->spr[SPR_HASH2] = ctx.pg_addr[1];
+                    /* Do not alter DAR nor DSISR */
+                    goto out;
+                } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+                    /* XXX: TODO */
+                } else {
+                    error_code = 0x40000000;
+                }
                 break;
             case -2:
                 /* Access rights violation */
@@ -514,7 +821,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
                     error_code = 0x04100000;
                     break;
                 default:
-                   printf("DSI: invalid exception (%d)\n", ret);
+                    printf("DSI: invalid exception (%d)\n", ret);
                     exception = EXCP_PROGRAM;
                     error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
                     break;
@@ -528,10 +835,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             }
             if (exception == EXCP_DSI && rw == 1)
                 error_code |= 0x02000000;
-           /* Store fault address */
-           env->spr[SPR_DAR] = address;
+            /* Store fault address */
+            env->spr[SPR_DAR] = address;
             env->spr[SPR_DSISR] = error_code;
         }
+    out:
 #if 0
         printf("%s: set exception to %d %02x\n",
                __func__, exception, error_code);
@@ -540,9 +848,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
         env->error_code = error_code;
         ret = 1;
     }
+
     return ret;
 }
-#endif
 
 /*****************************************************************************/
 /* BATs management */
@@ -551,11 +859,14 @@ static inline void do_invalidate_BAT (CPUPPCState *env,
                                       target_ulong BATu, target_ulong mask)
 {
     target_ulong base, end, page;
+
     base = BATu & ~0x0001FFFF;
     end = base + mask + 0x00020000;
 #if defined (DEBUG_BATS)
-    if (loglevel != 0)
-        fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask);
+    if (loglevel != 0) {
+        fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n",
+                base, end, mask);
+    }
 #endif
     for (page = base; page != end; page += TARGET_PAGE_SIZE)
         tlb_flush_page(env, page);
@@ -608,8 +919,7 @@ void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
             (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
 #if !defined(FLUSH_ALL_TLBS)
         do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
-#if defined(FLUSH_ALL_TLBS)
+#else
         tlb_flush(env, 1);
 #endif
     }
@@ -663,24 +973,8 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
     env->DBAT[1][nr] = value;
 }
 
-static inline void invalidate_all_tlbs (CPUPPCState *env)
-{
-    /* XXX: this needs to be completed for sotware driven TLB support */
-    tlb_flush(env, 1);
-}
-
 /*****************************************************************************/
 /* Special registers manipulation */
-target_ulong do_load_nip (CPUPPCState *env)
-{
-    return env->nip;
-}
-
-void do_store_nip (CPUPPCState *env, target_ulong value)
-{
-    env->nip = value;
-}
-
 target_ulong do_load_sdr1 (CPUPPCState *env)
 {
     return env->sdr1;
@@ -695,7 +989,7 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value)
 #endif
     if (env->sdr1 != value) {
         env->sdr1 = value;
-        invalidate_all_tlbs(env);
+        tlb_flush(env, 1);
     }
 }
 
@@ -724,34 +1018,13 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
                 tlb_flush_page(env, page);
         }
 #else
-        invalidate_all_tlbs(env);
+        tlb_flush(env, 1);
 #endif
     }
 }
+#endif /* !defined (CONFIG_USER_ONLY) */
 
-uint32_t do_load_cr (CPUPPCState *env)
-{
-    return (env->crf[0] << 28) |
-        (env->crf[1] << 24) |
-        (env->crf[2] << 20) |
-        (env->crf[3] << 16) |
-        (env->crf[4] << 12) |
-        (env->crf[5] << 8) |
-        (env->crf[6] << 4) |
-        (env->crf[7] << 0);
-}
-
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask)
-{
-    int i, sh;
-
-    for (i = 0, sh = 7; i < 8; i++, sh --) {
-        if (mask & (1 << sh))
-            env->crf[i] = (value >> (sh * 4)) & 0xFUL;
-    }
-}
-
-uint32_t do_load_xer (CPUPPCState *env)
+uint32_t ppc_load_xer (CPUPPCState *env)
 {
     return (xer_so << XER_SO) |
         (xer_ov << XER_OV) |
@@ -760,7 +1033,7 @@ uint32_t do_load_xer (CPUPPCState *env)
         (xer_cmp << XER_CMP);
 }
 
-void do_store_xer (CPUPPCState *env, uint32_t value)
+void ppc_store_xer (CPUPPCState *env, uint32_t value)
 {
     xer_so = (value >> XER_SO) & 0x01;
     xer_ov = (value >> XER_OV) & 0x01;
@@ -769,40 +1042,58 @@ void do_store_xer (CPUPPCState *env, uint32_t value)
     xer_bc = (value >> XER_BC) & 0x3F;
 }
 
-target_ulong do_load_msr (CPUPPCState *env)
+/* Swap temporary saved registers with GPRs */
+static inline void swap_gpr_tgpr (CPUPPCState *env)
 {
-    return (msr_vr << MSR_VR)  |
-        (msr_ap  << MSR_AP)  |
-        (msr_sa  << MSR_SA)  |
-        (msr_key << MSR_KEY) |
-        (msr_pow << MSR_POW) |
-        (msr_tlb << MSR_TLB) |
-        (msr_ile << MSR_ILE) |
-        (msr_ee << MSR_EE) |
-        (msr_pr << MSR_PR) |
-        (msr_fp << MSR_FP) |
-        (msr_me << MSR_ME) |
-        (msr_fe0 << MSR_FE0) |
-        (msr_se << MSR_SE) |
-        (msr_be << MSR_BE) |
-        (msr_fe1 << MSR_FE1) |
-        (msr_al  << MSR_AL)  |
-        (msr_ip << MSR_IP) |
-        (msr_ir << MSR_IR) |
-        (msr_dr << MSR_DR) |
-        (msr_pe  << MSR_PE)  |
-        (msr_px  << MSR_PX)  |
-        (msr_ri << MSR_RI) |
-        (msr_le << MSR_LE);
+    ppc_gpr_t tmp;
+
+    tmp = env->gpr[0];
+    env->gpr[0] = env->tgpr[0];
+    env->tgpr[0] = tmp;
+    tmp = env->gpr[1];
+    env->gpr[1] = env->tgpr[1];
+    env->tgpr[1] = tmp;
+    tmp = env->gpr[2];
+    env->gpr[2] = env->tgpr[2];
+    env->tgpr[2] = tmp;
+    tmp = env->gpr[3];
+    env->gpr[3] = env->tgpr[3];
+    env->tgpr[3] = tmp;
 }
 
-void do_compute_hflags (CPUPPCState *env)
+/* GDBstub can read and write MSR... */
+target_ulong do_load_msr (CPUPPCState *env)
 {
-    /* Compute current hflags */
-    env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
-        (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
-        (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | 
-        (msr_se << MSR_SE) | (msr_be << MSR_BE);
+    return
+#if defined (TARGET_PPC64)
+        (msr_sf   << MSR_SF)   |
+        (msr_isf  << MSR_ISF)  |
+        (msr_hv   << MSR_HV)   |
+#endif
+        (msr_ucle << MSR_UCLE) |
+        (msr_vr   << MSR_VR)   | /* VR / SPE */
+        (msr_ap   << MSR_AP)   |
+        (msr_sa   << MSR_SA)   |
+        (msr_key  << MSR_KEY)  |
+        (msr_pow  << MSR_POW)  | /* POW / WE */
+        (msr_tlb  << MSR_TLB)  | /* TLB / TGPE / CE */
+        (msr_ile  << MSR_ILE)  |
+        (msr_ee   << MSR_EE)   |
+        (msr_pr   << MSR_PR)   |
+        (msr_fp   << MSR_FP)   |
+        (msr_me   << MSR_ME)   |
+        (msr_fe0  << MSR_FE0)  |
+        (msr_se   << MSR_SE)   | /* SE / DWE / UBLE */
+        (msr_be   << MSR_BE)   | /* BE / DE */
+        (msr_fe1  << MSR_FE1)  |
+        (msr_al   << MSR_AL)   |
+        (msr_ip   << MSR_IP)   |
+        (msr_ir   << MSR_IR)   | /* IR / IS */
+        (msr_dr   << MSR_DR)   | /* DR / DS */
+        (msr_pe   << MSR_PE)   | /* PE / EP */
+        (msr_px   << MSR_PX)   | /* PX / PMM */
+        (msr_ri   << MSR_RI)   |
+        (msr_le   << MSR_LE);
 }
 
 void do_store_msr (CPUPPCState *env, target_ulong value)
@@ -812,10 +1103,7 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
     value &= env->msr_mask;
     if (((value >> MSR_IR) & 1) != msr_ir ||
         ((value >> MSR_DR) & 1) != msr_dr) {
-        /* Flush all tlb when changing translation mode
-         * When using software driven TLB, we may also need to reload
-         * all defined TLBs
-         */
+        /* Flush all tlb when changing translation mode */
         tlb_flush(env, 1);
         env->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
@@ -824,35 +1112,52 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
         fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
     }
 #endif
-    msr_vr  = (value >> MSR_VR)  & 1;
-    msr_ap  = (value >> MSR_AP)  & 1;
-    msr_sa  = (value >> MSR_SA)  & 1;
-    msr_key = (value >> MSR_KEY) & 1;
-    msr_pow = (value >> MSR_POW) & 1;
-    msr_tlb = (value >> MSR_TLB)  & 1;
-    msr_ile = (value >> MSR_ILE) & 1;
-    msr_ee  = (value >> MSR_EE)  & 1;
-    msr_pr  = (value >> MSR_PR)  & 1;
-    msr_fp  = (value >> MSR_FP)  & 1;
-    msr_me  = (value >> MSR_ME)  & 1;
-    msr_fe0 = (value >> MSR_FE0) & 1;
-    msr_se  = (value >> MSR_SE)  & 1;
-    msr_be  = (value >> MSR_BE)  & 1;
-    msr_fe1 = (value >> MSR_FE1) & 1;
-    msr_al  = (value >> MSR_AL)  & 1;
-    msr_ip  = (value >> MSR_IP)  & 1;
-    msr_ir  = (value >> MSR_IR)  & 1;
-    msr_dr  = (value >> MSR_DR)  & 1;
-    msr_pe  = (value >> MSR_PE)  & 1;
-    msr_px  = (value >> MSR_PX)  & 1;
-    msr_ri  = (value >> MSR_RI)  & 1;
-    msr_le  = (value >> MSR_LE)  & 1;
+    switch (PPC_EXCP(env)) {
+    case PPC_FLAGS_EXCP_602:
+    case PPC_FLAGS_EXCP_603:
+        if (((value >> MSR_TGPR) & 1) != msr_tgpr) {
+            /* Swap temporary saved registers with GPRs */
+            swap_gpr_tgpr(env);
+        }
+        break;
+    default:
+        break;
+    }
+#if defined (TARGET_PPC64)
+    msr_sf   = (value >> MSR_SF)   & 1;
+    msr_isf  = (value >> MSR_ISF)  & 1;
+    msr_hv   = (value >> MSR_HV)   & 1;
+#endif
+    msr_ucle = (value >> MSR_UCLE) & 1;
+    msr_vr   = (value >> MSR_VR)   & 1; /* VR / SPE */
+    msr_ap   = (value >> MSR_AP)   & 1;
+    msr_sa   = (value >> MSR_SA)   & 1;
+    msr_key  = (value >> MSR_KEY)  & 1;
+    msr_pow  = (value >> MSR_POW)  & 1; /* POW / WE */
+    msr_tlb  = (value >> MSR_TLB)  & 1; /* TLB / TGPR / CE */
+    msr_ile  = (value >> MSR_ILE)  & 1;
+    msr_ee   = (value >> MSR_EE)   & 1;
+    msr_pr   = (value >> MSR_PR)   & 1;
+    msr_fp   = (value >> MSR_FP)   & 1;
+    msr_me   = (value >> MSR_ME)   & 1;
+    msr_fe0  = (value >> MSR_FE0)  & 1;
+    msr_se   = (value >> MSR_SE)   & 1; /* SE / DWE / UBLE */
+    msr_be   = (value >> MSR_BE)   & 1; /* BE / DE */
+    msr_fe1  = (value >> MSR_FE1)  & 1;
+    msr_al   = (value >> MSR_AL)   & 1;
+    msr_ip   = (value >> MSR_IP)   & 1;
+    msr_ir   = (value >> MSR_IR)   & 1; /* IR / IS */
+    msr_dr   = (value >> MSR_DR)   & 1; /* DR / DS */
+    msr_pe   = (value >> MSR_PE)   & 1; /* PE / EP */
+    msr_px   = (value >> MSR_PX)   & 1; /* PX / PMM */
+    msr_ri   = (value >> MSR_RI)   & 1;
+    msr_le   = (value >> MSR_LE)   & 1;
     do_compute_hflags(env);
 
     enter_pm = 0;
     switch (PPC_EXCP(env)) {
     case PPC_FLAGS_EXCP_7x0:
-       if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
+        if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
             enter_pm = 1;
         break;
     default:
@@ -866,75 +1171,16 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
     }
 }
 
-float64 do_load_fpscr (CPUPPCState *env)
+void do_compute_hflags (CPUPPCState *env)
 {
-    /* The 32 MSB of the target fpr are undefined.
-     * They'll be zero...
-     */
-    union {
-        float64 d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-    int i;
-
-#ifdef WORDS_BIGENDIAN
-#define WORD0 0
-#define WORD1 1
-#else
-#define WORD0 1
-#define WORD1 0
+    /* Compute current hflags */
+    env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
+        (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
+        (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | 
+        (msr_se << MSR_SE) | (msr_be << MSR_BE);
+#if defined (TARGET_PPC64)
+    env->hflags |= (msr_sf << MSR_SF) | (msr_hv << MSR_HV);
 #endif
-    u.s.u[WORD0] = 0;
-    u.s.u[WORD1] = 0;
-    for (i = 0; i < 8; i++)
-        u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
-    return u.d;
-}
-
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask)
-{
-    /*
-     * We use only the 32 LSB of the incoming fpr
-     */
-    union {
-        double d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-    int i, rnd_type;
-
-    u.d = f;
-    if (mask & 0x80)
-        env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
-    for (i = 1; i < 7; i++) {
-        if (mask & (1 << (7 - i)))
-            env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
-    }
-    /* TODO: update FEX & VX */
-    /* Set rounding mode */
-    switch (env->fpscr[0] & 0x3) {
-    case 0:
-        /* Best approximation (round to nearest) */
-        rnd_type = float_round_nearest_even;
-        break;
-    case 1:
-        /* Smaller magnitude (round toward zero) */
-        rnd_type = float_round_to_zero;
-        break;
-    case 2:
-        /* Round toward +infinite */
-        rnd_type = float_round_up;
-        break;
-    default:
-    case 3:
-        /* Round toward -infinite */
-        rnd_type = float_round_down;
-        break;
-    }
-    set_float_rounding_mode(rnd_type, &env->fp_status);
 }
 
 /*****************************************************************************/
@@ -944,17 +1190,18 @@ void do_interrupt (CPUState *env)
 {
     env->exception_index = -1;
 }
-#else
+#else /* defined (CONFIG_USER_ONLY) */
 static void dump_syscall(CPUState *env)
 {
-    fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n",
+    fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x "
+            "r5=0x%08x r6=0x%08x nip=0x%08x\n",
             env->gpr[0], env->gpr[3], env->gpr[4],
             env->gpr[5], env->gpr[6], env->nip);
 }
 
 void do_interrupt (CPUState *env)
 {
-    target_ulong msr, *srr_0, *srr_1, tmp;
+    target_ulong msr, *srr_0, *srr_1;
     int excp;
 
     excp = env->exception_index;
@@ -967,7 +1214,7 @@ void do_interrupt (CPUState *env)
         if (loglevel != 0) {
             fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
                     (unsigned long)env->nip, excp, env->error_code);
-           cpu_dump_state(env, logfile, fprintf, 0);
+            cpu_dump_state(env, logfile, fprintf, 0);
         }
     }
 #endif
@@ -978,7 +1225,7 @@ void do_interrupt (CPUState *env)
     msr_pow = 0;
     /* Generate informations in save/restore registers */
     switch (excp) {
-        /* Generic PowerPC exceptions */
+    /* Generic PowerPC exceptions */
     case EXCP_RESET: /* 0x0100 */
         if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
             if (msr_ip)
@@ -993,7 +1240,7 @@ void do_interrupt (CPUState *env)
         if (msr_me == 0) {
             cpu_abort(env, "Machine check exception while not allowed\n");
         }
-        if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
+        if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) {
             srr_0 = &env->spr[SPR_40x_SRR2];
             srr_1 = &env->spr[SPR_40x_SRR3];
         }
@@ -1004,26 +1251,26 @@ void do_interrupt (CPUState *env)
         /* data location address has been stored
          * when the fault has been detected
          */
-       msr &= ~0xFFFF0000;
+        msr &= ~0xFFFF0000;
 #if defined (DEBUG_EXCEPTIONS)
-       if (loglevel) {
-           fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
-                   env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-       } else {
-           printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
-                  env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-       }
+        if (loglevel) {
+            fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
+                    env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+        } else {
+            printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
+                   env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+        }
 #endif
         goto store_next;
     case EXCP_ISI: /* 0x0400 */
         /* Store exception cause */
-       msr &= ~0xFFFF0000;
+        msr &= ~0xFFFF0000;
         msr |= env->error_code;
 #if defined (DEBUG_EXCEPTIONS)
-       if (loglevel != 0) {
-           fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
-                   msr, env->nip);
-       }
+        if (loglevel != 0) {
+            fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
+                    msr, env->nip);
+        }
 #endif
         goto store_next;
     case EXCP_EXTERNAL: /* 0x0500 */
@@ -1039,7 +1286,7 @@ void do_interrupt (CPUState *env)
         }
         goto store_next;
     case EXCP_ALIGN: /* 0x0600 */
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
+        if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) {
             /* Store exception cause */
             /* Get rS/rD and rA from faulting opcode */
             env->spr[SPR_DSISR] |=
@@ -1063,7 +1310,7 @@ void do_interrupt (CPUState *env)
                 printf("Ignore floating point exception\n");
 #endif
                 return;
-        }
+            }
             msr |= 0x00100000;
             /* Set FX */
             env->fpscr[7] |= 0x8;
@@ -1071,21 +1318,21 @@ void do_interrupt (CPUState *env)
             if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
                 ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
                 env->fpscr[7] |= 0x4;
-        break;
+            break;
         case EXCP_INVAL:
-            //     printf("Invalid instruction at 0x%08x\n", env->nip);
+            //      printf("Invalid instruction at 0x%08x\n", env->nip);
             msr |= 0x00080000;
-        break;
+            break;
         case EXCP_PRIV:
             msr |= 0x00040000;
-        break;
+            break;
         case EXCP_TRAP:
             msr |= 0x00020000;
             break;
         default:
             /* Should never occur */
-        break;
-    }
+            break;
+        }
         msr |= 0x00010000;
         goto store_current;
     case EXCP_NO_FP: /* 0x0800 */
@@ -1125,7 +1372,7 @@ void do_interrupt (CPUState *env)
         cpu_abort(env, "Floating point assist exception "
                   "is not implemented yet !\n");
         goto store_next;
-    /* 64 bits PowerPC exceptions */
+        /* 64 bits PowerPC exceptions */
     case EXCP_DSEG: /* 0x0380 */
         /* XXX: TODO */
         cpu_abort(env, "Data segment exception is not implemented yet !\n");
@@ -1141,14 +1388,16 @@ void do_interrupt (CPUState *env)
             /* Requeue it */
             env->interrupt_request |= CPU_INTERRUPT_TIMER;
 #endif
-        return;
+            return;
         }
-        cpu_abort(env,
-                  "Hypervisor decrementer exception is not implemented yet !\n");
+        /* XXX: TODO */
+        cpu_abort(env, "Hypervisor decrementer exception is not implemented "
+                  "yet !\n");
         goto store_next;
     /* Implementation specific exceptions */
     case 0x0A00:
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
+        if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 ||
+                   env->spr[SPR_PVR] == CPU_PPC_G2LE)) {
             /* Critical interrupt on G2 */
             /* XXX: TODO */
             cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
@@ -1186,9 +1435,10 @@ void do_interrupt (CPUState *env)
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
             /* ITLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
-            msr_tgpr = 1;
             goto store_gprs;
+        case PPC_FLAGS_EXCP_7x5:
+            /* ITLBMISS on 745/755 */
+            goto tlb_miss;
         default:
             cpu_abort(env, "Invalid exception 0x1000 !\n");
             break;
@@ -1198,8 +1448,8 @@ void do_interrupt (CPUState *env)
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_40x:
             /* FIT on 4xx */
-            cpu_abort(env, "40x FIT exception is not implemented yet !\n");
             /* XXX: TODO */
+            cpu_abort(env, "40x FIT exception is not implemented yet !\n");
             goto store_next;
         default:
             cpu_abort(env, "Invalid exception 0x1010 !\n");
@@ -1230,9 +1480,10 @@ void do_interrupt (CPUState *env)
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
             /* DLTLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
-            msr_tgpr = 1;
             goto store_gprs;
+        case PPC_FLAGS_EXCP_7x5:
+            /* DLTLBMISS on 745/755 */
+            goto tlb_miss;
         default:
             cpu_abort(env, "Invalid exception 0x1100 !\n");
             break;
@@ -1249,37 +1500,44 @@ void do_interrupt (CPUState *env)
         case PPC_FLAGS_EXCP_602:
         case PPC_FLAGS_EXCP_603:
             /* DSTLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
-            msr_tgpr = 1;
         store_gprs:
+            /* Swap temporary saved registers with GPRs */
+            swap_gpr_tgpr(env);
+            msr_tgpr = 1;
 #if defined (DEBUG_SOFTWARE_TLB)
             if (loglevel != 0) {
-                fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
-                        "DC %08x H1 %08x H2 %08x %08x\n",
-                        excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
-                        env->spr[SPR_IMISS], env->spr[SPR_DMISS],
-                        env->spr[SPR_ICMP], env->spr[SPR_DCMP],
-                        env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
+                const unsigned char *es;
+                target_ulong *miss, *cmp;
+                int en;
+                if (excp == 0x1000) {
+                    es = "I";
+                    en = 'I';
+                    miss = &env->spr[SPR_IMISS];
+                    cmp = &env->spr[SPR_ICMP];
+                } else {
+                    if (excp == 0x1100)
+                        es = "DL";
+                    else
+                        es = "DS";
+                    en = 'D';
+                    miss = &env->spr[SPR_DMISS];
+                    cmp = &env->spr[SPR_DCMP];
+                }
+                fprintf(logfile, "6xx %sTLB miss: %cM %08x %cC %08x "
+                        "H1 %08x H2 %08x %08x\n", es, en, *miss, en, *cmp,
+                        env->spr[SPR_HASH1], env->spr[SPR_HASH2],
                         env->error_code);
             }
 #endif
-            /* Swap temporary saved registers with GPRs */
-            tmp = env->gpr[0];
-            env->gpr[0] = env->tgpr[0];
-            env->tgpr[0] = tmp;
-            tmp = env->gpr[1];
-            env->gpr[1] = env->tgpr[1];
-            env->tgpr[1] = tmp;
-            tmp = env->gpr[2];
-            env->gpr[2] = env->tgpr[2];
-            env->tgpr[2] = tmp;
-            tmp = env->gpr[3];
-            env->gpr[3] = env->tgpr[3];
-            env->tgpr[3] = tmp;
+            goto tlb_miss;
+        case PPC_FLAGS_EXCP_7x5:
+            /* DSTLBMISS on 745/755 */
+        tlb_miss:
+            msr &= ~0xF83F0000;
             msr |= env->crf[0] << 28;
             msr |= env->error_code; /* key, D/I, S/L bits */
             /* Set way using a LRU mechanism */
-            msr |= (env->last_way ^ 1) << 17;
+            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
             goto store_next;
         default:
             cpu_abort(env, "Invalid exception 0x1200 !\n");
@@ -1324,6 +1582,7 @@ void do_interrupt (CPUState *env)
         switch (PPC_EXCP(env)) {
         case PPC_FLAGS_EXCP_602:
             /* Watchdog on 602 */
+            /* XXX: TODO */
             cpu_abort(env,
                       "602 watchdog exception is not implemented yet !\n");
             goto store_next;
diff --git a/target-ppc/mfrom_table.c b/target-ppc/mfrom_table.c
new file mode 100644 (file)
index 0000000..4c27173
--- /dev/null
@@ -0,0 +1,79 @@
+static const uint8_t mfrom_ROM_table[602] =
+{
+     77,  77,  76,  76,  75,  75,  74,  74, 
+     73,  73,  72,  72,  71,  71,  70,  70, 
+     69,  69,  68,  68,  68,  67,  67,  66, 
+     66,  65,  65,  64,  64,  64,  63,  63, 
+     62,  62,  61,  61,  61,  60,  60,  59, 
+     59,  58,  58,  58,  57,  57,  56,  56, 
+     56,  55,  55,  54,  54,  54,  53,  53, 
+     53,  52,  52,  51,  51,  51,  50,  50, 
+     50,  49,  49,  49,  48,  48,  47,  47, 
+     47,  46,  46,  46,  45,  45,  45,  44, 
+     44,  44,  43,  43,  43,  42,  42,  42, 
+     42,  41,  41,  41,  40,  40,  40,  39, 
+     39,  39,  39,  38,  38,  38,  37,  37, 
+     37,  37,  36,  36,  36,  35,  35,  35, 
+     35,  34,  34,  34,  34,  33,  33,  33, 
+     33,  32,  32,  32,  32,  31,  31,  31, 
+     31,  30,  30,  30,  30,  29,  29,  29, 
+     29,  28,  28,  28,  28,  28,  27,  27, 
+     27,  27,  26,  26,  26,  26,  26,  25, 
+     25,  25,  25,  25,  24,  24,  24,  24, 
+     24,  23,  23,  23,  23,  23,  23,  22, 
+     22,  22,  22,  22,  21,  21,  21,  21, 
+     21,  21,  20,  20,  20,  20,  20,  20, 
+     19,  19,  19,  19,  19,  19,  19,  18, 
+     18,  18,  18,  18,  18,  17,  17,  17, 
+     17,  17,  17,  17,  16,  16,  16,  16, 
+     16,  16,  16,  16,  15,  15,  15,  15, 
+     15,  15,  15,  15,  14,  14,  14,  14, 
+     14,  14,  14,  14,  13,  13,  13,  13, 
+     13,  13,  13,  13,  13,  12,  12,  12, 
+     12,  12,  12,  12,  12,  12,  12,  11, 
+     11,  11,  11,  11,  11,  11,  11,  11, 
+     11,  11,  10,  10,  10,  10,  10,  10, 
+     10,  10,  10,  10,  10,   9,   9,   9, 
+      9,   9,   9,   9,   9,   9,   9,   9, 
+      9,   9,   8,   8,   8,   8,   8,   8, 
+      8,   8,   8,   8,   8,   8,   8,   8, 
+      7,   7,   7,   7,   7,   7,   7,   7, 
+      7,   7,   7,   7,   7,   7,   7,   7, 
+      7,   6,   6,   6,   6,   6,   6,   6, 
+      6,   6,   6,   6,   6,   6,   6,   6, 
+      6,   6,   6,   6,   5,   5,   5,   5, 
+      5,   5,   5,   5,   5,   5,   5,   5, 
+      5,   5,   5,   5,   5,   5,   5,   5, 
+      5,   5,   5,   4,   4,   4,   4,   4, 
+      4,   4,   4,   4,   4,   4,   4,   4, 
+      4,   4,   4,   4,   4,   4,   4,   4, 
+      4,   4,   4,   4,   4,   4,   4,   3, 
+      3,   3,   3,   3,   3,   3,   3,   3, 
+      3,   3,   3,   3,   3,   3,   3,   3, 
+      3,   3,   3,   3,   3,   3,   3,   3, 
+      3,   3,   3,   3,   3,   3,   3,   3, 
+      3,   3,   3,   3,   3,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   2,   2, 
+      2,   2,   2,   2,   2,   2,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   1,   1,   1,   1,   1,   1,   1, 
+      1,   0, 
+};
diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c
new file mode 100644 (file)
index 0000000..ab4b1cc
--- /dev/null
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+
+int main (void)
+{
+    double d;
+    uint8_t n;
+    int i;
+    
+    printf("static const uint8_t mfrom_ROM_table[602] =\n{\n    ");
+    for (i = 0; i < 602; i++) {
+        /* Extremly decomposed:
+         *                    -T0 / 256
+         * T0 = 256 * log10(10          + 1.0) + 0.5
+         */
+        d = -i;
+        d /= 256.0;
+        d = exp10(d);
+        d += 1.0;
+        d = log10(d);
+        d *= 256;
+        d += 0.5;
+        n = d;
+        printf("%3d, ", n);
+        if ((i & 7) == 7)
+            printf("\n    ");
+    }
+    printf("\n};\n");
+
+    return 0;
+}
index ca1dbc5..1bad768 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation micro-operations for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,7 +22,9 @@
 
 #include "config.h"
 #include "exec.h"
+#include "op_helper.h"
 
+/* XXX: this is to be suppressed */
 #define regs (env)
 #define Ts0 (int32_t)T0
 #define Ts1 (int32_t)T1
@@ -32,7 +34,8 @@
 #define FT1 (env->ft1)
 #define FT2 (env->ft2)
 
-#define PPC_OP(name) void glue(op_, name)(void)
+/* XXX: this is to be suppressed... */
+#define PPC_OP(name) void OPPROTO glue(op_, name)(void)
 
 #define REG 0
 #include "op_template.h"
 /* set_Rc0 */
 PPC_OP(set_Rc0)
 {
-    uint32_t tmp;
-
-    if (Ts0 < 0) {
-        tmp = 0x08;
-    } else if (Ts0 > 0) {
-        tmp = 0x04;
-    } else {
-        tmp = 0x02;
-    }
-    tmp |= xer_ov;
-    env->crf[0] = tmp;
-    RETURN();
-}
-
-/* reset_Rc0 */
-PPC_OP(reset_Rc0)
-{
-    env->crf[0] = 0x02 | xer_ov;
-    RETURN();
-}
-
-/* set_Rc0_1 */
-PPC_OP(set_Rc0_1)
-{
-    env->crf[0] = 0x04 | xer_ov;
+    env->crf[0] = T0 | xer_ov;
     RETURN();
 }
 
@@ -170,6 +149,12 @@ PPC_OP(set_Rc1)
 }
 
 /* Constants load */
+void OPPROTO op_reset_T0 (void)
+{
+    T0 = 0;
+    RETURN();
+}
+
 PPC_OP(set_T0)
 {
     T0 = PARAM(1);
@@ -182,26 +167,30 @@ PPC_OP(set_T1)
     RETURN();
 }
 
+#if 0 // unused
 PPC_OP(set_T2)
 {
     T2 = PARAM(1);
     RETURN();
 }
+#endif
 
-/* Generate exceptions */
-PPC_OP(raise_exception_err)
+void OPPROTO op_move_T1_T0 (void)
 {
-    do_raise_exception_err(PARAM(1), PARAM(2));
+    T1 = T0;
+    RETURN();
 }
 
-PPC_OP(raise_exception)
+/* Generate exceptions */
+PPC_OP(raise_exception_err)
 {
-    do_raise_exception(PARAM(1));
+    do_raise_exception_err(PARAM(1), PARAM(2));
 }
 
 PPC_OP(update_nip)
 {
     env->nip = PARAM(1);
+    RETURN();
 }
 
 PPC_OP(debug)
@@ -209,46 +198,34 @@ PPC_OP(debug)
     do_raise_exception(EXCP_DEBUG);
 }
 
-/* Segment registers load and store with immediate index */
-PPC_OP(load_srin)
-{
-    T0 = regs->sr[T1 >> 28];
-    RETURN();
-}
 
-PPC_OP(store_srin)
+PPC_OP(exit_tb)
 {
-    do_store_sr(env, ((uint32_t)T1 >> 28), T0);
-    RETURN();
+    EXIT_TB();
 }
 
-PPC_OP(load_sdr1)
+/* Load/store special registers */
+PPC_OP(load_cr)
 {
-    T0 = regs->sdr1;
+    do_load_cr();
     RETURN();
 }
 
-PPC_OP(store_sdr1)
+PPC_OP(store_cr)
 {
-    do_store_sdr1(env, T0);
+    do_store_cr(PARAM(1));
     RETURN();
 }
 
-PPC_OP(exit_tb)
+void OPPROTO op_load_cro (void)
 {
-    EXIT_TB();
-}
-
-/* Load/store special registers */
-PPC_OP(load_cr)
-{
-    T0 = do_load_cr(env);
+    T0 = env->crf[PARAM1];
     RETURN();
 }
 
-PPC_OP(store_cr)
+void OPPROTO op_store_cro (void)
 {
-    do_store_cr(env, T0, PARAM(1));
+    env->crf[PARAM1] = T0;
     RETURN();
 }
 
@@ -272,15 +249,47 @@ PPC_OP(load_xer_bc)
     RETURN();
 }
 
+void OPPROTO op_store_xer_bc (void)
+{
+    xer_bc = T0;
+    RETURN();
+}
+
 PPC_OP(load_xer)
 {
-    T0 = do_load_xer(env);
+    do_load_xer();
     RETURN();
 }
 
 PPC_OP(store_xer)
 {
-    do_store_xer(env, T0);
+    do_store_xer();
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Segment registers load and store */
+PPC_OP(load_sr)
+{
+    T0 = regs->sr[T1];
+    RETURN();
+}
+
+PPC_OP(store_sr)
+{
+    do_store_sr(env, T1, T0);
+    RETURN();
+}
+
+PPC_OP(load_sdr1)
+{
+    T0 = regs->sdr1;
+    RETURN();
+}
+
+PPC_OP(store_sdr1)
+{
+    do_store_sdr1(env, T0);
     RETURN();
 }
 
@@ -295,6 +304,7 @@ PPC_OP(store_msr)
     do_store_msr(env, T0);
     RETURN();
 }
+#endif
 
 /* SPR */
 PPC_OP(load_spr)
@@ -345,6 +355,7 @@ PPC_OP(load_tbu)
     RETURN();
 }
 
+#if !defined(CONFIG_USER_ONLY)
 PPC_OP(store_tbl)
 {
     cpu_ppc_store_tbl(regs, T0);
@@ -360,7 +371,8 @@ PPC_OP(store_tbu)
 PPC_OP(load_decr)
 {
     T0 = cpu_ppc_load_decr(regs);
-    }
+    RETURN();
+}
 
 PPC_OP(store_decr)
 {
@@ -371,15 +383,16 @@ PPC_OP(store_decr)
 PPC_OP(load_ibat)
 {
     T0 = regs->IBAT[PARAM(1)][PARAM(2)];
+    RETURN();
 }
 
-void op_store_ibatu (void)
+void OPPROTO op_store_ibatu (void)
 {
     do_store_ibatu(env, PARAM1, T0);
     RETURN();
 }
 
-void op_store_ibatl (void)
+void OPPROTO op_store_ibatl (void)
 {
 #if 1
     env->IBAT[1][PARAM1] = T0;
@@ -392,15 +405,16 @@ void op_store_ibatl (void)
 PPC_OP(load_dbat)
 {
     T0 = regs->DBAT[PARAM(1)][PARAM(2)];
+    RETURN();
 }
 
-void op_store_dbatu (void)
+void OPPROTO op_store_dbatu (void)
 {
     do_store_dbatu(env, PARAM1, T0);
     RETURN();
 }
 
-void op_store_dbatl (void)
+void OPPROTO op_store_dbatl (void)
 {
 #if 1
     env->DBAT[1][PARAM1] = T0;
@@ -409,17 +423,18 @@ void op_store_dbatl (void)
 #endif
     RETURN();
 }
+#endif /* !defined(CONFIG_USER_ONLY) */
 
 /* FPSCR */
 PPC_OP(load_fpscr)
 {
-    FT0 = do_load_fpscr(env);
+    do_load_fpscr();
     RETURN();
 }
 
 PPC_OP(store_fpscr)
 {
-    do_store_fpscr(env, FT0, PARAM1);
+    do_store_fpscr(PARAM1);
     RETURN();
 }
 
@@ -454,6 +469,7 @@ PPC_OP(setcrfbit)
 PPC_OP(setlr)
 {
     regs->lr = PARAM1;
+    RETURN();
 }
 
 PPC_OP(goto_tb0)
@@ -469,6 +485,7 @@ PPC_OP(goto_tb1)
 PPC_OP(b_T1)
 {
     regs->nip = T1 & ~3;
+    RETURN();
 }
 
 PPC_OP(jz_T0)
@@ -491,11 +508,13 @@ PPC_OP(btest_T1)
 PPC_OP(movl_T1_ctr)
 {
     T1 = regs->ctr;
+    RETURN();
 }
 
 PPC_OP(movl_T1_lr)
 {
     T1 = regs->lr;
+    RETURN();
 }
 
 /* tests with result in T0 */
@@ -503,41 +522,49 @@ PPC_OP(movl_T1_lr)
 PPC_OP(test_ctr)
 {
     T0 = regs->ctr;
+    RETURN();
 }
 
 PPC_OP(test_ctr_true)
 {
     T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
+    RETURN();
 }
 
 PPC_OP(test_ctr_false)
 {
     T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
+    RETURN();
 }
 
 PPC_OP(test_ctrz)
 {
     T0 = (regs->ctr == 0);
+    RETURN();
 }
 
 PPC_OP(test_ctrz_true)
 {
     T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
+    RETURN();
 }
 
 PPC_OP(test_ctrz_false)
 {
     T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
+    RETURN();
 }
 
 PPC_OP(test_true)
 {
     T0 = (T0 & PARAM(1));
+    RETURN();
 }
 
 PPC_OP(test_false)
 {
     T0 = ((T0 & PARAM(1)) == 0);
+    RETURN();
 }
 
 /* CTR maintenance */
@@ -555,8 +582,7 @@ PPC_OP(add)
     RETURN();
 }
 
-void do_addo (void);
-void op_addo (void)
+void OPPROTO op_addo (void)
 {
     do_addo();
     RETURN();
@@ -575,21 +601,19 @@ PPC_OP(addc)
     RETURN();
 }
 
-void do_addco (void);
-void op_addco (void)
+void OPPROTO op_addco (void)
 {
     do_addco();
     RETURN();
 }
 
 /* add extended */
-void do_adde (void);
-void op_adde (void)
+void OPPROTO op_adde (void)
 {
     do_adde();
+    RETURN();
 }
 
-void do_addeo (void);
 PPC_OP(addeo)
 {
     do_addeo();
@@ -626,8 +650,7 @@ PPC_OP(addme)
     RETURN();
 }
 
-void do_addmeo (void);
-void op_addmeo (void)
+void OPPROTO op_addmeo (void)
 {
     do_addmeo();
     RETURN();
@@ -646,8 +669,7 @@ PPC_OP(addze)
     RETURN();
 }
 
-void do_addzeo (void);
-void op_addzeo (void)
+void OPPROTO op_addzeo (void)
 {
     do_addzeo();
     RETURN();
@@ -664,8 +686,7 @@ PPC_OP(divw)
     RETURN();
 }
 
-void do_divwo (void);
-void op_divwo (void)
+void OPPROTO op_divwo (void)
 {
     do_divwo();
     RETURN();
@@ -682,8 +703,7 @@ PPC_OP(divwu)
     RETURN();
 }
 
-void do_divwuo (void);
-void op_divwuo (void)
+void OPPROTO op_divwuo (void)
 {
     do_divwuo();
     RETURN();
@@ -717,8 +737,7 @@ PPC_OP(mullw)
     RETURN();
 }
 
-void do_mullwo (void);
-void op_mullwo (void)
+void OPPROTO op_mullwo (void)
 {
     do_mullwo();
     RETURN();
@@ -733,8 +752,7 @@ PPC_OP(neg)
     RETURN();
 }
 
-void do_nego (void);
-void op_nego (void)
+void OPPROTO op_nego (void)
 {
     do_nego();
     RETURN();
@@ -747,8 +765,7 @@ PPC_OP(subf)
     RETURN();
 }
 
-void do_subfo (void);
-void op_subfo (void)
+void OPPROTO op_subfo (void)
 {
     do_subfo();
     RETURN();
@@ -766,22 +783,19 @@ PPC_OP(subfc)
     RETURN();
 }
 
-void do_subfco (void);
-void op_subfco (void)
+void OPPROTO op_subfco (void)
 {
     do_subfco();
     RETURN();
 }
 
 /* substract from extended */
-void do_subfe (void);
-void op_subfe (void)
+void OPPROTO op_subfe (void)
 {
     do_subfe();
     RETURN();
 }
 
-void do_subfeo (void);
 PPC_OP(subfeo)
 {
     do_subfeo();
@@ -810,8 +824,7 @@ PPC_OP(subfme)
     RETURN();
 }
 
-void do_subfmeo (void);
-void op_subfmeo (void)
+void OPPROTO op_subfmeo (void)
 {
     do_subfmeo();
     RETURN();
@@ -830,8 +843,7 @@ PPC_OP(subfze)
     RETURN();
 }
 
-void do_subfzeo (void);
-void op_subfzeo (void)
+void OPPROTO op_subfzeo (void)
 {
     do_subfzeo();
     RETURN();
@@ -906,18 +918,48 @@ PPC_OP(andc)
 }
 
 /* andi. */
-PPC_OP(andi_)
+void OPPROTO op_andi_T0 (void)
 {
     T0 &= PARAM(1);
     RETURN();
 }
 
+void OPPROTO op_andi_T1 (void)
+{
+    T1 &= PARAM1;
+    RETURN();
+}
+
 /* count leading zero */
-PPC_OP(cntlzw)
+void OPPROTO op_cntlzw (void)
 {
-    T1 = T0;
-    for (T0 = 32; T1 > 0; T0--)
-        T1 = T1 >> 1;
+    int cnt;
+
+    cnt = 0;
+    if (!(T0 & 0xFFFF0000UL)) {
+        cnt += 16;
+        T0 <<= 16;
+    }
+    if (!(T0 & 0xFF000000UL)) {
+        cnt += 8;
+        T0 <<= 8;
+    }
+    if (!(T0 & 0xF0000000UL)) {
+        cnt += 4;
+        T0 <<= 4;
+    }
+    if (!(T0 & 0xC0000000UL)) {
+        cnt += 2;
+        T0 <<= 2;
+    }
+    if (!(T0 & 0x80000000UL)) {
+        cnt++;
+        T0 <<= 1;
+    }
+    if (!(T0 & 0x80000000UL)) {
+        cnt++;
+    }
+    T0 = cnt;
     RETURN();
 }
 
@@ -992,48 +1034,15 @@ PPC_OP(xori)
 }
 
 /***                             Integer rotate                            ***/
-/* rotate left word immediate then mask insert */
-PPC_OP(rlwimi)
-{
-    T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
-    RETURN();
-}
-
-/* rotate left immediate then and with mask insert */
-PPC_OP(rotlwi)
-{
-    T0 = rotl(T0, PARAM(1));
-    RETURN();
-}
-
-PPC_OP(slwi)
-{
-    T0 = T0 << PARAM(1);
-    RETURN();
-}
-
-PPC_OP(srwi)
+void OPPROTO op_rotl32_T0_T1 (void)
 {
-    T0 = T0 >> PARAM(1);
+    T0 = rotl32(T0, T1 & 0x1F);
     RETURN();
 }
 
-/* rotate left word then and with mask insert */
-PPC_OP(rlwinm)
+void OPPROTO op_rotli32_T0 (void)
 {
-    T0 = rotl(T0, PARAM(1)) & PARAM(2);
-    RETURN();
-}
-
-PPC_OP(rotl)
-{
-    T0 = rotl(T0, T1);
-    RETURN();
-}
-
-PPC_OP(rlwnm)
-{
-    T0 = rotl(T0, T1) & PARAM(1);
+    T0 = rotl32(T0, PARAM1);
     RETURN();
 }
 
@@ -1050,7 +1059,7 @@ PPC_OP(slw)
 }
 
 /* shift right algebraic word */
-void op_sraw (void)
+void OPPROTO op_sraw (void)
 {
     do_sraw();
     RETURN();
@@ -1080,25 +1089,55 @@ PPC_OP(srw)
     RETURN();
 }
 
+void OPPROTO op_sl_T0_T1 (void)
+{
+    T0 = T0 << T1;
+    RETURN();
+}
+
+void OPPROTO op_sli_T0 (void)
+{
+    T0 = T0 << PARAM1;
+    RETURN();
+}
+
+void OPPROTO op_srl_T0_T1 (void)
+{
+    T0 = T0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_srli_T0 (void)
+{
+    T0 = T0 >> PARAM1;
+    RETURN();
+}
+
+void OPPROTO op_srli_T1 (void)
+{
+    T1 = T1 >> PARAM1;
+    RETURN();
+}
+
 /***                       Floating-Point arithmetic                       ***/
 /* fadd - fadd. */
 PPC_OP(fadd)
 {
-    FT0 += FT1;
+    FT0 = float64_add(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fsub - fsub. */
 PPC_OP(fsub)
 {
-    FT0 -= FT1;
+    FT0 = float64_sub(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fmul - fmul. */
 PPC_OP(fmul)
 {
-    FT0 *= FT1;
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
@@ -1141,14 +1180,16 @@ PPC_OP(fsel)
 /* fmadd - fmadd. */
 PPC_OP(fmadd)
 {
-    FT0 = (FT0 * FT1) + FT2;
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
+    FT0 = float64_add(FT0, FT2, &env->fp_status);
     RETURN();
 }
 
 /* fmsub - fmsub. */
 PPC_OP(fmsub)
 {
-    FT0 = (FT0 * FT1) - FT2;
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
+    FT0 = float64_sub(FT0, FT2, &env->fp_status);
     RETURN();
 }
 
@@ -1170,7 +1211,7 @@ PPC_OP(fnmsub)
 /* frsp - frsp. */
 PPC_OP(frsp)
 {
-    FT0 = (float)FT0;
+    FT0 = float64_to_float32(FT0, &env->fp_status);
     RETURN();
 }
 
@@ -1188,7 +1229,6 @@ PPC_OP(fctiwz)
     RETURN();
 }
 
-
 /***                         Floating-Point compare                        ***/
 /* fcmpu */
 PPC_OP(fcmpu)
@@ -1229,12 +1269,14 @@ PPC_OP(fneg)
 
 /* Load and store */
 #define MEMSUFFIX _raw
+#include "op_helper.h"
 #include "op_mem.h"
 #if !defined(CONFIG_USER_ONLY)
 #define MEMSUFFIX _user
+#include "op_helper.h"
 #include "op_mem.h"
-
 #define MEMSUFFIX _kernel
+#include "op_helper.h"
 #include "op_mem.h"
 #endif
 
@@ -1247,24 +1289,18 @@ PPC_OP(check_reservation)
 }
 
 /* Return from interrupt */
-void do_rfi (void);
-void op_rfi (void)
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_rfi (void)
 {
     do_rfi();
     RETURN();
 }
+#endif
 
 /* Trap word */
-void do_tw (uint32_t cmp, int flags);
-void op_tw (void)
-{
-    do_tw(T1, PARAM(1));
-    RETURN();
-}
-
-void op_twi (void)
+void OPPROTO op_tw (void)
 {
-    do_tw(PARAM(1), PARAM(2));
+    do_tw(PARAM1);
     RETURN();
 }
 
@@ -1275,6 +1311,7 @@ PPC_OP(icbi)
     RETURN();
 }
 
+#if !defined(CONFIG_USER_ONLY)
 /* tlbia */
 PPC_OP(tlbia)
 {
@@ -1288,9 +1325,554 @@ PPC_OP(tlbie)
     do_tlbie();
     RETURN();
 }
+#endif
 
-void op_store_pir (void)
+/* PowerPC 602/603/755 software TLB load instructions */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_6xx_tlbld (void)
+{
+    do_load_6xx_tlb(0);
+    RETURN();
+}
+
+void OPPROTO op_6xx_tlbli (void)
+{
+    do_load_6xx_tlb(1);
+    RETURN();
+}
+#endif
+
+/* 601 specific */
+uint32_t cpu_ppc601_load_rtcl (CPUState *env);
+void OPPROTO op_load_601_rtcl (void)
+{
+    T0 = cpu_ppc601_load_rtcl(env);
+    RETURN();
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env);
+void OPPROTO op_load_601_rtcu (void)
+{
+    T0 = cpu_ppc601_load_rtcu(env);
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value);
+void OPPROTO op_store_601_rtcl (void)
+{
+    cpu_ppc601_store_rtcl(env, T0);
+    RETURN();
+}
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value);
+void OPPROTO op_store_601_rtcu (void)
+{
+    cpu_ppc601_store_rtcu(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_load_601_bat (void)
+{
+    T0 = env->IBAT[PARAM1][PARAM2];
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* 601 unified BATs store.
+ * To avoid using specific MMU code for 601, we store BATs in
+ * IBAT and DBAT simultaneously, then emulate unified BATs.
+ */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_batl (void)
+{
+    int nr = PARAM1;
+
+    env->IBAT[1][nr] = T0;
+    env->DBAT[1][nr] = T0;
+    RETURN();
+}
+
+void OPPROTO op_store_601_batu (void)
+{
+    do_store_601_batu(PARAM1);
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific instructions (POWER bridge) */
+/* XXX: those micro-ops need tests ! */
+void OPPROTO op_POWER_abs (void)
+{
+    if (T0 == INT32_MIN)
+        T0 = INT32_MAX;
+    else if (T0 < 0)
+        T0 = -T0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_abso (void)
+{
+    do_POWER_abso();
+    RETURN();
+}
+
+void OPPROTO op_POWER_clcs (void)
+{
+    do_POWER_clcs();
+    RETURN();
+}
+
+void OPPROTO op_POWER_div (void)
+{
+    do_POWER_div();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divo (void)
+{
+    do_POWER_divo();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divs (void)
+{
+    do_POWER_divs();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divso (void)
+{
+    do_POWER_divso();
+    RETURN();
+}
+
+void OPPROTO op_POWER_doz (void)
+{
+    if (Ts1 > Ts0)
+        T0 = T1 - T0;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_dozo (void)
+{
+    do_POWER_dozo();
+    RETURN();
+}
+
+void OPPROTO op_load_xer_cmp (void)
+{
+    T2 = xer_cmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_maskg (void)
+{
+    do_POWER_maskg();
+    RETURN();
+}
+
+void OPPROTO op_POWER_maskir (void)
+{
+    T0 = (T0 & ~T2) | (T1 & T2);
+    RETURN();
+}
+
+void OPPROTO op_POWER_mul (void)
+{
+    uint64_t tmp;
+
+    tmp = (uint64_t)T0 * (uint64_t)T1;
+    env->spr[SPR_MQ] = tmp >> 32;
+    T0 = tmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_mulo (void)
+{
+    do_POWER_mulo();
+    RETURN();
+}
+
+void OPPROTO op_POWER_nabs (void)
+{
+    if (T0 > 0)
+        T0 = -T0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_nabso (void)
+{
+    /* nabs never overflows */
+    if (T0 > 0)
+        T0 = -T0;
+    xer_ov = 0;
+    RETURN();
+}
+
+/* XXX: factorise POWER rotates... */
+void OPPROTO op_POWER_rlmi (void)
+{
+    T0 = rotl32(T0, T2) & PARAM1;
+    T0 |= T1 & PARAM2;
+    RETURN();
+}
+
+void OPPROTO op_POWER_rrib (void)
+{
+    T2 &= 0x1FUL;
+    T0 = rotl32(T0 & INT32_MIN, T2);
+    T0 |= T1 & ~rotl32(INT32_MIN, T2);
+    RETURN();
+}
+
+void OPPROTO op_POWER_sle (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, T1);
+    T0 = T0 << T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sleq (void)
+{
+    uint32_t tmp = env->spr[SPR_MQ];
+
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, T1);
+    T0 = T0 << T1;
+    T0 |= tmp >> (32 - T1);
+    RETURN();
+}
+
+void OPPROTO op_POWER_sllq (void)
+{
+    uint32_t msk = -1;
+
+    msk = msk << (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    T0 = (T0 << T1) & msk;
+    T0 |= env->spr[SPR_MQ] & ~msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_slq (void)
+{
+    uint32_t msk = -1, tmp;
+
+    msk = msk << (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    tmp = rotl32(T0, T1);
+    T0 = tmp & msk;
+    env->spr[SPR_MQ] = tmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sraq (void)
+{
+    env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL));
+    if (T1 & 0x20UL)
+        T0 = -1L;
+    else
+        T0 = Ts0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sre (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = Ts0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srea (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = T0 >> T1;
+    T0 = Ts0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sreq (void)
+{
+    uint32_t tmp;
+    int32_t msk;
+
+    T1 &= 0x1FUL;
+    msk = INT32_MIN >> T1;
+    tmp = env->spr[SPR_MQ];
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    T0 |= tmp & msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srlq (void)
+{
+    uint32_t tmp;
+    int32_t msk;
+
+    msk = INT32_MIN >> (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    tmp = env->spr[SPR_MQ];
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    T0 &= msk;
+    T0 |= tmp & ~msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srq (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    RETURN();
+}
+
+/* POWER instructions not implemented in PowerPC 601 */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_POWER_mfsri (void)
+{
+    T1 = T0 >> 28;
+    T0 = env->sr[T1];
+    RETURN();
+}
+
+void OPPROTO op_POWER_rac (void)
+{
+    do_POWER_rac();
+    RETURN();
+}
+
+void OPPROTO op_POWER_rfsvc (void)
+{
+    do_POWER_rfsvc();
+    RETURN();
+}
+#endif
+
+/* PowerPC 602 specific instruction */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_602_mfrom (void)
+{
+    do_op_602_mfrom();
+    RETURN();
+}
+#endif
+
+/* PowerPC 4xx specific micro-ops */
+void OPPROTO op_405_add_T0_T2 (void)
+{
+    T0 = (int32_t)T0 + (int32_t)T2;
+    RETURN();
+}
+
+void OPPROTO op_405_mulchw (void)
+{
+    T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulchwu (void)
+{
+    T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulhhw (void)
+{
+    T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulhhwu (void)
+{
+    T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mullhw (void)
+{
+    T0 = ((int16_t)T0) * ((int16_t)T1);
+    RETURN();
+}
+
+void OPPROTO op_405_mullhwu (void)
+{
+    T0 = ((uint16_t)T0) * ((uint16_t)T1);
+    RETURN();
+}
+
+void OPPROTO op_405_check_ov (void)
+{
+    do_405_check_ov();
+    RETURN();
+}
+
+void OPPROTO op_405_check_sat (void)
+{
+    do_405_check_sat();
+    RETURN();
+}
+
+void OPPROTO op_405_check_ovu (void)
+{
+    if (likely(T0 >= T2)) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    RETURN();
+}
+
+void OPPROTO op_405_check_satu (void)
+{
+    if (unlikely(T0 < T2)) {
+        /* Saturate result */
+        T0 = -1;
+    }
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_4xx_load_dcr (void)
+{
+    do_4xx_load_dcr(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_4xx_store_dcr (void)
+{
+    do_4xx_store_dcr(PARAM1);
+    RETURN();
+}
+
+/* Return from critical interrupt :
+ * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1
+ */
+void OPPROTO op_4xx_rfci (void)
+{
+    do_4xx_rfci();
+    RETURN();
+}
+
+void OPPROTO op_4xx_wrte (void)
+{
+    msr_ee = T0 >> 16;
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_lo (void)
+{
+    do_4xx_tlbre_lo();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_hi (void)
+{
+    do_4xx_tlbre_hi();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx (void)
+{
+    do_4xx_tlbsx();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx_ (void)
+{
+    do_4xx_tlbsx_();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_lo (void)
+{
+    do_4xx_tlbwe_lo();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_hi (void)
+{
+    do_4xx_tlbwe_hi();
+    RETURN();
+}
+#endif
+
+/* SPR micro-ops */
+/* 440 specific */
+void OPPROTO op_440_dlmzb (void)
+{
+    do_440_dlmzb();
+    RETURN();
+}
+
+void OPPROTO op_440_dlmzb_update_Rc (void)
+{
+    if (T0 == 8)
+        T0 = 0x2;
+    else if (T0 < 4)
+        T0 = 0x4;
+    else
+        T0 = 0x8;
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_pir (void)
 {
     env->spr[SPR_PIR] = T0 & 0x0000000FUL;
     RETURN();
 }
+
+void OPPROTO op_load_403_pb (void)
+{
+    do_load_403_pb(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_store_403_pb (void)
+{
+    do_store_403_pb(PARAM1);
+    RETURN();
+}
+
+target_ulong load_40x_pit (CPUState *env);
+void OPPROTO op_load_40x_pit (void)
+{
+    T0 = load_40x_pit(env);
+    RETURN();
+}
+
+void store_40x_pit (CPUState *env, target_ulong val);
+void OPPROTO op_store_40x_pit (void)
+{
+    store_40x_pit(env, T0);
+    RETURN();
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val);
+void OPPROTO op_store_booke_tcr (void)
+{
+    store_booke_tcr(env, T0);
+    RETURN();
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val);
+void OPPROTO op_store_booke_tsr (void)
+{
+    store_booke_tsr(env, T0);
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
index e949eb4..ea38497 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation helpers for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
 
 //#define DEBUG_OP
 //#define DEBUG_EXCEPTIONS
+//#define DEBUG_SOFTWARE_TLB
 //#define FLUSH_ALL_TLBS
 
 #define Ts0 (long)((target_long)T0)
@@ -38,7 +39,7 @@
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void cpu_loop_exit(void)
+void cpu_loop_exit (void)
 {
     longjmp(env->jmp_env, 1);
 }
@@ -50,16 +51,16 @@ void do_raise_exception_err (uint32_t exception, int error_code)
 #endif
     switch (exception) {
     case EXCP_PROGRAM:
-       if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
-           return;
-       break;
+        if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
+            return;
+        break;
     default:
-       break;
-}
+        break;
+    }
     env->exception_index = exception;
     env->error_code = error_code;
-        cpu_loop_exit();
-    }
+    cpu_loop_exit();
+}
 
 void do_raise_exception (uint32_t exception)
 {
@@ -67,6 +68,119 @@ void do_raise_exception (uint32_t exception)
 }
 
 /*****************************************************************************/
+/* Registers load and stores */
+void do_load_cr (void)
+{
+    T0 = (env->crf[0] << 28) |
+        (env->crf[1] << 24) |
+        (env->crf[2] << 20) |
+        (env->crf[3] << 16) |
+        (env->crf[4] << 12) |
+        (env->crf[5] << 8) |
+        (env->crf[6] << 4) |
+        (env->crf[7] << 0);
+}
+
+void do_store_cr (uint32_t mask)
+{
+    int i, sh;
+
+    for (i = 0, sh = 7; i < 8; i++, sh --) {
+        if (mask & (1 << sh))
+            env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
+    }
+}
+
+void do_load_xer (void)
+{
+    T0 = (xer_so << XER_SO) |
+        (xer_ov << XER_OV) |
+        (xer_ca << XER_CA) |
+        (xer_bc << XER_BC) |
+        (xer_cmp << XER_CMP);
+}
+
+void do_store_xer (void)
+{
+    xer_so = (T0 >> XER_SO) & 0x01;
+    xer_ov = (T0 >> XER_OV) & 0x01;
+    xer_ca = (T0 >> XER_CA) & 0x01;
+    xer_cmp = (T0 >> XER_CMP) & 0xFF;
+    xer_bc = (T0 >> XER_BC) & 0x3F;
+}
+
+void do_load_fpscr (void)
+{
+    /* The 32 MSB of the target fpr are undefined.
+     * They'll be zero...
+     */
+    union {
+        float64 d;
+        struct {
+            uint32_t u[2];
+        } s;
+    } u;
+    int i;
+
+#ifdef WORDS_BIGENDIAN
+#define WORD0 0
+#define WORD1 1
+#else
+#define WORD0 1
+#define WORD1 0
+#endif
+    u.s.u[WORD0] = 0;
+    u.s.u[WORD1] = 0;
+    for (i = 0; i < 8; i++)
+        u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
+    FT0 = u.d;
+}
+
+void do_store_fpscr (uint32_t mask)
+{
+    /*
+     * We use only the 32 LSB of the incoming fpr
+     */
+    union {
+        double d;
+        struct {
+            uint32_t u[2];
+        } s;
+    } u;
+    int i, rnd_type;
+
+    u.d = FT0;
+    if (mask & 0x80)
+        env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
+    for (i = 1; i < 7; i++) {
+        if (mask & (1 << (7 - i)))
+            env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
+    }
+    /* TODO: update FEX & VX */
+    /* Set rounding mode */
+    switch (env->fpscr[0] & 0x3) {
+    case 0:
+        /* Best approximation (round to nearest) */
+        rnd_type = float_round_nearest_even;
+        break;
+    case 1:
+        /* Smaller magnitude (round toward zero) */
+        rnd_type = float_round_to_zero;
+        break;
+    case 2:
+        /* Round toward +infinite */
+        rnd_type = float_round_up;
+        break;
+    default:
+    case 3:
+        /* Round toward -infinite */
+        rnd_type = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+/*****************************************************************************/
 /* Fixed point operations helpers */
 void do_addo (void)
 {
@@ -301,21 +415,21 @@ void do_sraw (void)
         if (likely(T1 != 0)) {
             ret = (int32_t)T0 >> (T1 & 0x1fUL);
             if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
-    xer_ca = 0;
+                xer_ca = 0;
             } else {
-            xer_ca = 1;
+                xer_ca = 1;
             }
         } else {
-        ret = T0;
+            ret = T0;
             xer_ca = 0;
         }
     } else {
         ret = (-1) * ((uint32_t)T0 >> 31);
         if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
             xer_ca = 0;
-    } else {
+        } else {
             xer_ca = 1;
-    }
+        }
     }
     T0 = ret;
 }
@@ -330,7 +444,7 @@ void do_fctiw (void)
     } p;
 
     /* XXX: higher bits are not supposed to be significant.
-     *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
+     *     to make tests easier, return the same as a real PowerPC 750 (aka G3)
      */
     p.i = float64_to_int32(FT0, &env->fp_status);
     p.i |= 0xFFF80000ULL << 32;
@@ -381,7 +495,7 @@ void do_fres (void)
     } p;
 
     if (likely(isnormal(FT0))) {
-        FT0 = (float)(1.0 / FT0);
+        FT0 = float32_div(1.0, FT0, &env->fp_status);
     } else {
         p.d = FT0;
         if (p.i == 0x8000000000000000ULL) {
@@ -467,8 +581,8 @@ void do_fcmpo (void)
     } else {
         T0 = 0x01UL;
         env->fpscr[4] |= 0x1;
-        /* I don't know how to test "quiet" nan... */
-        if (0 /* || ! quiet_nan(...) */) {
+        if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
+            /* Quiet NaN case */
             env->fpscr[6] |= 0x1;
             if (!(env->fpscr[1] & 0x8))
                 env->fpscr[4] |= 0x8;
@@ -479,6 +593,7 @@ void do_fcmpo (void)
     env->fpscr[3] = T0;
 }
 
+#if !defined (CONFIG_USER_ONLY)
 void do_rfi (void)
 {
     env->nip = env->spr[SPR_SRR0] & ~0x00000003;
@@ -489,14 +604,15 @@ void do_rfi (void)
 #endif
     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
+#endif
 
-void do_tw (uint32_t cmp, int flags)
+void do_tw (int flags)
 {
-    if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
-                  (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
-                  (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
-                  (T0 < cmp && (flags & 0x02)) ||
-                  (T0 > cmp && (flags & 0x01)))))
+    if (!likely(!((Ts0 < Ts1 && (flags & 0x10)) ||
+                  (Ts0 > Ts1 && (flags & 0x08)) ||
+                  (Ts0 == Ts1 && (flags & 0x04)) ||
+                  (T0 < T1 && (flags & 0x02)) ||
+                  (T0 > T1 && (flags & 0x01)))))
         do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
 }
 
@@ -519,20 +635,311 @@ void do_icbi (void)
 }
 
 /*****************************************************************************/
-/* MMU related helpers */
-/* TLB invalidation helpers */
-void do_tlbia (void)
+/* PowerPC 601 specific instructions (POWER bridge) */
+void do_POWER_abso (void)
 {
-    tlb_flush(env, 1);
+    if (T0 == INT32_MIN) {
+        T0 = INT32_MAX;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        T0 = -T0;
+        xer_ov = 0;
+    }
 }
 
-void do_tlbie (void)
+void do_POWER_clcs (void)
 {
-#if !defined(FLUSH_ALL_TLBS)
-    tlb_flush_page(env, T0);
+    switch (T0) {
+    case 0x0CUL:
+        /* Instruction cache line size */
+        T0 = ICACHE_LINE_SIZE;
+        break;
+    case 0x0DUL:
+        /* Data cache line size */
+        T0 = DCACHE_LINE_SIZE;
+        break;
+    case 0x0EUL:
+        /* Minimum cache line size */
+        T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ?
+            ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+        break;
+    case 0x0FUL:
+        /* Maximum cache line size */
+        T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ?
+            ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+        break;
+    default:
+        /* Undefined */
+        break;
+    }
+}
+
+void do_POWER_div (void)
+{
+    uint64_t tmp;
+
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+    } else {
+        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+        env->spr[SPR_MQ] = tmp % T1;
+        T0 = tmp / Ts1;
+    }
+}
+
+void do_POWER_divo (void)
+{
+    int64_t tmp;
+
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+        env->spr[SPR_MQ] = tmp % T1;
+        tmp /= Ts1;
+        if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
+            xer_ov = 1;
+            xer_so = 1;
+        } else {
+            xer_ov = 0;
+        }
+        T0 = tmp;
+    }
+}
+
+void do_POWER_divs (void)
+{
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+    } else {
+        env->spr[SPR_MQ] = T0 % T1;
+        T0 = Ts0 / Ts1;
+    }
+}
+
+void do_POWER_divso (void)
+{
+    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        T0 = Ts0 / Ts1;
+        env->spr[SPR_MQ] = Ts0 % Ts1;
+        xer_ov = 0;
+    }
+}
+
+void do_POWER_dozo (void)
+{
+    if (Ts1 > Ts0) {
+        T2 = T0;
+        T0 = T1 - T0;
+        if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
+            xer_so = 1;
+            xer_ov = 1;
+        } else {
+            xer_ov = 0;
+        }
+    } else {
+        T0 = 0;
+        xer_ov = 0;
+    }
+}
+
+void do_POWER_maskg (void)
+{
+    uint32_t ret;
+
+    if (T0 == T1 + 1) {
+        ret = -1;
+    } else {
+        ret = (((uint32_t)(-1)) >> (T0)) ^
+            (((uint32_t)(-1) >> (T1)) >> 1);
+        if (T0 > T1)
+            ret = ~ret;
+    }
+    T0 = ret;
+}
+
+void do_POWER_mulo (void)
+{
+    uint64_t tmp;
+
+    tmp = (uint64_t)T0 * (uint64_t)T1;
+    env->spr[SPR_MQ] = tmp >> 32;
+    T0 = tmp;
+    if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        xer_ov = 0;
+    }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void do_POWER_rac (void)
+{
+#if 0
+    mmu_ctx_t ctx;
+
+    /* We don't have to generate many instances of this instruction,
+     * as rac is supervisor only.
+     */
+    if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0)
+        T0 = ctx.raddr;
+#endif
+}
+
+void do_POWER_rfsvc (void)
+{
+    env->nip = env->lr & ~0x00000003UL;
+    T0 = env->ctr & 0x0000FFFFUL;
+    do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+    dump_rfi();
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+/* PowerPC 601 BAT management helper */
+void do_store_601_batu (int nr)
+{
+    do_store_ibatu(env, nr, T0);
+    env->DBAT[0][nr] = env->IBAT[0][nr];
+    env->DBAT[1][nr] = env->IBAT[1][nr];
+}
+#endif
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+#define USE_MFROM_ROM_TABLE
+void do_op_602_mfrom (void)
+{
+    if (likely(T0 < 602)) {
+#ifdef USE_MFROM_ROM_TABLE
+#include "mfrom_table.c"
+        T0 = mfrom_ROM_table[T0];
 #else
-    do_tlbia();
+        double d;
+        /* Extremly decomposed:
+         *                    -T0 / 256
+         * T0 = 256 * log10(10          + 1.0) + 0.5
+         */
+        d = T0;
+        d = float64_div(d, 256, &env->fp_status);
+        d = float64_chs(d);
+        d = exp10(d); // XXX: use float emulation function
+        d = float64_add(d, 1.0, &env->fp_status);
+        d = log10(d); // XXX: use float emulation function
+        d = float64_mul(d, 256, &env->fp_status);
+        d = float64_add(d, 0.5, &env->fp_status);
+        T0 = float64_round_to_int(d, &env->fp_status);
 #endif
+    } else {
+        T0 = 0;
+    }
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+void do_405_check_ov (void)
+{
+    if (likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+}
+
+void do_405_check_sat (void)
+{
+    if (!likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) {
+        /* Saturate result */
+        if (T2 >> 31) {
+            T0 = INT32_MIN;
+        } else {
+            T0 = INT32_MAX;
+        }
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void do_4xx_rfci (void)
+{
+    env->nip = env->spr[SPR_40x_SRR2];
+    T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000;
+    do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+    dump_rfi();
+#endif
+    env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_4xx_load_dcr (int dcrn)
+{
+    target_ulong val;
+    
+    if (unlikely(env->dcr_read == NULL))
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+    else if (unlikely((*env->dcr_read)(env->dcr_env, dcrn, &val) != 0))
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+    else
+        T0 = val;
+}
+
+void do_4xx_store_dcr (int dcrn)
+{
+    if (unlikely(env->dcr_write == NULL))
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+    else if (unlikely((*env->dcr_write)(env->dcr_env, dcrn, T0) != 0))
+        do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+}
+
+void do_load_403_pb (int num)
+{
+    T0 = env->pb[num];
+}
+
+void do_store_403_pb (int num)
+{
+    if (likely(env->pb[num] != T0)) {
+        env->pb[num] = T0;
+        /* Should be optimized */
+        tlb_flush(env, 1);
+    }
+}
+#endif
+
+/* 440 specific */
+void do_440_dlmzb (void)
+{
+    target_ulong mask;
+    int i;
+
+    i = 1;
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((T0 & mask) == 0)
+            goto done;
+        i++;
+    }
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((T1 & mask) == 0)
+            break;
+        i++;
+    }
+ done:
+    T0 = i;
 }
 
 /*****************************************************************************/
@@ -570,7 +977,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
     saved_env = env;
     env = cpu_single_env;
     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
-    if (!likely(ret == 0)) {
+    if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
             pc = (target_phys_addr_t)retaddr;
@@ -579,11 +986,230 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
                 /* the PC is inside the translated code. It means that we have
                    a virtual CPU fault */
                 cpu_restore_state(tb, env, pc, NULL);
-}
+            }
         }
         do_raise_exception_err(env->exception_index, env->error_code);
     }
     env = saved_env;
 }
-#endif /* !CONFIG_USER_ONLY */
 
+/* TLB invalidation helpers */
+void do_tlbia (void)
+{
+    if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+        ppc6xx_tlb_invalidate_all(env);
+    } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+        /* XXX: TODO */
+#if 0
+        ppcbooke_tlb_invalidate_all(env);
+#endif
+    } else {
+        tlb_flush(env, 1);
+    }
+}
+
+void do_tlbie (void)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+        ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
+        if (env->id_tlbs == 1)
+            ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
+    } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+        /* XXX: TODO */
+#if 0
+        ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
+                                     env->spr[SPR_BOOKE_PID]);
+#endif
+    } else {
+        /* tlbie invalidate TLBs for all segments */
+        T0 &= TARGET_PAGE_MASK;
+        T0 &= ~((target_ulong)-1 << 28);
+        /* XXX: this case should be optimized,
+         * giving a mask to tlb_flush_page
+         */
+        tlb_flush_page(env, T0 | (0x0 << 28));
+        tlb_flush_page(env, T0 | (0x1 << 28));
+        tlb_flush_page(env, T0 | (0x2 << 28));
+        tlb_flush_page(env, T0 | (0x3 << 28));
+        tlb_flush_page(env, T0 | (0x4 << 28));
+        tlb_flush_page(env, T0 | (0x5 << 28));
+        tlb_flush_page(env, T0 | (0x6 << 28));
+        tlb_flush_page(env, T0 | (0x7 << 28));
+        tlb_flush_page(env, T0 | (0x8 << 28));
+        tlb_flush_page(env, T0 | (0x9 << 28));
+        tlb_flush_page(env, T0 | (0xA << 28));
+        tlb_flush_page(env, T0 | (0xB << 28));
+        tlb_flush_page(env, T0 | (0xC << 28));
+        tlb_flush_page(env, T0 | (0xD << 28));
+        tlb_flush_page(env, T0 | (0xE << 28));
+        tlb_flush_page(env, T0 | (0xF << 28));
+    }
+#else
+    do_tlbia();
+#endif
+}
+
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+void do_load_6xx_tlb (int is_code)
+{
+    target_ulong RPN, CMP, EPN;
+    int way;
+    
+    RPN = env->spr[SPR_RPA];
+    if (is_code) {
+        CMP = env->spr[SPR_ICMP];
+        EPN = env->spr[SPR_IMISS];
+    } else {
+        CMP = env->spr[SPR_DCMP];
+        EPN = env->spr[SPR_DMISS];
+    }
+    way = (env->spr[SPR_SRR1] >> 17) & 1;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+                __func__, (unsigned long)T0, (unsigned long)EPN,
+                (unsigned long)CMP, (unsigned long)RPN, way);
+    }
+#endif
+    /* Store this TLB */
+    ppc6xx_tlb_store(env, T0 & TARGET_PAGE_MASK, way, is_code, CMP, RPN);
+}
+
+/* Helpers for 4xx TLB management */
+void do_4xx_tlbia (void)
+{
+#if 0
+    ppc_tlb_t *tlb;
+    target_ulong page, end;
+    int i;
+
+    for (i = 0; i < 64; i++) {
+        tlb = &env->tlb[i];
+        if (tlb->prot & PAGE_VALID) {
+            end = tlb->EPN + tlb->size;
+            for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+            tlb->prot &= ~PAGE_VALID;
+        }
+    }
+#endif
+}
+
+void do_4xx_tlbre_lo (void)
+{
+#if 0
+    ppc_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0];
+    T0 = tlb->stor[0];
+    env->spr[SPR_40x_PID] = tlb->pid;
+#endif
+}
+
+void do_4xx_tlbre_hi (void)
+{
+#if 0
+    ppc_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0];
+    T0 = tlb->stor[1];
+#endif
+}
+
+static int tlb_4xx_search (target_ulong virtual)
+{
+#if 0
+    ppc_tlb_t *tlb;
+    target_ulong base, mask;
+    int i, ret;
+
+    /* Default return value is no match */
+    ret = -1;
+    for (i = 0; i < 64; i++) {
+        tlb = &env->tlb[i];
+        /* Check TLB validity */
+        if (!(tlb->prot & PAGE_VALID))
+            continue;
+        /* Check TLB PID vs current PID */
+        if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID])
+            continue;
+        /* Check TLB address vs virtual address */
+        base = tlb->EPN;
+        mask = ~(tlb->size - 1);
+        if ((base & mask) != (virtual & mask))
+            continue;
+        ret = i;
+        break;
+    }
+
+    return ret;
+#else
+    return -1;
+#endif
+}
+
+void do_4xx_tlbsx (void)
+{
+    T0 = tlb_4xx_search(T0);
+}
+
+void do_4xx_tlbsx_ (void)
+{
+    int tmp = xer_ov;
+
+    T0 = tlb_4xx_search(T0);
+    if (T0 != -1)
+        tmp |= 0x02;
+    env->crf[0] = tmp;
+}
+
+void do_4xx_tlbwe_lo (void)
+{
+#if 0
+    ppc_tlb_t *tlb;
+    target_ulong page, end;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0];
+    /* Invalidate previous TLB (if it's valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+            tlb_flush_page(env, page);
+    }
+    tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7));
+    tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
+    if (T1 & 0x400)
+        tlb->prot |= PAGE_VALID;
+    else
+        tlb->prot &= ~PAGE_VALID;
+    tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */
+    /* Invalidate new TLB (if valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+            tlb_flush_page(env, page);
+    }
+#endif
+}
+
+void do_4xx_tlbwe_hi (void)
+{
+#if 0
+    ppc_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0];
+    tlb->RPN = T1 & 0xFFFFFC00;
+    tlb->prot = PAGE_READ;
+    if (T1 & 0x200)
+        tlb->prot |= PAGE_EXEC;
+    if (T1 & 0x100)
+        tlb->prot |= PAGE_WRITE;
+#endif
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
new file mode 100644 (file)
index 0000000..0cba002
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  PowerPC emulation helpers header for qemu.
+ * 
+ *  Copyright (c) 2003-2007 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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy 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
+ */
+
+#if defined(MEMSUFFIX)
+
+/* Memory load/store helpers */
+void glue(do_lsw, MEMSUFFIX) (int dst);
+void glue(do_lsw_le, MEMSUFFIX) (int dst);
+void glue(do_stsw, MEMSUFFIX) (int src);
+void glue(do_stsw_le, MEMSUFFIX) (int src);
+void glue(do_lmw, MEMSUFFIX) (int dst);
+void glue(do_lmw_le, MEMSUFFIX) (int dst);
+void glue(do_stmw, MEMSUFFIX) (int src);
+void glue(do_stmw_le, MEMSUFFIX) (int src);
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb);
+void glue(do_POWER2_lfq, MEMSUFFIX) (void);
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void);
+
+#else
+
+/* Registers load and stores */
+void do_load_cr (void);
+void do_store_cr (uint32_t mask);
+void do_load_xer (void);
+void do_store_xer (void);
+void do_load_fpscr (void);
+void do_store_fpscr (uint32_t mask);
+
+/* Integer arithmetic helpers */
+void do_addo (void);
+void do_addco (void);
+void do_adde (void);
+void do_addeo (void);
+void do_addmeo (void);
+void do_addzeo (void);
+void do_divwo (void);
+void do_divwuo (void);
+void do_mullwo (void);
+void do_nego (void);
+void do_subfo (void);
+void do_subfco (void);
+void do_subfe (void);
+void do_subfeo (void);
+void do_subfmeo (void);
+void do_subfzeo (void);
+void do_sraw(void);
+
+/* Floating-point arithmetic helpers */
+void do_fsqrt (void);
+void do_fres (void);
+void do_frsqrte (void);
+void do_fsel (void);
+void do_fnmadd (void);
+void do_fnmsub (void);
+void do_fctiw (void);
+void do_fctiwz (void);
+void do_fcmpu (void);
+void do_fcmpo (void);
+
+void do_tw (int flags);
+void do_icbi (void);
+
+#if !defined(CONFIG_USER_ONLY)
+void do_rfi (void);
+void do_tlbia (void);
+void do_tlbie (void);
+void do_load_6xx_tlb (int is_code);
+#endif
+
+/* POWER / PowerPC 601 specific helpers */
+void do_store_601_batu (int nr);
+void do_POWER_abso (void);
+void do_POWER_clcs (void);
+void do_POWER_div (void);
+void do_POWER_divo (void);
+void do_POWER_divs (void);
+void do_POWER_divso (void);
+void do_POWER_dozo (void);
+void do_POWER_maskg (void);
+void do_POWER_mulo (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_POWER_rac (void);
+void do_POWER_rfsvc (void);
+#endif
+
+/* PowerPC 602 specific helper */
+#if !defined(CONFIG_USER_ONLY)
+void do_op_602_mfrom (void);
+#endif
+
+/* PowerPC 4xx specific helpers */
+void do_405_check_ov (void);
+void do_405_check_sat (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_4xx_load_dcr (int dcrn);
+void do_4xx_store_dcr (int dcrn);
+void do_4xx_rfci (void);
+void do_4xx_tlbre_lo (void);
+void do_4xx_tlbre_hi (void);
+void do_4xx_tlbsx (void);
+void do_4xx_tlbsx_ (void);
+void do_4xx_tlbwe_lo (void);
+void do_4xx_tlbwe_hi (void);
+#endif
+
+void do_440_dlmzb (void);
+
+#if !defined(CONFIG_USER_ONLY)
+void do_load_403_pb (int num);
+void do_store_403_pb (int num);
+#endif
+
+#endif
index fb90691..45bb90d 100644 (file)
@@ -1,20 +1,78 @@
+/*
+ *  PowerPC emulation micro-operations helpers for qemu.
+ * 
+ *  Copyright (c) 2003-2007 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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy 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
+ */
+
+/* Multiple word / string load and store */
+static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+    return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) |
+        ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24);
+}
+
+static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data)
+{
+    uint32_t tmp =
+        ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) |
+        ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24);
+    glue(stl, MEMSUFFIX)(EA, tmp);
+}
+
+void glue(do_lmw, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
+    }
+}
+
+void glue(do_stmw, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(stl, MEMSUFFIX)(T0, ugpr(src));
+    }
+}
+
+void glue(do_lmw_le, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
+    }
+}
+
+void glue(do_stmw_le, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(st32r, MEMSUFFIX)(T0, ugpr(src));
+    }
+}
+
 void glue(do_lsw, MEMSUFFIX) (int dst)
 {
     uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, dst);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
         ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
-        if (dst == 32)
+        if (unlikely(dst == 32))
             dst = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         tmp = 0;
         for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
             tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
@@ -27,18 +85,12 @@ void glue(do_stsw, MEMSUFFIX) (int src)
 {
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, src);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
         glue(stl, MEMSUFFIX)(T0, ugpr(src++));
-        if (src == 32)
+        if (unlikely(src == 32))
             src = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
             glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
     }
@@ -49,20 +101,12 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
     uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, dst);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        tmp = glue(ldl, MEMSUFFIX)(T0);
-        ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
-            ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
-        if (dst == 32)
+        ugpr(dst++) = glue(ld32r, MEMSUFFIX)(T0);
+        if (unlikely(dst == 32))
             dst = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         tmp = 0;
         for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
             tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
@@ -73,28 +117,108 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
 
 void glue(do_stsw_le, MEMSUFFIX) (int src)
 {
-    uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, src);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        tmp = ((ugpr(src++) & 0xFF000000) >> 24);
-        tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);
-        tmp |= ((ugpr(src++) & 0x0000FF00) << 8);
-        tmp |= ((ugpr(src++) & 0x000000FF) << 24);
-        glue(stl, MEMSUFFIX)(T0, tmp);
-        if (src == 32)
+        glue(st32r, MEMSUFFIX)(T0, ugpr(src++));
+        if (unlikely(src == 32))
             src = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
             glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
     }
 }
 
+/* PPC 601 specific instructions (POWER bridge) */
+// XXX: to be tested
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb)
+{
+    int i, c, d, reg;
+
+    d = 24;
+    reg = dest;
+    for (i = 0; i < T1; i++) {
+        c = glue(ldub, MEMSUFFIX)(T0++);
+        /* ra (if not 0) and rb are never modified */
+        if (likely(reg != rb && (ra == 0 || reg != ra))) {
+            ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d);
+        }
+        if (unlikely(c == T2))
+            break;
+        if (likely(d != 0)) {
+            d -= 8;
+        } else {
+            d = 24;
+            reg++;
+            reg = reg & 0x1F;
+        }
+    }
+    T0 = i;
+}
+
+/* XXX: TAGs are not managed */
+void glue(do_POWER2_lfq, MEMSUFFIX) (void)
+{
+    FT0 = glue(ldfq, MEMSUFFIX)(T0);
+    FT1 = glue(ldfq, MEMSUFFIX)(T0 + 4);
+}
+
+static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    u.d = glue(ldfq, MEMSUFFIX)(EA);
+    u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+        ((u.u & 0x00FF000000000000ULL) >> 40) |
+        ((u.u & 0x0000FF0000000000ULL) >> 24) |
+        ((u.u & 0x000000FF00000000ULL) >> 8) |
+        ((u.u & 0x00000000FF000000ULL) << 8) |
+        ((u.u & 0x0000000000FF0000ULL) << 24) |
+        ((u.u & 0x000000000000FF00ULL) << 40) |
+        ((u.u & 0x00000000000000FFULL) << 56);
+
+    return u.d;
+}
+
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+    FT0 = glue(ldfqr, MEMSUFFIX)(T0 + 4);
+    FT1 = glue(ldfqr, MEMSUFFIX)(T0);
+}
+
+void glue(do_POWER2_stfq, MEMSUFFIX) (void)
+{
+    glue(stfq, MEMSUFFIX)(T0, FT0);
+    glue(stfq, MEMSUFFIX)(T0 + 4, FT1);
+}
+
+static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    u.d = d;
+    u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+        ((u.u & 0x00FF000000000000ULL) >> 40) |
+        ((u.u & 0x0000FF0000000000ULL) >> 24) |
+        ((u.u & 0x000000FF00000000ULL) >> 8) |
+        ((u.u & 0x00000000FF000000ULL) << 8) |
+        ((u.u & 0x0000000000FF0000ULL) << 24) |
+        ((u.u & 0x000000000000FF00ULL) << 40) |
+        ((u.u & 0x00000000000000FFULL) << 56);
+    glue(stfq, MEMSUFFIX)(EA, u.d);
+}
+
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+    glue(stfqr, MEMSUFFIX)(T0 + 4, FT0);
+    glue(stfqr, MEMSUFFIX)(T0, FT1);
+}
+
 #undef MEMSUFFIX
index 9b3f721..a084b31 100644 (file)
@@ -1,6 +1,22 @@
-/* External helpers */
-void glue(do_lsw, MEMSUFFIX) (int dst);
-void glue(do_stsw, MEMSUFFIX) (int src);
+/*
+ *  PowerPC emulation micro-operations for qemu.
+ * 
+ *  Copyright (c) 2003-2007 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 as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy 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
+ */
 
 static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
 {
@@ -11,7 +27,7 @@ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
 static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
 {
     int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
-    return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
+    return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
 }
 
 static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
@@ -80,41 +96,25 @@ PPC_ST_OP(wbr_le, stl);
 /***                    Integer load and store multiple                    ***/
 PPC_OP(glue(lmw, MEMSUFFIX))
 {
-    int dst = PARAM(1);
-
-    for (; dst < 32; dst++, T0 += 4) {
-        ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
-    }
+    glue(do_lmw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-PPC_OP(glue(stmw, MEMSUFFIX))
+PPC_OP(glue(lmw_le, MEMSUFFIX))
 {
-    int src = PARAM(1);
-
-    for (; src < 32; src++, T0 += 4) {
-        glue(stl, MEMSUFFIX)(T0, ugpr(src));
-    }
+    glue(do_lmw_le, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-PPC_OP(glue(lmw_le, MEMSUFFIX))
+PPC_OP(glue(stmw, MEMSUFFIX))
 {
-    int dst = PARAM(1);
-
-    for (; dst < 32; dst++, T0 += 4) {
-        ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
-    }
+    glue(do_stmw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
 PPC_OP(glue(stmw_le, MEMSUFFIX))
 {
-    int src = PARAM(1);
-
-    for (; src < 32; src++, T0 += 4) {
-        glue(st32r, MEMSUFFIX)(T0, ugpr(src));
-    }
+    glue(do_stmw_le, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
@@ -125,7 +125,6 @@ PPC_OP(glue(lswi, MEMSUFFIX))
     RETURN();
 }
 
-void glue(do_lsw_le, MEMSUFFIX) (int dst);
 PPC_OP(glue(lswi_le, MEMSUFFIX))
 {
     glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@@ -139,9 +138,9 @@ PPC_OP(glue(lswi_le, MEMSUFFIX))
  */
 PPC_OP(glue(lswx, MEMSUFFIX))
 {
-    if (T1 > 0) {
-        if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
-            (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+    if (unlikely(T1 > 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
             do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
         } else {
             glue(do_lsw, MEMSUFFIX)(PARAM(1));
@@ -152,9 +151,9 @@ PPC_OP(glue(lswx, MEMSUFFIX))
 
 PPC_OP(glue(lswx_le, MEMSUFFIX))
 {
-    if (T1 > 0) {
-        if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
-            (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+    if (unlikely(T1 > 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
             do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
         } else {
             glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@@ -169,7 +168,6 @@ PPC_OP(glue(stsw, MEMSUFFIX))
     RETURN();
 }
 
-void glue(do_stsw_le, MEMSUFFIX) (int src);
 PPC_OP(glue(stsw_le, MEMSUFFIX))
 {
     glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
@@ -180,7 +178,7 @@ PPC_OP(glue(stsw_le, MEMSUFFIX))
 #define PPC_STF_OP(name, op)                                                  \
 PPC_OP(glue(glue(st, name), MEMSUFFIX))                                       \
 {                                                                             \
-    glue(op, MEMSUFFIX)(T0, FT1);                                     \
+    glue(op, MEMSUFFIX)(T0, FT0);                                             \
     RETURN();                                                                 \
 }
 
@@ -228,7 +226,7 @@ PPC_STF_OP(fs_le, stflr);
 #define PPC_LDF_OP(name, op)                                                  \
 PPC_OP(glue(glue(l, name), MEMSUFFIX))                                        \
 {                                                                             \
-    FT1 = glue(op, MEMSUFFIX)(T0);                                    \
+    FT0 = glue(op, MEMSUFFIX)(T0);                                            \
     RETURN();                                                                 \
 }
 
@@ -277,22 +275,22 @@ PPC_LDF_OP(fs_le, ldflr);
 /* Load and set reservation */
 PPC_OP(glue(lwarx, MEMSUFFIX))
 {
-    if (T0 & 0x03) {
+    if (unlikely(T0 & 0x03)) {
         do_raise_exception(EXCP_ALIGN);
     } else {
-       T1 = glue(ldl, MEMSUFFIX)(T0);
-       regs->reserve = T0;
+        T1 = glue(ldl, MEMSUFFIX)(T0);
+        regs->reserve = T0;
     }
     RETURN();
 }
 
 PPC_OP(glue(lwarx_le, MEMSUFFIX))
 {
-    if (T0 & 0x03) {
+    if (unlikely(T0 & 0x03)) {
         do_raise_exception(EXCP_ALIGN);
     } else {
-       T1 = glue(ld32r, MEMSUFFIX)(T0);
-       regs->reserve = T0;
+        T1 = glue(ld32r, MEMSUFFIX)(T0);
+        regs->reserve = T0;
     }
     RETURN();
 }
@@ -300,33 +298,33 @@ PPC_OP(glue(lwarx_le, MEMSUFFIX))
 /* Store with reservation */
 PPC_OP(glue(stwcx, MEMSUFFIX))
 {
-    if (T0 & 0x03) {
+    if (unlikely(T0 & 0x03)) {
         do_raise_exception(EXCP_ALIGN);
     } else {
-        if (regs->reserve != T0) {
+        if (unlikely(regs->reserve != T0)) {
             env->crf[0] = xer_ov;
         } else {
             glue(stl, MEMSUFFIX)(T0, T1);
             env->crf[0] = xer_ov | 0x02;
         }
     }
-    regs->reserve = 0;
+    regs->reserve = -1;
     RETURN();
 }
 
 PPC_OP(glue(stwcx_le, MEMSUFFIX))
 {
-    if (T0 & 0x03) {
+    if (unlikely(T0 & 0x03)) {
         do_raise_exception(EXCP_ALIGN);
     } else {
-        if (regs->reserve != T0) {
+        if (unlikely(regs->reserve != T0)) {
             env->crf[0] = xer_ov;
         } else {
             glue(st32r, MEMSUFFIX)(T0, T1);
             env->crf[0] = xer_ov | 0x02;
         }
     }
-    regs->reserve = 0;
+    regs->reserve = -1;
     RETURN();
 }
 
@@ -340,6 +338,17 @@ PPC_OP(glue(dcbz, MEMSUFFIX))
     glue(stl, MEMSUFFIX)(T0 + 0x14, 0);
     glue(stl, MEMSUFFIX)(T0 + 0x18, 0);
     glue(stl, MEMSUFFIX)(T0 + 0x1C, 0);
+#if DCACHE_LINE_SIZE == 64
+    /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+    glue(stl, MEMSUFFIX)(T0 + 0x20UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x24UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x28UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x2CUL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x30UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x34UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x38UL, 0);
+    glue(stl, MEMSUFFIX)(T0 + 0x3CUL, 0);
+#endif
     RETURN();
 }
 
@@ -368,4 +377,41 @@ PPC_OP(glue(ecowx_le, MEMSUFFIX))
     RETURN();
 }
 
+/* XXX: those micro-ops need tests ! */
+/* PowerPC 601 specific instructions (POWER bridge) */
+void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void)
+{
+    /* When byte count is 0, do nothing */
+    if (likely(T1 > 0)) {
+        glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3);
+    }
+    RETURN();
+}
+
+/* POWER2 quad load and store */
+/* XXX: TAGs are not managed */
+void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_lfq, MEMSUFFIX)();
+    RETURN();
+}
+
+void glue(op_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_lfq_le, MEMSUFFIX)();
+    RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_stfq, MEMSUFFIX)();
+    RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_stfq_le, MEMSUFFIX)();
+    RETURN();
+}
+
 #undef MEMSUFFIX
index 1be640d..511d065 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation micro-operations for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  */
 
 /* General purpose registers moves */
-void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void)
 {
     T0 = regs->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void)
 {
     T1 = regs->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void)
 {
     T2 = regs->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void)
 {
     regs->gpr[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void)
 {
     regs->gpr[REG] = T1;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void)
 {
     regs->gpr[REG] = T2;
     RETURN();
 }
+#endif
 
 #if REG <= 7
 /* Condition register moves */
-void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T0_crf, REG) (void)
 {
     T0 = regs->crf[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T1_crf, REG) (void)
 {
     T1 = regs->crf[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T0_crf_crf, REG) (void)
 {
     regs->crf[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
 {
     regs->crf[REG] = T1;
     RETURN();
 }
 
 /* Floating point condition and status register moves */
-void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
+void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
 {
     T0 = regs->fpscr[REG];
     RETURN();
 }
 
 #if REG == 0
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
 {
     regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
-{
-    regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
-    RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
 {
     regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
     RETURN();
 }
 #else
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
 {
     regs->fpscr[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
-{
-    regs->fpscr[REG] = PARAM(1);
-    RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
 {
     regs->fpscr[REG] = 0x0;
     RETURN();
@@ -129,55 +119,42 @@ void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
 #endif /* REG <= 7 */
 
 /* floating point registers moves */
-void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void)
 {
     FT0 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT0;
     RETURN();
 }
 
-void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void)
 {
     FT1 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT1;
     RETURN();
 }
 
-void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void)
 {
     FT2 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT2;
     RETURN();
 }
-
-#if REG <= 15
-/* Segment register moves */
-void OPPROTO glue(op_load_sr, REG)(void)
-{
-    T0 = env->sr[REG];
-    RETURN();
-}
-
-void OPPROTO glue(op_store_sr, REG)(void)
-{
-    do_store_sr(env, REG, T0);
-    RETURN();
-}
 #endif
 
 #undef REG
index 41737d4..1e6c9cb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation for qemu: main translation routines.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,7 @@
 
 //#define DO_SINGLE_STEP
 //#define PPC_DEBUG_DISAS
+//#define DO_PPC_STATISTICS
 
 #ifdef USE_DIRECT_JUMP
 #define TBPARAM(x)
@@ -96,25 +97,12 @@ GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
 GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
 GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
 GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
-    &gen_op_store_T0_fpscri_fpscr0,
-    &gen_op_store_T0_fpscri_fpscr1,
-    &gen_op_store_T0_fpscri_fpscr2,
-    &gen_op_store_T0_fpscri_fpscr3,
-    &gen_op_store_T0_fpscri_fpscr4,
-    &gen_op_store_T0_fpscri_fpscr5,
-    &gen_op_store_T0_fpscri_fpscr6,
-    &gen_op_store_T0_fpscri_fpscr7,
-};
 static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
 {
-    (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
+    gen_op_set_T0(param);
+    gen_op_store_T0_fpscr(n);
 }
 
-/* Segment register moves */
-GEN16(gen_op_load_sr, gen_op_load_sr);
-GEN16(gen_op_store_sr, gen_op_store_sr);
-
 /* General purpose registers moves */
 GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
 GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
@@ -122,7 +110,9 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
 
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
+#if 0 // unused
 GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
+#endif
 
 /* floating point registers moves */
 GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
@@ -130,9 +120,9 @@ GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
 GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
 GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
 GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
+#if 0 // unused
 GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
-
-static uint8_t  spr_access[1024 / 2];
+#endif
 
 /* internal defines */
 typedef struct DisasContext {
@@ -158,8 +148,18 @@ struct opc_handler_t {
     uint32_t type;
     /* handler */
     void (*handler)(DisasContext *ctx);
+#if defined(DO_PPC_STATISTICS)
+    const unsigned char *oname;
+    uint64_t count;
+#endif
 };
 
+static inline void gen_set_Rc0 (DisasContext *ctx)
+{
+    gen_op_cmpi(0);
+    gen_op_set_Rc0();
+}
+
 #define RET_EXCP(ctx, excp, error)                                            \
 do {                                                                          \
     if ((ctx)->exception == EXCP_NONE) {                                      \
@@ -209,13 +209,13 @@ typedef struct opcode_t {
 
 /***                           Instruction decoding                        ***/
 #define EXTRACT_HELPER(name, shift, nb)                                       \
-static inline uint32_t name (uint32_t opcode)                                 \
+static inline target_ulong name (uint32_t opcode)                             \
 {                                                                             \
     return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
 }
 
 #define EXTRACT_SHELPER(name, shift, nb)                                      \
-static inline int32_t name (uint32_t opcode)                                  \
+static inline target_long name (uint32_t opcode)                              \
 {                                                                             \
     return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
 }
@@ -278,7 +278,7 @@ EXTRACT_HELPER(FPIMM, 20, 4);
 /* Displacement */
 EXTRACT_SHELPER(d, 0, 16);
 /* Immediate address */
-static inline uint32_t LI (uint32_t opcode)
+static inline target_ulong LI (uint32_t opcode)
 {
     return (opcode >> 0) & 0x03FFFFFC;
 }
@@ -296,13 +296,29 @@ EXTRACT_HELPER(AA, 1, 1);
 EXTRACT_HELPER(LK, 0, 1);
 
 /* Create a mask between <start> and <end> bits */
-static inline uint32_t MASK (uint32_t start, uint32_t end)
+static inline target_ulong MASK (uint32_t start, uint32_t end)
 {
-    uint32_t ret;
+    target_ulong ret;
 
-    ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
-    if (start > end)
-        return ~ret;
+#if defined(TARGET_PPC64)
+    if (likely(start == 0)) {
+        ret = (uint64_t)(-1ULL) << (63 - end);
+    } else if (likely(end == 63)) {
+        ret = (uint64_t)(-1ULL) >> start;
+    }
+#else
+    if (likely(start == 0)) {
+        ret = (uint32_t)(-1ULL) << (31  - end);
+    } else if (likely(end == 31)) {
+        ret = (uint32_t)(-1ULL) >> start;
+    }
+#endif
+    else {
+        ret = (((target_ulong)(-1ULL)) >> (start)) ^
+            (((target_ulong)(-1ULL) >> (end)) >> 1);
+        if (unlikely(start > end))
+            return ~ret;
+    }
 
     return ret;
 }
@@ -320,6 +336,7 @@ static inline uint32_t MASK (uint32_t start, uint32_t end)
     __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
 #endif
 
+#if defined(DO_PPC_STATISTICS)
 #define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
 OPCODES_SECTION opcode_t opc_##name = {                                       \
     .opc1 = op1,                                                              \
@@ -330,9 +347,25 @@ OPCODES_SECTION opcode_t opc_##name = {                                       \
         .inval   = invl,                                                      \
         .type = _typ,                                                         \
         .handler = &gen_##name,                                               \
+        .oname = stringify(name),                                             \
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
+#else
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+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),                                                 \
+}
+#endif
 
 #define GEN_OPCODE_MARK(name)                                                 \
 OPCODES_SECTION opcode_t opc_##name = {                                       \
@@ -370,9 +403,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 #define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval)                     \
@@ -381,9 +414,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 #define __GEN_INT_ARITH1(name, opc1, opc2, opc3)                              \
@@ -391,18 +424,18 @@ 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();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 #define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3)                            \
 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();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 /* Two operands arithmetic functions */
@@ -454,41 +487,51 @@ GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
 /* addi */
 GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int32_t simm = SIMM(ctx->opcode);
+    target_long simm = SIMM(ctx->opcode);
 
     if (rA(ctx->opcode) == 0) {
+        /* li case */
         gen_op_set_T0(simm);
     } else {
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_addi(simm);
+        if (likely(simm != 0))
+            gen_op_addi(simm);
     }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 /* addic */
 GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
+    target_long simm = SIMM(ctx->opcode);
+
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_addic(SIMM(ctx->opcode));
+    if (likely(simm != 0))
+        gen_op_addic(SIMM(ctx->opcode));
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 /* addic. */
 GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
+    target_long simm = SIMM(ctx->opcode);
+
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_addic(SIMM(ctx->opcode));
-    gen_op_set_Rc0();
+    if (likely(simm != 0))
+        gen_op_addic(SIMM(ctx->opcode));
     gen_op_store_T0_gpr(rD(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 /* addis */
 GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int32_t simm = SIMM(ctx->opcode);
+    target_long simm = SIMM(ctx->opcode);
 
     if (rA(ctx->opcode) == 0) {
+        /* lis case */
         gen_op_set_T0(simm << 16);
     } else {
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_addi(simm << 16);
+        if (likely(simm != 0))
+            gen_op_addi(simm << 16);
     }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
@@ -543,9 +586,9 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER)                  \
     gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 #define GEN_LOGICAL2(name, opc)                                               \
 __GEN_LOGICAL2(name, 0x1C, opc)
@@ -555,9 +598,9 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER)                   \
 {                                                                             \
     gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 /* and & and. */
@@ -568,17 +611,17 @@ GEN_LOGICAL2(andc, 0x01);
 GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_andi_(UIMM(ctx->opcode));
-    gen_op_set_Rc0();
+    gen_op_andi_T0(UIMM(ctx->opcode));
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 /* andis. */
 GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_andi_(UIMM(ctx->opcode) << 16);
-    gen_op_set_Rc0();
+    gen_op_andi_T0(UIMM(ctx->opcode) << 16);
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 
 /* cntlzw */
@@ -597,15 +640,25 @@ GEN_LOGICAL2(nor, 0x03);
 /* or & or. */
 GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
 {
-    gen_op_load_gpr_T0(rS(ctx->opcode));
-    /* Optimisation for mr case */
-    if (rS(ctx->opcode) != rB(ctx->opcode)) {
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_or();
+    int rs, ra, rb;
+
+    rs = rS(ctx->opcode);
+    ra = rA(ctx->opcode);
+    rb = rB(ctx->opcode);
+    /* Optimisation for mr. ri case */
+    if (rs != ra || rs != rb) {
+        gen_op_load_gpr_T0(rs);
+        if (rs != rb) {
+            gen_op_load_gpr_T1(rb);
+            gen_op_or();
+        }
+        gen_op_store_T0_gpr(ra);
+        if (unlikely(Rc(ctx->opcode) != 0))
+            gen_set_Rc0(ctx);
+    } else if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_gpr_T0(rs);
+        gen_set_Rc0(ctx);
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
-    gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
 /* orc & orc. */
@@ -619,67 +672,68 @@ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
         gen_op_load_gpr_T1(rB(ctx->opcode));
         gen_op_xor();
     } else {
-        gen_op_set_T0(0);
+        gen_op_reset_T0();
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* ori */
 GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
+        /* XXX: should handle special NOPs for POWER series */
         return;
-        }
-        gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (likely(uimm != 0))
         gen_op_ori(uimm);
-        gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 /* oris */
 GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
         return;
-        }
-        gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (likely(uimm != 0))
         gen_op_ori(uimm << 16);
-        gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 /* xori */
 GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
-    gen_op_xori(uimm);
+    if (likely(uimm != 0))
+        gen_op_xori(uimm);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
 /* xoris */
 GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
-    gen_op_xori(uimm << 16);
+    if (likely(uimm != 0))
+        gen_op_xori(uimm << 16);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
@@ -687,16 +741,42 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 /* rlwimi & rlwimi. */
 GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t mb, me;
+    target_ulong mask;
+    uint32_t mb, me, sh;
+    int n;
 
     mb = MB(ctx->opcode);
     me = ME(ctx->opcode);
+    sh = SH(ctx->opcode);
+    n = me + 1 - mb;
+    if (likely(sh == 0)) {
+        if (likely(mb == 0 && me == 31)) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            goto do_store;
+        } else if (likely(mb == 31 && me == 0)) {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+            goto do_store;
+        }
+        gen_op_load_gpr_T0(rS(ctx->opcode));
+        gen_op_load_gpr_T1(rA(ctx->opcode));
+        goto do_mask;
+    }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rA(ctx->opcode));
-    gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
+    gen_op_rotli32_T0(SH(ctx->opcode));
+ do_mask:
+#if defined(TARGET_PPC64)
+    mb += 32;
+    me += 32;
+#endif
+    mask = MASK(mb, me);
+    gen_op_andi_T0(mask);
+    gen_op_andi_T1(~mask);
+    gen_op_or();
+ do_store:
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* rlwinm & rlwinm. */
 GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -707,35 +787,34 @@ 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;
-#endif
+    if (likely(sh == 0)) {
+        goto do_mask;
+    }
+    if (likely(mb == 0)) {
+        if (likely(me == 31)) {
+            gen_op_rotli32_T0(sh);
+            goto do_store;
+        } else if (likely(me == (31 - sh))) {
+            gen_op_sli_T0(sh);
+            goto do_store;
         }
-    } else if (me == 31) {
-#if 0
-        if (sh == (32 - mb)) {
-            gen_op_srwi(mb);
-            goto store;
+    } else if (likely(me == 31)) {
+        if (likely(sh == (32 - mb))) {
+            gen_op_srli_T0(mb);
+            goto do_store;
         }
-#endif
     }
-    gen_op_rlwinm(sh, MASK(mb, me));
-store:
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
+    gen_op_rotli32_T0(sh);
+ do_mask:
+#if defined(TARGET_PPC64)
+    mb += 32;
+    me += 32;
+#endif
+    gen_op_andi_T0(MASK(mb, me));
+ do_store:
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* rlwnm & rlwnm. */
 GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -746,15 +825,17 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
     me = ME(ctx->opcode);
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
-    if (mb == 0 && me == 31) {
-        gen_op_rotl();
-    } else
-    {
-        gen_op_rlwnm(MASK(mb, me));
+    gen_op_rotl32_T0_T1();
+    if (unlikely(mb != 0 || me != 31)) {
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        gen_op_andi_T0(MASK(mb, me));
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 
 /***                             Integer shift                             ***/
@@ -767,10 +848,10 @@ 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();
+        gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* srw & srw. */
 __GEN_LOGICAL2(srw, 0x18, 0x10);
@@ -779,7 +860,7 @@ __GEN_LOGICAL2(srw, 0x18, 0x10);
 #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat)                           \
 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT)                   \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
@@ -792,7 +873,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT)                   \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
@@ -803,7 +884,7 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
 #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
@@ -815,7 +896,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AB(name, op2, inval)                                        \
@@ -825,7 +906,7 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
 #define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
@@ -837,7 +918,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AC(name, op2, inval)                                        \
@@ -847,7 +928,7 @@ _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) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
@@ -855,14 +936,14 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT)                   \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
 #define GEN_FLOAT_BS(name, op1, op2)                                          \
 GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                   \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
@@ -870,7 +951,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                   \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
@@ -881,13 +962,13 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0);
 /* fmul - fmuls */
 GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
 
-/* fres */
+/* fres */ /* XXX: not in 601 */
 GEN_FLOAT_BS(res, 0x3B, 0x18);
 
-/* frsqrte */
+/* frsqrte */ /* XXX: not in 601 */
 GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
 
-/* fsel */
+/* fsel */ /* XXX: not in 601 */
 _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
 /* fsub - fsubs */
 GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
@@ -895,7 +976,7 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
 /* fsqrt */
 GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -903,13 +984,13 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_fsqrt();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -918,7 +999,7 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
     gen_op_fsqrt();
     gen_op_frsp();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -942,9 +1023,9 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00);
 
 /***                         Floating-Point compare                        ***/
 /* fcmpo */
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -956,9 +1037,9 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
 }
 
 /* fcmpu */
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -976,14 +1057,14 @@ GEN_FLOAT_B(abs, 0x08, 0x08);
 /* fmr  - fmr. */
 GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!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));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -996,7 +1077,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01);
 /* mcrfs */
 GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -1008,13 +1089,13 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 /* mffs */
 GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!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))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -1023,15 +1104,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
     
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!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)));
+    gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
     gen_op_store_T0_fpscr(crb);
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -1040,7 +1121,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
     
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
@@ -1048,35 +1129,70 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
     gen_op_load_fpscr_T0(crb);
     gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
     gen_op_store_T0_fpscr(crb);
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /* mtfsf */
 GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!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))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /* mtfsfi */
 GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!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))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
+/***                           Addressing modes                            ***/
+/* Register indirect with immediate index : EA = (rA|0) + SIMM */
+static inline void gen_addr_imm_index (DisasContext *ctx)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        gen_op_set_T0(simm);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        if (likely(simm != 0))
+            gen_op_addi(simm);
+    }
+}
+
+static inline void gen_addr_reg_index (DisasContext *ctx)
+{
+    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();
+    }
+}
+
+static inline void gen_addr_register (DisasContext *ctx)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_op_reset_T0();
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+}
+
 /***                             Integer load                              ***/
 #define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
 #if defined(CONFIG_USER_ONLY)
@@ -1118,14 +1234,7 @@ static GenOpFunc *gen_op_st##width[] = {                                      \
 #define GEN_LD(width, opc)                                                    \
 GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
 }
@@ -1133,15 +1242,12 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
 #define GEN_LDU(width, opc)                                                   \
 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)) {                                 \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    gen_addr_imm_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
@@ -1150,14 +1256,12 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
 #define GEN_LDUX(width, opc)                                                  \
 GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
 {                                                                             \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
@@ -1166,13 +1270,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
 #define GEN_LDX(width, opc2, opc3)                                            \
 GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)           \
 {                                                                             \
-    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();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
 }
@@ -1197,14 +1295,7 @@ GEN_LDS(wz, 0x00);
 #define GEN_ST(width, opc)                                                    \
 GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
 }
@@ -1212,14 +1303,11 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
 #define GEN_STU(width, opc)                                                   \
 GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    gen_addr_imm_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
@@ -1228,13 +1316,11 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
 #define GEN_STUX(width, opc)                                                  \
 GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
 {                                                                             \
-    if (rA(ctx->opcode) == 0) {                                               \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
@@ -1243,13 +1329,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
 #define GEN_STX(width, opc2, opc3)                                            \
 GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)          \
 {                                                                             \
-    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();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
 }
@@ -1311,30 +1391,18 @@ static GenOpFunc1 *gen_op_stmw[] = {
 /* lmw */
 GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int simm = SIMM(ctx->opcode);
-
-    if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm);
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        if (simm != 0)
-            gen_op_addi(simm);
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
     op_ldstm(lmw, rD(ctx->opcode));
 }
 
 /* stmw */
 GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int simm = SIMM(ctx->opcode);
-
-    if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm);
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        if (simm != 0)
-            gen_op_addi(simm);
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
     op_ldstm(stmw, rS(ctx->opcode));
 }
 
@@ -1391,19 +1459,16 @@ 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)) {
+    if (unlikely(((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); 
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_register(ctx);
+    gen_op_set_T1(nb);
     op_ldsts(lswi, start);
 }
 
@@ -1413,17 +1478,13 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
     int ra = rA(ctx->opcode);
     int rb = rB(ctx->opcode);
 
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
     if (ra == 0) {
-        gen_op_load_gpr_T0(rb);
         ra = rb;
-    } else {
-        gen_op_load_gpr_T0(ra);
-        gen_op_load_gpr_T1(rb);
-        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);
 }
 
@@ -1432,46 +1493,33 @@ 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));
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_register(ctx);
     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));
 }
 
 /* stswx */
 GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
 {
-    int ra = rA(ctx->opcode);
-
-    if (ra == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-        ra = rB(ctx->opcode);
-    } else {
-        gen_op_load_gpr_T0(ra);
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        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); 
+    gen_op_update_nip(ctx->nip - 4); 
+    gen_addr_reg_index(ctx);
+    gen_op_load_xer_bc();
     op_ldsts(stsw, rS(ctx->opcode));
 }
 
 /***                        Memory synchronisation                         ***/
 /* eieio */
-GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
 {
 }
 
 /* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
 {
 }
 
@@ -1502,15 +1550,9 @@ static GenOpFunc *gen_op_stwcx[] = {
 #endif
 
 /* lwarx */
-GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
 {
-    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();
-    }
+    gen_addr_reg_index(ctx);
     op_lwarx();
     gen_op_store_T1_gpr(rD(ctx->opcode));
 }
@@ -1518,19 +1560,13 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
 /* stwcx. */
 GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
 {
-        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();
-        }
+    gen_addr_reg_index(ctx);
     gen_op_load_gpr_T1(rS(ctx->opcode));
     op_stwcx();
 }
 
 /* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
 {
 }
 
@@ -1538,79 +1574,59 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
 #define GEN_LDF(width, opc)                                                   \
 GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                 \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
 }
 
 #define GEN_LDUF(width, opc)                                                  \
 GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)              \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    gen_addr_imm_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
 #define GEN_LDUXF(width, opc)                                                 \
 GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)             \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
 #define GEN_LDXF(width, opc2, opc3)                                           \
 GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)             \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!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 {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
 }
 
 #define GEN_LDFS(width, op)                                                   \
@@ -1629,38 +1645,28 @@ GEN_LDFS(fs, 0x10);
 #define GEN_STF(width, opc)                                                   \
 GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_imm_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
 }
 
 #define GEN_STUF(width, opc)                                                  \
 GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)             \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_imm_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
@@ -1668,18 +1674,16 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)             \
 #define GEN_STUXF(width, opc)                                                 \
 GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
         RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
         RET_INVAL(ctx);                                                       \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
@@ -1687,18 +1691,12 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
 #define GEN_STXF(width, opc2, opc3)                                           \
 GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)            \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
+    if (unlikely(!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 {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
 }
 
@@ -1718,10 +1716,12 @@ GEN_STFS(fs, 0x14);
 /* stfiwx */
 GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
+    if (unlikely(!ctx->fpu_enabled)) {
         RET_EXCP(ctx, EXCP_NO_FP, 0);
         return;
     }
+    gen_addr_reg_index(ctx);
+    /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
     RET_INVAL(ctx);
 }
 
@@ -1745,9 +1745,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
     } else {
         gen_op_set_T1(dest);
         gen_op_b_T1();
+        gen_op_reset_T0();
         if (ctx->singlestep_enabled)
             gen_op_debug();
-        gen_op_set_T0(0);
         gen_op_exit_tb();
     }
 }
@@ -1755,12 +1755,15 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
 /* b ba bl bla */
 GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
-    uint32_t li, target;
+    target_ulong li, target;
 
     /* sign extend LI */
-    li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
-
-    if (AA(ctx->opcode) == 0)
+#if defined(TARGET_PPC64)
+    li = ((target_long)LI(ctx->opcode) << 38) >> 38;
+#else
+    li = ((target_long)LI(ctx->opcode) << 6) >> 6;
+#endif
+    if (likely(AA(ctx->opcode) == 0))
         target = ctx->nip + li - 4;
     else
         target = li;
@@ -1777,18 +1780,18 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 
 static inline void gen_bcond(DisasContext *ctx, int type) 
 {                                                                             
-    uint32_t target = 0;
+    target_ulong target = 0;
+    target_ulong li;
     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) {
+        li = (target_long)((int16_t)(BD(ctx->opcode)));
+        if (likely(AA(ctx->opcode) == 0)) {
             target = ctx->nip + li - 4;
         } else {
             target = li;
@@ -1821,6 +1824,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
                 gen_goto_tb(ctx, 0, target);
             } else {
                 gen_op_b_T1();
+                gen_op_reset_T0();
             }
             goto no_test;
         }
@@ -1865,8 +1869,12 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         gen_goto_tb(ctx, 1, ctx->nip);
     } else {
         gen_op_btest_T1(ctx->nip);
+        gen_op_reset_T0();
     }
  no_test:
+    if (ctx->singlestep_enabled)
+        gen_op_debug();
+    gen_op_exit_tb();
     ctx->exception = EXCP_BRANCH;                                             
 }
 
@@ -1901,21 +1909,21 @@ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                 \
 }
 
 /* crand */
-GEN_CRLOGIC(and, 0x08)
+GEN_CRLOGIC(and, 0x08);
 /* crandc */
-GEN_CRLOGIC(andc, 0x04)
+GEN_CRLOGIC(andc, 0x04);
 /* creqv */
-GEN_CRLOGIC(eqv, 0x09)
+GEN_CRLOGIC(eqv, 0x09);
 /* crnand */
-GEN_CRLOGIC(nand, 0x07)
+GEN_CRLOGIC(nand, 0x07);
 /* crnor */
-GEN_CRLOGIC(nor, 0x01)
+GEN_CRLOGIC(nor, 0x01);
 /* cror */
-GEN_CRLOGIC(or, 0x0E)
+GEN_CRLOGIC(or, 0x0E);
 /* crorc */
-GEN_CRLOGIC(orc, 0x0D)
+GEN_CRLOGIC(orc, 0x0D);
 /* crxor */
-GEN_CRLOGIC(xor, 0x06)
+GEN_CRLOGIC(xor, 0x06);
 /* mcrf */
 GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
 {
@@ -1925,13 +1933,13 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
 
 /***                           System linkage                              ***/
 /* rfi (supervisor only) */
-GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
+GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
 #else
     /* Restore CPU state */
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVOPC(ctx);
         return;
     }
@@ -1952,7 +1960,7 @@ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
 
 /***                                Trap                                   ***/
 /* tw */
-GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
+GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
@@ -1965,39 +1973,11 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
 GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
-#if 0
-    printf("%s: param=0x%04x T0=0x%04x\n", __func__,
-           SIMM(ctx->opcode), TO(ctx->opcode));
-#endif
-    gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
+    gen_op_set_T1(SIMM(ctx->opcode));
+    gen_op_tw(TO(ctx->opcode));
 }
 
 /***                          Processor control                            ***/
-static inline int check_spr_access (int spr, int rw, int supervisor)
-{
-    uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
-
-#if 0
-    if (spr != LR && spr != CTR) {
-    if (loglevel > 0) {
-        fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
-                SPR_ENCODE(spr), supervisor, rw, rights,
-                (rights >> ((2 * supervisor) + rw)) & 1);
-    } else {
-        printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
-               SPR_ENCODE(spr), supervisor, rw, rights,
-               (rights >> ((2 * supervisor) + rw)) & 1);
-    }
-    }
-#endif
-    if (rights == 0)
-        return -1;
-    rights = rights >> (2 * supervisor);
-    rights = rights >> rw;
-
-    return rights & 1;
-}
-
 /* mcrxr */
 GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
 {
@@ -2007,9 +1987,22 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
 }
 
 /* mfcr */
-GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
 {
-    gen_op_load_cr();
+#if 0 // XXX: to be tested
+    uint32_t crm, crn;
+    
+    if (likely(ctx->opcode & 0x00100000)) {
+        crm = CRM(ctx->opcode);
+        if (likely((crm ^ (crm - 1)) == 0)) {
+            crn = ffs(crm);
+            gen_op_load_cro(7 - crn);
+        }
+    } else
+#endif
+        {
+            gen_op_load_cr();
+        }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
@@ -2019,7 +2012,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVREG(ctx);
         return;
     }
@@ -2051,8 +2044,8 @@ static inline void gen_op_mfspr (DisasContext *ctx)
     else
 #endif
         read_cb = ctx->spr_cb[sprn].uea_read;
-    if (read_cb != NULL) {
-        if (read_cb != SPR_NOACCESS) {
+    if (likely(read_cb != NULL)) {
+        if (likely(read_cb != SPR_NOACCESS)) {
             (*read_cb)(ctx, sprn);
             gen_op_store_T0_gpr(rD(ctx->opcode));
         } else {
@@ -2062,7 +2055,7 @@ static inline void gen_op_mfspr (DisasContext *ctx)
                         sprn, sprn);
             }
             printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
-        RET_PRIVREG(ctx);
+            RET_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
@@ -2078,7 +2071,7 @@ static inline void gen_op_mfspr (DisasContext *ctx)
 GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
 {
     gen_op_mfspr(ctx);
-    }
+}
 
 /* mftb */
 GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
@@ -2087,11 +2080,20 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
 }
 
 /* mtcrf */
-/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
 GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
 {
+    uint32_t crm, crn;
+    
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_store_cr(CRM(ctx->opcode));
+    crm = CRM(ctx->opcode);
+    if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
+        crn = ffs(crm);
+        gen_op_srli_T0(crn * 4);
+        gen_op_andi_T0(0xF);
+        gen_op_store_cro(7 - crn);
+    } else {
+        gen_op_store_cr(crm);
+    }
 }
 
 /* mtmsr */
@@ -2100,7 +2102,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVREG(ctx);
         return;
     }
@@ -2124,8 +2126,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
     else
 #endif
         write_cb = ctx->spr_cb[sprn].uea_write;
-    if (write_cb != NULL) {
-        if (write_cb != SPR_NOACCESS) {
+    if (likely(write_cb != NULL)) {
+        if (likely(write_cb != SPR_NOACCESS)) {
             gen_op_load_gpr_T0(rS(ctx->opcode));
             (*write_cb)(ctx, sprn);
         } else {
@@ -2135,8 +2137,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
                         sprn, sprn);
             }
             printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
-        RET_PRIVREG(ctx);
-    }
+            RET_PRIVREG(ctx);
+        }
     } else {
         /* Not defined */
         if (loglevel) {
@@ -2156,13 +2158,7 @@ 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();
-    }
+    gen_addr_reg_index(ctx);
     op_ldst(lbz);
 }
 
@@ -2172,18 +2168,13 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!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);
+    gen_addr_reg_index(ctx);
+    /* XXX: specification says this should be treated as a store by the MMU */
+    //op_ldst(lbz);
     op_ldst(stb);
 #endif
 }
@@ -2191,31 +2182,35 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
 /* 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();
-    }
+    /* XXX: specification say this is treated as a load by the MMU */
+    gen_addr_reg_index(ctx);
     op_ldst(lbz);
 }
 
 /* dcbt */
 GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
 {
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /* dcbtst */
 GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
 {
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /* dcbz */
+#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
 #if defined(CONFIG_USER_ONLY)
-#define op_dcbz() gen_op_dcbz_raw()
+static GenOpFunc *gen_op_dcbz[] = {
+    &gen_op_dcbz_raw,
+    &gen_op_dcbz_raw,
+};
 #else
-#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
 static GenOpFunc *gen_op_dcbz[] = {
     &gen_op_dcbz_user,
     &gen_op_dcbz_user,
@@ -2226,13 +2221,7 @@ static GenOpFunc *gen_op_dcbz[] = {
 
 GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 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();
-    }
+    gen_addr_reg_index(ctx);
     op_dcbz();
     gen_op_check_reservation();
 }
@@ -2240,14 +2229,11 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
 /* icbi */
 GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 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();
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
     gen_op_icbi();
+    RET_STOP(ctx);
 }
 
 /* Optional: */
@@ -2264,11 +2250,12 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVREG(ctx);
         return;
     }
-    gen_op_load_sr(SR(ctx->opcode));
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_load_sr();
     gen_op_store_T0_gpr(rD(ctx->opcode));
 #endif
 }
@@ -2279,12 +2266,13 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVREG(ctx);
         return;
     }
     gen_op_load_gpr_T1(rB(ctx->opcode));
-    gen_op_load_srin();
+    gen_op_srli_T1(28);
+    gen_op_load_sr();
     gen_op_store_T0_gpr(rD(ctx->opcode));
 #endif
 }
@@ -2295,12 +2283,13 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVREG(ctx);
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_store_sr(SR(ctx->opcode));
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_store_sr();
     RET_STOP(ctx);
 #endif
 }
@@ -2311,13 +2300,14 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         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_srli_T1(28);
+    gen_op_store_sr();
     RET_STOP(ctx);
 #endif
 }
@@ -2330,7 +2320,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         if (loglevel)
             fprintf(logfile, "%s: ! supervisor\n", __func__);
         RET_PRIVOPC(ctx);
@@ -2342,12 +2332,12 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
 }
 
 /* tlbie */
-GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVOPC(ctx);
         return;
     }
@@ -2358,12 +2348,12 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
 }
 
 /* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
+    if (unlikely(!ctx->supervisor)) {
         RET_PRIVOPC(ctx);
         return;
     }
@@ -2406,30 +2396,1149 @@ static GenOpFunc *gen_op_ecowx[] = {
 GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
 {
     /* Should check EAR[E] & alignment ! */
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
+    gen_addr_reg_index(ctx);
+    op_eciwx();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* ecowx */
+GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
+{
+    /* Should check EAR[E] & alignment ! */
+    gen_addr_reg_index(ctx);
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    op_ecowx();
+}
+
+/* PowerPC 601 specific instructions */
+/* abs - abs. */
+GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_abs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* abso - abso. */
+GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_abso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* clcs */
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_clcs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* div - div. */
+GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_div();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divo - divo. */
+GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divs - divs. */
+GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divso - divso. */
+GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* doz - doz. */
+GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_doz();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* dozo - dozo. */
+GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_dozo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* dozi */
+GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_set_T1(SIMM(ctx->opcode));
+    gen_op_POWER_doz();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* As lscbx load from memory byte after byte, it's always endian safe */
+#define op_POWER_lscbx(start, ra, rb) \
+(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+    &gen_op_POWER_lscbx_raw,
+    &gen_op_POWER_lscbx_raw,
+};
+#else
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+    &gen_op_POWER_lscbx_user,
+    &gen_op_POWER_lscbx_user,
+    &gen_op_POWER_lscbx_kernel,
+    &gen_op_POWER_lscbx_kernel,
+};
+#endif
+
+/* lscbx - lscbx. */
+GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
+{
+    int ra = rA(ctx->opcode);
+    int rb = rB(ctx->opcode);
+
+    gen_addr_reg_index(ctx);
+    if (ra == 0) {
+        ra = rb;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_op_load_xer_bc();
+    gen_op_load_xer_cmp();
+    op_POWER_lscbx(rD(ctx->opcode), ra, rb);
+    gen_op_store_xer_bc();
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* maskg - maskg. */
+GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_maskg();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* maskir - maskir. */
+GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_maskir();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* mul - mul. */
+GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_mul();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* mulo - mulo. */
+GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_mulo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* nabs - nabs. */
+GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_nabs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* nabso - nabso. */
+GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_nabso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* rlmi - rlmi. */
+GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+    uint32_t mb, me;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rA(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* rrib - rrib. */
+GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rA(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_rrib();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sle - sle. */
+GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sle();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sleq - sleq. */
+GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sleq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sliq - sliq. */
+GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sle();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* slliq - slliq. */
+GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sleq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sllq - sllq. */
+GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sllq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* slq - slq. */
+GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_slq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sraiq -sraiq. */
+GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sraq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sraq - sraq. */
+GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sraq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sre - sre. */
+GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sre();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srea - srea. */
+GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srea();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sreq */
+GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sreq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sriq */
+GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_srq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srliq */
+GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_srlq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srlq */
+GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srlq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srq */
+GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* PowerPC 602 specific instructions */
+/* dsa  */
+GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
+{
+    /* XXX: TODO */
+    RET_INVAL(ctx);
+}
+
+/* esa */
+GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
+{
+    /* XXX: TODO */
+    RET_INVAL(ctx);
+}
+
+/* mfrom */
+GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_602_mfrom();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* 602 - 603 - G2 TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_6xx_tlbld();
+    RET_STOP(ctx);
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_6xx_tlbli();
+    RET_STOP(ctx);
+#endif
+}
+
+/* POWER instructions not in PowerPC 601 */
+/* clf */
+GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
+{
+    /* Cache line flush: implemented as no-op */
+}
+
+/* cli */
+GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
+{
+    /* Cache line invalidate: priviledged and treated as no-op */
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+#endif
+}
+
+/* dclst */
+GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
+{
+    /* Data cache line store: treated as no-op */
+}
+
+GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+
+    gen_addr_reg_index(ctx);
+    gen_op_POWER_mfsri();
+    gen_op_store_T0_gpr(rd);
+    if (ra != 0 && ra != rd)
+        gen_op_store_T1_gpr(ra);
+#endif
+}
+
+GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    gen_op_POWER_rac();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_POWER_rfsvc();
+    RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* svc is not implemented for now */
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
+#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+    &gen_op_POWER2_lfq_le_raw,
+    &gen_op_POWER2_lfq_raw,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+    &gen_op_POWER2_stfq_le_raw,
+    &gen_op_POWER2_stfq_raw,
+};
+#else
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+    &gen_op_POWER2_lfq_le_user,
+    &gen_op_POWER2_lfq_user,
+    &gen_op_POWER2_lfq_le_kernel,
+    &gen_op_POWER2_lfq_kernel,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+    &gen_op_POWER2_stfq_le_user,
+    &gen_op_POWER2_stfq_user,
+    &gen_op_POWER2_stfq_le_kernel,
+    &gen_op_POWER2_stfq_kernel,
+};
+#endif
+
+/* lfq */
+GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* lfqu */
+GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* lfqux */
+GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* lfqx */
+GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* stfq */
+GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+}
+
+/* stfqu */
+GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_imm_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* stfqux */
+GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* stfqx */
+GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_op_update_nip(ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+}
+
+/* BookE specific instructions */
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
+{
+    /* XXX: TODO */
+    RET_INVAL(ctx);
+}
+
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    /* Use the same micro-ops as for tlbie */
+    gen_op_tlbie();
+    RET_STOP(ctx);
+#endif
+}
+
+/* All 405 MAC instructions are translated here */
+static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
+                                         int ra, int rb, int rt, int Rc)
+{
+    gen_op_load_gpr_T0(ra);
+    gen_op_load_gpr_T1(rb);
+    switch (opc3 & 0x0D) {
+    case 0x05:
+        /* macchw    - macchw.    - macchwo   - macchwo.   */
+        /* macchws   - macchws.   - macchwso  - macchwso.  */
+        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
+        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
+        /* mulchw - mulchw. */
+        gen_op_405_mulchw();
+        break;
+    case 0x04:
+        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
+        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
+        /* mulchwu - mulchwu. */
+        gen_op_405_mulchwu();
+        break;
+    case 0x01:
+        /* machhw    - machhw.    - machhwo   - machhwo.   */
+        /* machhws   - machhws.   - machhwso  - machhwso.  */
+        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
+        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
+        /* mulhhw - mulhhw. */
+        gen_op_405_mulhhw();
+        break;
+    case 0x00:
+        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
+        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
+        /* mulhhwu - mulhhwu. */
+        gen_op_405_mulhhwu();
+        break;
+    case 0x0D:
+        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
+        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
+        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
+        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
+        /* mullhw - mullhw. */
+        gen_op_405_mullhw();
+        break;
+    case 0x0C:
+        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
+        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
+        /* mullhwu - mullhwu. */
+        gen_op_405_mullhwu();
+        break;
+    }
+    if (opc2 & 0x02) {
+        /* nmultiply-and-accumulate (0x0E) */
+        gen_op_neg();
+    }
+    if (opc2 & 0x04) {
+        /* (n)multiply-and-accumulate (0x0C - 0x0E) */
+        gen_op_load_gpr_T2(rt);
+        gen_op_move_T1_T0();
+        gen_op_405_add_T0_T2();
+    }
+    if (opc3 & 0x10) {
+        /* Check overflow */
+        if (opc3 & 0x01)
+            gen_op_405_check_ov();
+        else
+            gen_op_405_check_ovu();
+    }
+    if (opc3 & 0x02) {
+        /* Saturate */
+        if (opc3 & 0x01)
+            gen_op_405_check_sat();
+        else
+            gen_op_405_check_satu();
+    }
+    gen_op_store_T0_gpr(rt);
+    if (unlikely(Rc) != 0) {
+        /* Update Rc0 */
+        gen_set_Rc0(ctx);
+    }
+}
+
+#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
+{                                                                             \
+    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
+                         rD(ctx->opcode), Rc(ctx->opcode));                   \
+}
+
+/* macchw    - macchw.    */
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
+/* macchwo   - macchwo.   */
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
+/* macchws   - macchws.   */
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
+/* macchwso  - macchwso.  */
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
+/* macchwsu  - macchwsu.  */
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
+/* macchwsuo - macchwsuo. */
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
+/* macchwu   - macchwu.   */
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
+/* macchwuo  - macchwuo.  */
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
+/* machhw    - machhw.    */
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
+/* machhwo   - machhwo.   */
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
+/* machhws   - machhws.   */
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
+/* machhwso  - machhwso.  */
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
+/* machhwsu  - machhwsu.  */
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
+/* machhwsuo - machhwsuo. */
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
+/* machhwu   - machhwu.   */
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
+/* machhwuo  - machhwuo.  */
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
+/* maclhw    - maclhw.    */
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
+/* maclhwo   - maclhwo.   */
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
+/* maclhws   - maclhws.   */
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
+/* maclhwso  - maclhwso.  */
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
+/* maclhwu   - maclhwu.   */
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
+/* maclhwuo  - maclhwuo.  */
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
+/* maclhwsu  - maclhwsu.  */
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
+/* maclhwsuo - maclhwsuo. */
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
+/* nmacchw   - nmacchw.   */
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
+/* nmacchwo  - nmacchwo.  */
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
+/* nmacchws  - nmacchws.  */
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
+/* nmacchwso - nmacchwso. */
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
+/* nmachhw   - nmachhw.   */
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
+/* nmachhwo  - nmachhwo.  */
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
+/* nmachhws  - nmachhws.  */
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
+/* nmachhwso - nmachhwso. */
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
+/* nmaclhw   - nmaclhw.   */
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
+/* nmaclhwo  - nmaclhwo.  */
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
+/* nmaclhws  - nmaclhws.  */
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
+/* nmaclhwso - nmaclhwso. */
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
+
+/* mulchw  - mulchw.  */
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
+/* mulchwu - mulchwu. */
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
+/* mulhhw  - mulhhw.  */
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
+/* mulhhwu - mulhhwu. */
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
+/* mullhw  - mullhw.  */
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
+/* mullhwu - mullhwu. */
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
+
+/* mfdcr */
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVREG(ctx);
+#else
+    uint32_t dcrn = SPR(ctx->opcode);
+
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVREG(ctx);
+        return;
+    }
+    gen_op_4xx_load_dcr(dcrn);
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtdcr */
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVREG(ctx);
+#else
+    uint32_t dcrn = SPR(ctx->opcode);
+
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_4xx_store_dcr(dcrn);
+#endif
+}
+
+/* dccci */
+GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* dcread */
+GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    op_ldst(lwz);
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* icbt */
+GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/* iccci */
+GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* icread */
+GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* rfci (supervisor only) */
+GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    /* Restore CPU state */
+    gen_op_4xx_rfci();
+    RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* tlbre */
+GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
+        gen_op_4xx_tlbre_hi();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_4xx_tlbre_lo();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    default:
+        RET_INVAL(ctx);
+        break;
     }
-    op_eciwx();
+#endif
+}
+
+/* tlbsx - tlbsx. */ /* Named tlbs in BookE */
+GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    if (Rc(ctx->opcode))
+        gen_op_4xx_tlbsx_();
+    else
+        gen_op_4xx_tlbsx();
     gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
 }
 
-/* ecowx */
-GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
+/* tlbwe */
+GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON)
 {
-    /* Should check EAR[E] & alignment ! */
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_4xx_tlbwe_hi();
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_4xx_tlbwe_lo();
+        break;
+    default:
+        RET_INVAL(ctx);
+        break;
     }
-    gen_op_load_gpr_T2(rS(ctx->opcode));
-    op_ecowx();
+#endif
+}
+
+/* wrtee */
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rD(ctx->opcode));
+    gen_op_4xx_wrte();
+    RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* wrteei */
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    RET_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        RET_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_set_T0(ctx->opcode & 0x00010000);
+    gen_op_4xx_wrte();
+    RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* PPC 440 specific instructions */
+/* dlmzb */
+GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_440_dlmzb();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_op_store_xer_bc();
+    if (Rc(ctx->opcode)) {
+        gen_op_440_dlmzb_update_Rc();
+        gen_op_store_T0_crf(0);
+    }
+}
+
+/* mbar replaces eieio on 440 */
+GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+}
+
+/* msync replaces sync on 440 */
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+}
+
+/* icbt */
+GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /* End opcode list */
@@ -2439,18 +3548,25 @@ GEN_OPCODE_MARK(end);
 
 /*****************************************************************************/
 /* Misc PowerPC helpers */
+static inline uint32_t load_xer (CPUState *env)
+{
+    return (xer_so << XER_SO) |
+        (xer_ov << XER_OV) |
+        (xer_ca << XER_CA) |
+        (xer_bc << XER_BC) |
+        (xer_cmp << XER_CMP);
+}
+
 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 "%016" PRIx64
 #define RGPL  4
 #define RFPL  4
 #else
 #define FILL "        "
-#define REGX "%08" PRIx64
 #define RGPL  8
 #define RFPL  4
 #endif
@@ -2459,30 +3575,38 @@ void cpu_dump_state(CPUState *env, FILE *f,
 
     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++) {
+    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      TB %08x %08x "
+#if !defined(CONFIG_USER_ONLY)
+                "DECR %08x"
+#endif
+                "\n",
+                do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env),
+                cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+                , cpu_ppc_load_decr(env)
+#endif
+                );
+    for (i = 0; i < 32; i++) {
         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");
-        }
+    }
     cpu_fprintf(f, "CR ");
-        for (i = 0; i < 8; i++)
+    for (i = 0; i < 8; i++)
         cpu_fprintf(f, "%01x", env->crf[i]);
     cpu_fprintf(f, "  [");
-        for (i = 0; i < 8; i++) {
-            char a = '-';
-            if (env->crf[i] & 0x08)
-                a = 'L';
-            else if (env->crf[i] & 0x04)
-                a = 'G';
-            else if (env->crf[i] & 0x02)
-                a = 'E';
+    for (i = 0; i < 8; i++) {
+        char a = '-';
+        if (env->crf[i] & 0x08)
+            a = 'L';
+        else if (env->crf[i] & 0x04)
+            a = 'G';
+        else if (env->crf[i] & 0x02)
+            a = 'E';
         cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
-        }
+    }
     cpu_fprintf(f, " ]             " FILL "RES " REGX "\n", env->reserve);
     for (i = 0; i < 32; i++) {
         if ((i & (RFPL - 1)) == 0)
@@ -2501,6 +3625,53 @@ void cpu_dump_state(CPUState *env, FILE *f,
 #undef FILL
 }
 
+void cpu_dump_statistics (CPUState *env, FILE*f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags)
+{
+#if defined(DO_PPC_STATISTICS)
+    opc_handler_t **t1, **t2, **t3, *handler;
+    int op1, op2, op3;
+
+    t1 = env->opcodes;
+    for (op1 = 0; op1 < 64; op1++) {
+        handler = t1[op1];
+        if (is_indirect_opcode(handler)) {
+            t2 = ind_table(handler);
+            for (op2 = 0; op2 < 32; op2++) {
+                handler = t2[op2];
+                if (is_indirect_opcode(handler)) {
+                    t3 = ind_table(handler);
+                    for (op3 = 0; op3 < 32; op3++) {
+                        handler = t3[op3];
+                        if (handler->count == 0)
+                            continue;
+                        cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
+                                    "%016llx %lld\n",
+                                    op1, op2, op3, op1, (op3 << 5) | op2,
+                                    handler->oname,
+                                    handler->count, handler->count);
+                    }
+                } else {
+                    if (handler->count == 0)
+                        continue;
+                    cpu_fprintf(f, "%02x %02x    (%02x %04d) %16s: "
+                                "%016llx %lld\n",
+                                op1, op2, op1, op2, handler->oname,
+                                handler->count, handler->count);
+                }
+            }
+        } else {
+            if (handler->count == 0)
+                continue;
+            cpu_fprintf(f, "%02x       (%02x     ) %16s: %016llx %lld\n",
+                        op1, op1, handler->oname,
+                        handler->count, handler->count);
+        }
+    }
+#endif
+}
+
 /*****************************************************************************/
 int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                                     int search_pc)
@@ -2534,8 +3705,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
 #endif
     /* Set env in case of segfault during code fetch */
     while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
-        if (env->nb_breakpoints > 0) {
-            for(j = 0; j < env->nb_breakpoints; j++) {
+        if (unlikely(env->nb_breakpoints > 0)) {
+            for (j = 0; j < env->nb_breakpoints; j++) {
                 if (env->breakpoints[j] == ctx.nip) {
                     gen_op_update_nip(ctx.nip); 
                     gen_op_debug();
@@ -2543,7 +3714,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                 }
             }
         }
-        if (search_pc) {
+        if (unlikely(search_pc)) {
             j = gen_opc_ptr - gen_opc_buf;
             if (lj < j) {
                 lj++;
@@ -2586,11 +3757,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             }
         }
         /* Is opcode *REALLY* valid ? */
-                if (handler->handler == &gen_invalid) {
+        if (unlikely(handler->handler == &gen_invalid)) {
             if (loglevel > 0) {
-                    fprintf(logfile, "invalid/unsupported opcode: "
+                fprintf(logfile, "invalid/unsupported opcode: "
                         "%02x - %02x - %02x (%08x) 0x%08x %d\n",
-                            opc1(ctx.opcode), opc2(ctx.opcode),
+                        opc1(ctx.opcode), opc2(ctx.opcode),
                         opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
             } else {
                 printf("invalid/unsupported opcode: "
@@ -2598,8 +3769,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                        opc1(ctx.opcode), opc2(ctx.opcode),
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
             }
-                } else {
-            if ((ctx.opcode & handler->inval) != 0) {
+        } else {
+            if (unlikely((ctx.opcode & handler->inval) != 0)) {
                 if (loglevel > 0) {
                     fprintf(logfile, "invalid bits: %08x for opcode: "
                             "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
@@ -2609,38 +3780,40 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
                 } else {
                     printf("invalid bits: %08x for opcode: "
                            "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
-                            ctx.opcode & handler->inval, opc1(ctx.opcode),
-                            opc2(ctx.opcode), opc3(ctx.opcode),
+                           ctx.opcode & handler->inval, opc1(ctx.opcode),
+                           opc2(ctx.opcode), opc3(ctx.opcode),
                            ctx.opcode, ctx.nip - 4);
-            }
+                }
                 RET_INVAL(ctxp);
                 break;
             }
         }
         (*(handler->handler))(&ctx);
+#if defined(DO_PPC_STATISTICS)
+        handler->count++;
+#endif
         /* Check trace mode exceptions */
-        if ((msr_be && ctx.exception == EXCP_BRANCH) ||
-            /* Check in single step trace mode
-             * we need to stop except if:
-             * - rfi, trap or syscall
-             * - first instruction of an exception handler
-             */
-            (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 (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
+                     /* Check in single step trace mode
+                      * we need to stop except if:
+                      * - rfi, trap or syscall
+                      * - first instruction of an exception handler
+                      */
+                     (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))) {
             RET_EXCP(ctxp, EXCP_TRACE, 0);
         }
-
         /* if we reach a page boundary or are single stepping, stop
          * generation
          */
-        if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
-            (env->singlestep_enabled)) {
+        if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+                     (env->singlestep_enabled))) {
             break;
-    }
+        }
 #if defined (DO_SINGLE_STEP)
         break;
 #endif
@@ -2648,28 +3821,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     if (ctx.exception == EXCP_NONE) {
         gen_goto_tb(&ctx, 0, ctx.nip);
     } else if (ctx.exception != EXCP_BRANCH) {
-        gen_op_set_T0(0);
+        gen_op_reset_T0();
+        /* Generate the return instruction */
+        gen_op_exit_tb();
     }
-#if 1
-    /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
-     *              do bad business and then qemu crashes !
-     */
-    gen_op_set_T0(0);
-#endif
-    /* Generate the return instruction */
-    gen_op_exit_tb();
     *gen_opc_ptr = INDEX_op_end;
-    if (search_pc) {
+    if (unlikely(search_pc)) {
         j = gen_opc_ptr - gen_opc_buf;
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
         tb->size = 0;
-#if 0
-        if (loglevel > 0) {
-            page_dump(logfile);
-        }
-#endif
     } else {
         tb->size = ctx.nip - pc_start;
     }
@@ -2679,8 +3841,10 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
         cpu_dump_state(env, logfile, fprintf, 0);
     }
     if (loglevel & CPU_LOG_TB_IN_ASM) {
+        int flags;
+        flags = msr_le;
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-       target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
+        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
         fprintf(logfile, "\n");
     }
     if (loglevel & CPU_LOG_TB_OP) {
index ddf0c91..d4159fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  PowerPC CPU initialization for qemu.
  * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -48,7 +48,7 @@ static void spr_write_generic (void *opaque, int sprn)
     gen_op_store_spr(sprn);
 }
 
-/* SPR common to all PPC */
+/* SPR common to all PowerPC */
 /* XER */
 static void spr_read_xer (void *opaque, int sprn)
 {
@@ -93,8 +93,9 @@ static void spr_read_ureg (void *opaque, int sprn)
     gen_op_load_spr(sprn + 0x10);
 }
 
-/* SPR common to all non-embedded PPC (ie not 4xx) */
+/* SPR common to all non-embedded PowerPC */
 /* DECR */
+#if !defined(CONFIG_USER_ONLY)
 static void spr_read_decr (void *opaque, int sprn)
 {
     gen_op_load_decr();
@@ -104,29 +105,33 @@ static void spr_write_decr (void *opaque, int sprn)
 {
     gen_op_store_decr();
 }
+#endif
 
-/* SPR common to all non-embedded PPC, except 601 */
+/* SPR common to all non-embedded PowerPC, except 601 */
 /* Time base */
 static void spr_read_tbl (void *opaque, int sprn)
 {
     gen_op_load_tbl();
 }
 
-static void spr_write_tbl (void *opaque, int sprn)
+static void spr_read_tbu (void *opaque, int sprn)
 {
-    gen_op_store_tbl();
+    gen_op_load_tbu();
 }
 
-static void spr_read_tbu (void *opaque, int sprn)
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_tbl (void *opaque, int sprn)
 {
-    gen_op_load_tbu();
+    gen_op_store_tbl();
 }
 
 static void spr_write_tbu (void *opaque, int sprn)
 {
     gen_op_store_tbu();
 }
+#endif
 
+#if !defined(CONFIG_USER_ONLY)
 /* IBAT0U...IBAT0U */
 /* IBAT0L...IBAT7L */
 static void spr_read_ibat (void *opaque, int sprn)
@@ -229,11 +234,129 @@ static void spr_write_sdr1 (void *opaque, int sprn)
     RET_STOP(ctx);
 }
 
+/* 64 bits PowerPC specific SPRs */
+/* ASR */
+#if defined(TARGET_PPC64)
+static void spr_read_asr (void *opaque, int sprn)
+{
+    gen_op_load_asr();
+}
+
+static void spr_write_asr (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_asr();
+    RET_STOP(ctx);
+}
+#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific registers */
+/* RTC */
+static void spr_read_601_rtcl (void *opaque, int sprn)
+{
+    gen_op_load_601_rtcl();
+}
+
+static void spr_read_601_rtcu (void *opaque, int sprn)
+{
+    gen_op_load_601_rtcu();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_601_rtcu (void *opaque, int sprn)
+{
+    gen_op_store_601_rtcu();
+}
+
+static void spr_write_601_rtcl (void *opaque, int sprn)
+{
+    gen_op_store_601_rtcl();
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_601_ubat (void *opaque, int sprn)
+{
+    gen_op_load_601_bat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_write_601_ubatu (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_601_ubatl (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2);
+    RET_STOP(ctx);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_40x_pit (void *opaque, int sprn)
+{
+    gen_op_load_40x_pit();
+}
+
+static void spr_write_40x_pit (void *opaque, int sprn)
+{
+    gen_op_store_40x_pit();
+}
+
+static void spr_write_booke_tcr (void *opaque, int sprn)
+{
+    gen_op_store_booke_tcr();
+}
+
+static void spr_write_booke_tsr (void *opaque, int sprn)
+{
+    gen_op_store_booke_tsr();
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_403_pbr (void *opaque, int sprn)
+{
+    gen_op_load_403_pb(sprn - SPR_403_PBL1);
+}
+
+static void spr_write_403_pbr (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_403_pb(sprn - SPR_403_PBL1);
+    RET_STOP(ctx);
+}
+
 static void spr_write_pir (void *opaque, int sprn)
 {
     gen_op_store_pir();
 }
+#endif
 
+#if defined(CONFIG_USER_ONLY)
+#define spr_register(env, num, name, uea_read, uea_write,                     \
+                     oea_read, oea_write, initial_value)                      \
+do {                                                                          \
+     _spr_register(env, num, name, uea_read, uea_write, initial_value);       \
+} while (0)
+static inline void _spr_register (CPUPPCState *env, int num,
+                                  const unsigned char *name,
+                                  void (*uea_read)(void *opaque, int sprn),
+                                  void (*uea_write)(void *opaque, int sprn),
+                                  target_ulong initial_value)
+#else
 static inline void spr_register (CPUPPCState *env, int num,
                                  const unsigned char *name,
                                  void (*uea_read)(void *opaque, int sprn),
@@ -241,25 +364,30 @@ static inline void spr_register (CPUPPCState *env, int num,
                                  void (*oea_read)(void *opaque, int sprn),
                                  void (*oea_write)(void *opaque, int sprn),
                                  target_ulong initial_value)
+#endif
 {
     ppc_spr_t *spr;
 
     spr = &env->spr_cb[num];
     if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
-        spr->uea_read != NULL || spr->uea_write != NULL ||
-        spr->oea_read != NULL || spr->oea_write != NULL) {
+#if !defined(CONFIG_USER_ONLY)
+        spr->oea_read != NULL || spr->oea_write != NULL ||
+#endif
+        spr->uea_read != NULL || spr->uea_write != NULL) {
         printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
         exit(1);
     }
 #if defined(PPC_DEBUG_SPR)
-    printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name,
-           (unsigned long long)initial_value);
+    printf("*** register spr %d (%03x) %s val " REGX "\n", num, num, name,
+           initial_value);
 #endif
     spr->name = name;
     spr->uea_read = uea_read;
     spr->uea_write = uea_write;
+#if !defined(CONFIG_USER_ONLY)
     spr->oea_read = oea_read;
     spr->oea_write = oea_write;
+#endif
     env->spr[num] = initial_value;
 }
 
@@ -493,6 +621,70 @@ static void gen_tbl (CPUPPCState *env)
                  0x00000000);
 }
 
+/* Softare table search registers */
+static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+    env->nb_tlb = nb_tlbs;
+    env->nb_ways = nb_ways;
+    env->id_tlbs = 1;
+    spr_register(env, SPR_DMISS, "DMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_DCMP, "DCMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH1, "HASH1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH2, "HASH2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_IMISS, "IMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_ICMP, "ICMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_RPA, "RPA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR common to MPC755 and G2 */
+static void gen_spr_G2_755 (CPUPPCState *env)
+{
+    /* SGPRs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
 /* SPR common to all 7xx PowerPC implementations */
 static void gen_spr_7xx (CPUPPCState *env)
 {
@@ -513,6 +705,11 @@ static void gen_spr_7xx (CPUPPCState *env)
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
     /* Performance monitors */
     /* XXX : not implemented */
     spr_register(env, SPR_MMCR0, "MMCR0",
@@ -669,151 +866,1366 @@ static void gen_spr_604 (CPUPPCState *env)
                  0x00000000);
 }
 
-// XXX: TODO (64 bits PPC sprs)
-/*
- * ASR => SPR 280 (64 bits)
- * FPECR => SPR 1022 (?)
- * VRSAVE => SPR 256 (Altivec)
- * SCOMC => SPR 276 (64 bits ?)
- * SCOMD => SPR 277 (64 bits ?)
- * HSPRG0 => SPR 304 (hypervisor)
- * HSPRG1 => SPR 305 (hypervisor)
- * HDEC => SPR 310 (hypervisor)
- * HIOR => SPR 311 (hypervisor)
- * RMOR => SPR 312 (970)
- * HRMOR => SPR 313 (hypervisor)
- * HSRR0 => SPR 314 (hypervisor)
- * HSRR1 => SPR 315 (hypervisor)
- * LPCR => SPR 316 (970)
- * LPIDR => SPR 317 (970)
- * ... and more (thermal management, performance counters, ...)
- */
-
-static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
+/* SPR specific to PowerPC 603 implementation */
+static void gen_spr_603 (CPUPPCState *env)
 {
-    /* Default MMU definitions */
-    env->nb_BATs = -1;
-    env->nb_tlb = 0;
-    env->nb_ways = 0;
-    /* XXX: missing:
-     * 32 bits PPC:
-     * - MPC5xx(x)
-     * - MPC8xx(x)
-     * - RCPU (MPC5xx)
-     */
-    spr_register(env, SPR_PVR, "PVR",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, SPR_NOACCESS,
-                 def->pvr);
-    switch (def->pvr & def->pvr_mask) {
-    case CPU_PPC_604:     /* PPC 604                       */
-    case CPU_PPC_604E:    /* PPC 604e                      */
-    case CPU_PPC_604R:    /* PPC 604r                      */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_604(env);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    case CPU_PPC_74x:     /* PPC 740 / 750                 */
-    case CPU_PPC_74xP:    /* PPC 740P / 750P               */
-    case CPU_PPC_750CXE:  /* IBM PPC 750cxe                */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_7xx(env);
-        /* XXX : not implemented */
-        spr_register(env, SPR_L2CR, "L2CR",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    case CPU_PPC_750FX:   /* IBM PPC 750 FX                */
-    case CPU_PPC_750GX:   /* IBM PPC 750 GX                */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
-        gen_high_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_7xx(env);
-        /* XXX : not implemented */
-        spr_register(env, SPR_L2CR, "L2CR",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
                  SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_750_HID2, "HID2",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    default:
-        gen_spr_generic(env);
-        break;
-    }
-    if (env->nb_BATs == -1)
-        env->nb_BATs = 4;
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
 }
 
-#if defined(PPC_DUMP_CPU)
-static void dump_sprs (CPUPPCState *env)
+/* SPR specific to PowerPC G2 implementation */
+static void gen_spr_G2 (CPUPPCState *env)
 {
-    ppc_spr_t *spr;
-    uint32_t pvr = env->spr[SPR_PVR];
-    uint32_t sr, sw, ur, uw;
-    int i, j, n;
-
-    printf("* SPRs for PVR=%08x\n", pvr);
-    for (i = 0; i < 32; i++) {
-        for (j = 0; j < 32; j++) {
-            n = (i << 5) | j;
-            spr = &env->spr_cb[n];
+    /* Memory base address */
+    /* MBAR */
+    spr_register(env, SPR_MBAR, "MBAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* System version register */
+    /* SVR */
+    spr_register(env, SPR_SVR, "SVR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Exception processing */
+    spr_register(env, SPR_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR2, "DABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR2, "IABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IBCR, "IBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DBCR, "DBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 602 implementation */
+static void gen_spr_602 (CPUPPCState *env)
+{
+    /* ESA registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SER, "SER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SEBR, "SEBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_ESASR, "ESASR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Floating point status */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SP, "SP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_LT, "LT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Watchdog timer */
+    /* XXX : not implemented */
+    spr_register(env, SPR_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Interrupt base */
+    spr_register(env, SPR_IBR, "IBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 601 implementation */
+static void gen_spr_601 (CPUPPCState *env)
+{
+    /* Multiplication/division register */
+    /* MQ */
+    spr_register(env, SPR_MQ, "MQ",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* RTC registers */
+    spr_register(env, SPR_601_RTCU, "RTCU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcu,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCU, "RTCU",
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_601_RTCL, "RTCL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcl,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCL, "RTCL",
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 0x00000000);
+    /* Timer */
+#if 0 /* ? */
+    spr_register(env, SPR_601_UDECR, "UDECR",
+                 &spr_read_decr, SPR_NOACCESS,
+                 &spr_read_decr, SPR_NOACCESS,
+                 0x00000000);
+#endif
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    spr_register(env, SPR_IBAT0U, "IBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT0L, "IBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1U, "IBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1L, "IBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2U, "IBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2L, "IBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3U, "IBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3L, "IBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+}
+
+/* PowerPC BookE SPR */
+static void gen_spr_BookE (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* Interrupt processing */
+    spr_register(env, SPR_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR2, "DBCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_EVPR, "EVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR0, "IVOR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR1, "IVOR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR2, "IVOR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR3, "IVOR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR4, "IVOR4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR5, "IVOR5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR6, "IVOR6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR7, "IVOR7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR8, "IVOR8",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR9, "IVOR9",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR10, "IVOR10",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR11, "IVOR11",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR12, "IVOR12",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR13, "IVOR13",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR14, "IVOR14",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR15, "IVOR15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DECAR, "DECAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 440 implementation */
+static void gen_spr_440 (CPUPPCState *env)
+{
+    /* Cache control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV0, "DNV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV1, "DNV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV2, "DNV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV3, "DNV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVT0, "DVT0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVT1, "DVT1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVT2, "DVT2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVT3, "DVT3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVLIM, "DVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV0, "INV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV1, "INV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV2, "INV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV3, "INV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVT0, "IVT0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVT1, "IVT1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVT2, "IVT2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVT3, "IVT3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVLIM, "IVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Cache debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DCBTRH, "DCBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DCBTRL, "DCBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_4xx_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ICBTRH, "ICBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ICBTRL, "ICBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DBDR, "DBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Processor control */
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_440_RSTCFG, "RSTCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Storage control */
+    spr_register(env, SPR_440_MMUCR, "MMUCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR shared between PowerPC 40x implementations */
+static void gen_spr_40x (CPUPPCState *env)
+{
+    /* Cache */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DCCR, "DCCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_ICCR, "ICCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_4xx_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Bus access control */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MMU */
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Exception */
+    spr_register(env, SPR_40x_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_EVPR, "EVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR2, "SRR2",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR3, "SRR3",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timers */
+    spr_register(env, SPR_40x_PIT, "PIT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_40x_pit, &spr_write_40x_pit,
+                 0x00000000);
+    spr_register(env, SPR_40x_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_40x_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 /* Last reset was system reset (system boot */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 405 implementation */
+static void gen_spr_405 (CPUPPCState *env)
+{
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00700000);
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Storage control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_SLER, "SLER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_SU0R, "SU0R",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* SPRG */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR shared between PowerPC 401 & 403 implementations */
+static void gen_spr_401_403 (CPUPPCState *env)
+{
+    /* Time base */
+    spr_register(env, SPR_403_VTBL,  "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBL,   "TBL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbl,
+                 0x00000000);
+    spr_register(env, SPR_403_VTBU,  "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBU,   "TBU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbu,
+                 0x00000000);
+    /* Debug */
+    /* XXX: not implemented */
+    spr_register(env, SPR_403_CDBCR, "CDBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 403 implementation */
+static void gen_spr_403 (CPUPPCState *env)
+{
+    /* MMU */
+    spr_register(env, SPR_403_PBL1,  "PBL1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU1,  "PBU1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBL2,  "PBL2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU2,  "PBU2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC compression coprocessor extension */
+#if defined (TODO)
+static void gen_spr_compress (CPUPPCState *env)
+{
+    spr_register(env, SPR_401_SKR, "SKR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+#endif
+
+// XXX: TODO (64 bits PowerPC SPRs)
+/*
+ * ASR => SPR 280 (64 bits)
+ * FPECR => SPR 1022 (?)
+ * VRSAVE => SPR 256 (Altivec)
+ * SCOMC => SPR 276 (64 bits ?)
+ * SCOMD => SPR 277 (64 bits ?)
+ * HSPRG0 => SPR 304 (hypervisor)
+ * HSPRG1 => SPR 305 (hypervisor)
+ * HDEC => SPR 310 (hypervisor)
+ * HIOR => SPR 311 (hypervisor)
+ * RMOR => SPR 312 (970)
+ * HRMOR => SPR 313 (hypervisor)
+ * HSRR0 => SPR 314 (hypervisor)
+ * HSRR1 => SPR 315 (hypervisor)
+ * LPCR => SPR 316 (970)
+ * LPIDR => SPR 317 (970)
+ * ... and more (thermal management, performance counters, ...)
+ */
+
+static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
+{
+    env->reserve = -1;
+    /* Default MMU definitions */
+    env->nb_BATs = -1;
+    env->nb_tlb = 0;
+    env->nb_ways = 0;
+    /* XXX: missing:
+     * 32 bits PowerPC:
+     * - MPC5xx(x)
+     * - MPC8xx(x)
+     * - RCPU (same as MPC5xx ?)
+     */
+    spr_register(env, SPR_PVR, "PVR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 def->pvr);
+    printf("%s: PVR %08x mask %08x => %08x\n", __func__,
+           def->pvr, def->pvr_mask, def->pvr & def->pvr_mask);
+    switch (def->pvr & def->pvr_mask) {
+        /* Embedded PowerPC from IBM                           */
+    case CPU_PPC_401A1:   /* 401 A1 family                 */
+    case CPU_PPC_401B2:   /* 401 B2 family                 */
+    case CPU_PPC_401C2:   /* 401 C2 family                 */
+    case CPU_PPC_401D2:   /* 401 D2 family                 */
+    case CPU_PPC_401E2:   /* 401 E2 family                 */
+    case CPU_PPC_401F2:   /* 401 F2 family                 */
+    case CPU_PPC_401G2:   /* 401 G2 family                 */
+    case CPU_PPC_IOP480:  /* IOP 480 family                */
+    case CPU_PPC_COBRA:   /* IBM Processor for Network Resources */
+        gen_spr_generic(env);
+        gen_spr_40x(env);
+        gen_spr_401_403(env);
+#if defined (TODO)
+        /* XXX: optional ? */
+        gen_spr_compress(env);
+#endif
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+    case CPU_PPC_403GA:   /* 403 GA family                 */
+    case CPU_PPC_403GB:   /* 403 GB family                 */
+    case CPU_PPC_403GC:   /* 403 GC family                 */
+    case CPU_PPC_403GCX:  /* 403 GCX family                */
+        gen_spr_generic(env);
+        gen_spr_40x(env);
+        gen_spr_401_403(env);
+        gen_spr_403(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+    case CPU_PPC_405CR:   /* 405 GP/CR family              */
+    case CPU_PPC_405EP:   /* 405 EP family                 */
+    case CPU_PPC_405GPR:  /* 405 GPR family                */
+    case CPU_PPC_405D2:   /* 405 D2 family                 */
+    case CPU_PPC_405D4:   /* 405 D4 family                 */
+        gen_spr_generic(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_40x(env);
+        gen_spr_405(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+    case CPU_PPC_NPE405H: /* NPe405 H family               */
+    case CPU_PPC_NPE405H2:
+    case CPU_PPC_NPE405L: /* Npe405 L family               */
+        gen_spr_generic(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_40x(env);
+        gen_spr_405(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+#if defined (TODO)
+    case CPU_PPC_STB01000:
+#endif
+#if defined (TODO)
+    case CPU_PPC_STB01010:
+#endif
+#if defined (TODO)
+    case CPU_PPC_STB0210:
+#endif
+    case CPU_PPC_STB03:   /* STB03 family                  */
+#if defined (TODO)
+    case CPU_PPC_STB043:  /* STB043 family                  */
+#endif
+#if defined (TODO)
+    case CPU_PPC_STB045:  /* STB045 family                  */
+#endif
+    case CPU_PPC_STB25:   /* STB25 family                  */
+#if defined (TODO)
+    case CPU_PPC_STB130:  /* STB130 family                 */
+#endif
+        gen_spr_generic(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_40x(env);
+        gen_spr_405(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+    case CPU_PPC_440EP:   /* 440 EP family                 */
+    case CPU_PPC_440GP:   /* 440 GP family                 */
+    case CPU_PPC_440GX:   /* 440 GX family                 */
+    case CPU_PPC_440GXc:  /* 440 GXc family                */
+    case CPU_PPC_440GXf:  /* 440 GXf family                */
+    case CPU_PPC_440SP:   /* 440 SP family                 */
+    case CPU_PPC_440SP2:
+    case CPU_PPC_440SPE:  /* 440 SPE family                */
+        gen_spr_generic(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_BookE(env);
+        gen_spr_440(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+        /* Embedded PowerPC from Freescale                     */
+#if defined (TODO)
+    case CPU_PPC_5xx:
+        break;
+#endif
+#if defined (TODO)
+    case CPU_PPC_8xx:     /* MPC821 / 823 / 850 / 860      */
+        break;
+#endif
+#if defined (TODO)
+    case CPU_PPC_82xx_HIP3:    /* MPC8240 / 8260                */
+    case CPU_PPC_82xx_HIP4:    /* MPC8240 / 8260                */
+        break;
+#endif
+#if defined (TODO)
+    case CPU_PPC_827x:    /* MPC 827x / 828x               */
+        break;
+#endif
+
+        /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */
+    case CPU_PPC_e500v110:
+    case CPU_PPC_e500v120:
+    case CPU_PPC_e500v210:
+    case CPU_PPC_e500v220:
+        gen_spr_generic(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_BookE(env);
+        env->nb_BATs = 0;
+        env->nb_tlb = 64;
+        env->nb_ways = 1;
+        env->id_tlbs = 0;
+        break;
+
+#if defined (TODO)
+    case CPU_PPC_e600:
+        break;
+#endif
+
+        /* 32 bits PowerPC                                     */
+    case CPU_PPC_601:     /* PowerPC 601                   */
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        gen_spr_601(env);
+        /* Hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_601_HID2, "HID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_601_HID5, "HID5",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+#if 0 /* ? */
+        spr_register(env, SPR_601_HID15, "HID15",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+#endif
+        env->nb_tlb = 64;
+        env->nb_ways = 2;
+        env->id_tlbs = 0;
+        env->id_tlbs = 0;
+        break;
+
+    case CPU_PPC_602:     /* PowerPC 602                   */
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_6xx_7xx_soft_tlb(env, 64, 2);
+        gen_spr_602(env);
+        /* hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+    case CPU_PPC_603:     /* PowerPC 603                   */
+    case CPU_PPC_603E:    /* PowerPC 603e                  */
+    case CPU_PPC_603E7v:
+    case CPU_PPC_603E7v2:
+    case CPU_PPC_603P:    /* PowerPC 603p                  */
+    case CPU_PPC_603R:    /* PowerPC 603r                  */
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_6xx_7xx_soft_tlb(env, 64, 2);
+        gen_spr_603(env);
+        /* hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+        
+    case CPU_PPC_G2:      /* PowerPC G2 family             */
+    case CPU_PPC_G2H4:
+    case CPU_PPC_G2gp:
+    case CPU_PPC_G2ls:
+    case CPU_PPC_G2LE:    /* PowerPC G2LE family           */
+    case CPU_PPC_G2LEgp:
+    case CPU_PPC_G2LEls:
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        /* Memory management */
+        gen_high_BATs(env);
+        gen_6xx_7xx_soft_tlb(env, 64, 2);
+        gen_spr_G2_755(env);
+        gen_spr_G2(env);
+        /* Hardware implementation register */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID2, "HID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+    case CPU_PPC_604:     /* PowerPC 604                   */
+    case CPU_PPC_604E:    /* PowerPC 604e                  */
+    case CPU_PPC_604R:    /* PowerPC 604r                  */
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_604(env);
+        /* Hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+    case CPU_PPC_74x:     /* PowerPC 740 / 750             */
+    case CPU_PPC_740E:
+    case CPU_PPC_750E:
+    case CPU_PPC_74xP:    /* PowerPC 740P / 750P           */
+    case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe            */
+    case CPU_PPC_750CXE22:
+    case CPU_PPC_750CXE23:
+    case CPU_PPC_750CXE24:
+    case CPU_PPC_750CXE24b:
+    case CPU_PPC_750CXE31:
+    case CPU_PPC_750CXE31b:
+    case CPU_PPC_750CXR:
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_7xx(env);
+        /* Hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+    case CPU_PPC_750FX10: /* IBM PowerPC 750 FX            */
+    case CPU_PPC_750FX20:
+    case CPU_PPC_750FX21:
+    case CPU_PPC_750FX22:
+    case CPU_PPC_750FX23:
+    case CPU_PPC_750GX10: /* IBM PowerPC 750 GX            */
+    case CPU_PPC_750GX11:
+    case CPU_PPC_750GX12:
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
+        gen_high_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        gen_spr_7xx(env);
+        /* Hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_750_HID2, "HID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+    case CPU_PPC_755_10:  /* PowerPC 755                   */
+    case CPU_PPC_755_11:
+    case CPU_PPC_755_20:
+    case CPU_PPC_755D:
+    case CPU_PPC_755E:
+        gen_spr_generic(env);
+        gen_spr_ne_601(env);
+        /* Memory management */
+        gen_low_BATs(env);
+        /* Time base */
+        gen_tbl(env);
+        /* Memory management */
+        gen_high_BATs(env);
+        gen_6xx_7xx_soft_tlb(env, 64, 2);
+        gen_spr_G2_755(env);
+        /* L2 cache control */
+        /* XXX : not implemented */
+        spr_register(env, SPR_ICTC, "ICTC",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_L2PM, "L2PM",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* Hardware implementation registers */
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID0, "HID0",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID1, "HID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        /* XXX : not implemented */
+        spr_register(env, SPR_HID2, "HID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+        break;
+
+#if defined (TODO)
+        /* G4 family */
+    case CPU_PPC_7400:    /* PowerPC 7400                  */
+    case CPU_PPC_7410C:   /* PowerPC 7410                  */
+    case CPU_PPC_7410D:
+    case CPU_PPC_7410E:
+    case CPU_PPC_7441:    /* PowerPC 7441                  */
+    case CPU_PPC_7445:    /* PowerPC 7445                  */
+    case CPU_PPC_7447:    /* PowerPC 7447                  */
+    case CPU_PPC_7447A:   /* PowerPC 7447A                 */
+    case CPU_PPC_7448:    /* PowerPC 7448                  */
+    case CPU_PPC_7450:    /* PowerPC 7450                  */
+    case CPU_PPC_7450b:
+    case CPU_PPC_7451:    /* PowerPC 7451                  */
+    case CPU_PPC_7451G:
+    case CPU_PPC_7455:    /* PowerPC 7455                  */
+    case CPU_PPC_7455F:
+    case CPU_PPC_7455G:
+    case CPU_PPC_7457:    /* PowerPC 7457                  */
+    case CPU_PPC_7457C:
+    case CPU_PPC_7457A:   /* PowerPC 7457A                 */
+        break;
+#endif
+
+#if defined (TODO)
+        /* 64 bits PowerPC                                     */
+    case CPU_PPC_620:     /* PowerPC 620                   */
+    case CPU_PPC_630:     /* PowerPC 630 (Power 3)         */
+    case CPU_PPC_631:     /* PowerPC 631 (Power 3+)        */
+    case CPU_PPC_POWER4:  /* Power 4                       */
+    case CPU_PPC_POWER4P: /* Power 4+                      */
+    case CPU_PPC_POWER5:  /* Power 5                       */
+    case CPU_PPC_POWER5P: /* Power 5+                      */
+    case CPU_PPC_970:     /* PowerPC 970                   */
+    case CPU_PPC_970FX10: /* PowerPC 970 FX                */
+    case CPU_PPC_970FX20:
+    case CPU_PPC_970FX21:
+    case CPU_PPC_970FX30:
+    case CPU_PPC_970FX31:
+    case CPU_PPC_970MP10: /* PowerPC 970 MP                */
+    case CPU_PPC_970MP11:
+    case CPU_PPC_CELL10:  /* Cell family                   */
+    case CPU_PPC_CELL20:
+    case CPU_PPC_CELL30:
+    case CPU_PPC_CELL31:
+    case CPU_PPC_RS64:    /* Apache (RS64/A35)             */
+    case CPU_PPC_RS64II:  /* NorthStar (RS64-II/A50)       */
+    case CPU_PPC_RS64III: /* Pulsar (RS64-III)             */
+    case CPU_PPC_RS64IV:  /* IceStar/IStar/SStar (RS64-IV) */
+        break;
+#endif
+
+#if defined (TODO)
+        /* POWER                                               */
+    case CPU_POWER:       /* POWER                         */
+    case CPU_POWER2:      /* POWER2                        */
+        break;
+#endif
+
+    default:
+        gen_spr_generic(env);
+        break;
+    }
+    if (env->nb_BATs == -1)
+        env->nb_BATs = 4;
+    /* Allocate TLBs buffer when needed */
+    if (env->nb_tlb != 0) {
+        int nb_tlb = env->nb_tlb;
+        if (env->id_tlbs != 0)
+            nb_tlb *= 2;
+        env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+        /* Pre-compute some useful values */
+        env->tlb_per_way = env->nb_tlb / env->nb_ways;
+    }
+}
+
+#if defined(PPC_DUMP_CPU)
+static void dump_sprs (CPUPPCState *env)
+{
+    ppc_spr_t *spr;
+    uint32_t pvr = env->spr[SPR_PVR];
+    uint32_t sr, sw, ur, uw;
+    int i, j, n;
+
+    printf("* SPRs for PVR=%08x\n", pvr);
+    for (i = 0; i < 32; i++) {
+        for (j = 0; j < 32; j++) {
+            n = (i << 5) | j;
+            spr = &env->spr_cb[n];
+#if !defined(CONFIG_USER_ONLY)
             sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
             sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
+#else
+            sw = 0;
+            sr = 0;
+#endif
             uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS;
             ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS;
             if (sw || sr || uw || ur) {
@@ -889,7 +2301,7 @@ static int register_direct_insn (opc_handler_t **ppc_opcodes,
 {
     if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
         printf("*** ERROR: opcode %02x already assigned in main "
-                "opcode table\n", idx);
+               "opcode table\n", idx);
         return -1;
     }
 
@@ -903,20 +2315,20 @@ static int register_ind_in_table (opc_handler_t **table,
     if (table[idx1] == &invalid_handler) {
         if (create_new_table(table, idx1) < 0) {
             printf("*** ERROR: unable to create indirect table "
-                    "idx=%02x\n", idx1);
+                   "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);
+                   "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);
+               "opcode table %02x\n", idx2, idx1);
         return -1;
     }
 
@@ -925,7 +2337,7 @@ static int register_ind_in_table (opc_handler_t **table,
 
 static int register_ind_insn (opc_handler_t **ppc_opcodes,
                               unsigned char idx1, unsigned char idx2,
-                               opc_handler_t *handler)
+                              opc_handler_t *handler)
 {
     int ret;
 
@@ -936,17 +2348,17 @@ static int register_ind_insn (opc_handler_t **ppc_opcodes,
 
 static int register_dblind_insn (opc_handler_t **ppc_opcodes, 
                                  unsigned char idx1, unsigned char idx2,
-                                  unsigned char idx3, opc_handler_t *handler)
+                                 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);
+               "[%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);
+               "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
         return -1;
     }
 
@@ -1012,21 +2424,22 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
 
     fill_new_table(env->opcodes, 0x40);
 #if defined(PPC_DUMP_CPU)
-    printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
+    printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n",
+           def->pvr, def->name, def->insns_flags, def->flags);
 #endif
     if (&opc_start < &opc_end) {
-       start = &opc_start;
-       end = &opc_end;
+        start = &opc_start;
+        end = &opc_end;
     } else {
-       start = &opc_end;
-       end = &opc_start;
+        start = &opc_end;
+        end = &opc_start;
     }
     for (opc = start + 1; opc != end; opc++) {
         if ((opc->handler.type & def->insns_flags) != 0) {
             if (register_insn(env->opcodes, opc) < 0) {
-                printf("*** ERROR initializing PPC instruction "
-                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
-                        opc->opc3);
+                printf("*** ERROR initializing PowerPC instruction "
+                       "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+                       opc->opc3);
                 return -1;
             }
 #if defined(PPC_DUMP_CPU)
@@ -1038,7 +2451,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
                     } else {
                         printf(" %02x %02x -- (%2d %4d) : %s\n",
                                opc->opc1, opc->opc2, opc->opc1, opc->opc2,
-                                    opc->oname);
+                               opc->oname);
                     }
                 } else {
                     printf(" %02x %02x %02x (%2d %4d) : %s\n",
@@ -1061,23 +2474,22 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def)
 {
     env->msr_mask = def->msr_mask;
     env->flags = def->flags;
-    if (create_ppc_opcodes(env, def) < 0) {
-        printf("Error creating opcodes table\n");
-        fflush(stdout);
-        fflush(stderr);
+    if (create_ppc_opcodes(env, def) < 0)
         return -1;
-    }
     init_ppc_proc(env, def);
 #if defined(PPC_DUMP_CPU)
     dump_sprs(env);
+    if (env->tlb != NULL) {
+        printf("%d %s TLB in %d ways\n", env->nb_tlb,
+               env->id_tlbs ? "splitted" : "merged", env->nb_ways);
+    }
 #endif
-    fflush(stdout);
-    fflush(stderr);
 
     return 0;
 }
 
-CPUPPCState *cpu_ppc_init(void)
+void do_compute_hflags (CPUPPCState *env);
+CPUPPCState *cpu_ppc_init (void)
 {
     CPUPPCState *env;
 
@@ -1112,911 +2524,1171 @@ void cpu_ppc_close(CPUPPCState *env)
 /*****************************************************************************/
 /* PowerPC CPU definitions */
 static ppc_def_t ppc_defs[] =
-{
-    /* Embedded PPC */
-#if defined (TODO)
-    /* PPC 401 */
     {
-        .name        = "401",
-        .pvr         = CPU_PPC_401,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_401,
-        .flags       = PPC_FLAGS_401,
-        .msr_mask    = xxx,
-    },
+        /* Embedded PowerPC */
+#if defined (TODO)
+        /* PowerPC 401 */
+        {
+            .name        = "401",
+            .pvr         = CPU_PPC_401,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_401,
+            .flags       = PPC_FLAGS_401,
+            .msr_mask    = xxx,
+        },
 #endif
 #if defined (TODO)
-    /* IOP480 (401 microcontroler) */
-    {
-        .name        = "iop480",
-        .pvr         = CPU_PPC_IOP480,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_401,
-        .flags       = PPC_FLAGS_401,
-        .msr_mask    = xxx,
-    },
+        /* IOP480 (401 microcontroler) */
+        {
+            .name        = "iop480",
+            .pvr         = CPU_PPC_IOP480,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_401,
+            .flags       = PPC_FLAGS_401,
+            .msr_mask    = xxx,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 403 GA */
-    {
-        .name        = "403ga",
-        .pvr         = CPU_PPC_403GA,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
+        /* IBM Processor for Network Resources */
+        {
+            .name        = "Cobra",
+            .pvr         = CPU_PPC_COBRA,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_401,
+            .flags       = PPC_FLAGS_401,
+            .msr_mask    = xxx,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 403 GB */
-    {
-        .name        = "403gb",
-        .pvr         = CPU_PPC_403GB,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
+        /* Generic PowerPC 403 */
+        {
+            .name        = "403",
+            .pvr         = CPU_PPC_403,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_403,
+            .flags       = PPC_FLAGS_403,
+            .msr_mask    = 0x000000000007D23D,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 403 GC */
-    {
-        .name        = "403gc",
-        .pvr         = CPU_PPC_403GC,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
+        /* PowerPC 403 GA */
+        {
+            .name        = "403ga",
+            .pvr         = CPU_PPC_403GA,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_403,
+            .flags       = PPC_FLAGS_403,
+            .msr_mask    = 0x000000000007D23D,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 403 GCX */
-    {
-        .name        = "403gcx",
-        .pvr         = CPU_PPC_403GCX,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
+        /* PowerPC 403 GB */
+        {
+            .name        = "403gb",
+            .pvr         = CPU_PPC_403GB,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_403,
+            .flags       = PPC_FLAGS_403,
+            .msr_mask    = 0x000000000007D23D,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 CR */
-    {
-        .name        = "405cr",
-        .pvr         = CPU_PPC_405,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 403 GC */
+        {
+            .name        = "403gc",
+            .pvr         = CPU_PPC_403GC,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_403,
+            .flags       = PPC_FLAGS_403,
+            .msr_mask    = 0x000000000007D23D,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 GP */
-    {
-        .name        = "405gp",
-        .pvr         = CPU_PPC_405,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 403 GCX */
+        {
+            .name        = "403gcx",
+            .pvr         = CPU_PPC_403GCX,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_403,
+            .flags       = PPC_FLAGS_403,
+            .msr_mask    = 0x000000000007D23D,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 EP */
-    {
-        .name        = "405ep",
-        .pvr         = CPU_PPC_405EP,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* Generic PowerPC 405 */
+        {
+            .name        = "405",
+            .pvr         = CPU_PPC_405,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 GPR */
-    {
-        .name        = "405gpr",
-        .pvr         = CPU_PPC_405GPR,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 CR */
+        {
+            .name        = "405cr",
+            .pvr         = CPU_PPC_405,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 D2 */
-    {
-        .name        = "405d2",
-        .pvr         = CPU_PPC_405D2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 GP */
+        {
+            .name        = "405gp",
+            .pvr         = CPU_PPC_405,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 405 D4 */
-    {
-        .name        = "405d4",
-        .pvr         = CPU_PPC_405D4,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 EP */
+        {
+            .name        = "405ep",
+            .pvr         = CPU_PPC_405EP,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* Npe405 H */
-    {
-        .name        = "Npe405H",
-        .pvr         = CPU_PPC_NPE405H,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 GPR */
+        {
+            .name        = "405gpr",
+            .pvr         = CPU_PPC_405GPR,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* Npe405 L */
-    {
-        .name        = "Npe405L",
-        .pvr         = CPU_PPC_NPE405L,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 D2 */
+        {
+            .name        = "405d2",
+            .pvr         = CPU_PPC_405D2,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* STB03xx */
-    {
-        .name        = "STB03",
-        .pvr         = CPU_PPC_STB03,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* PowerPC 405 D4 */
+        {
+            .name        = "405d4",
+            .pvr         = CPU_PPC_405D4,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* STB04xx */
-    {
-        .name        = "STB04",
-        .pvr         = CPU_PPC_STB04,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* Npe405 H */
+        {
+            .name        = "Npe405H",
+            .pvr         = CPU_PPC_NPE405H,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* STB25xx */
-    {
-        .name        = "STB25",
-        .pvr         = CPU_PPC_STB25,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
+        /* Npe405 L */
+        {
+            .name        = "Npe405L",
+            .pvr         = CPU_PPC_NPE405L,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 440 EP */
-    {
-        .name        = "440ep",
-        .pvr         = CPU_PPC_440EP,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_440,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
+        /* STB010000 */
+        {
+            .name        = "STB01000",
+            .pvr         = CPU_PPC_STB01000,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 440 GP */
-    {
-        .name        = "440gp",
-        .pvr         = CPU_PPC_440GP,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_440,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
+        /* STB01010 */
+        {
+            .name        = "STB01010",
+            .pvr         = CPU_PPC_STB01010,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 440 GX */
-    {
-        .name        = "440gx",
-        .pvr         = CPU_PPC_440GX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
+        /* STB0210 */
+        {
+            .name        = "STB0210",
+            .pvr         = CPU_PPC_STB0210,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
-
-    /* 32 bits "classic" powerpc */
 #if defined (TODO)
-    /* PPC 601 */
-    {
-        .name        = "601",
-        .pvr         = CPU_PPC_601,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_601,
-        .flags       = PPC_FLAGS_601,
-        .msr_mask    = 0x000000000000FD70,
-    },
+        /* STB03xx */
+        {
+            .name        = "STB03",
+            .pvr         = CPU_PPC_STB03,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 602 */
-    {
-        .name        = "602",
-        .pvr         = CPU_PPC_602,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_602,
-        .flags       = PPC_FLAGS_602,
-        .msr_mask    = 0x0000000000C7FF73,
-    },
+        /* STB043x */
+        {
+            .name        = "STB043",
+            .pvr         = CPU_PPC_STB043,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 603 */
-    {
-        .name        = "603",
-        .pvr         = CPU_PPC_603,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
+        /* STB045x */
+        {
+            .name        = "STB045",
+            .pvr         = CPU_PPC_STB045,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 603e */
-    {
-        .name        = "603e",
-        .pvr         = CPU_PPC_603E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-    {
-        .name        = "Stretch",
-        .pvr         = CPU_PPC_603E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
+        /* STB25xx */
+        {
+            .name        = "STB25",
+            .pvr         = CPU_PPC_STB25,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 603ev */
-    {
-        .name        = "603ev",
-        .pvr         = CPU_PPC_603EV,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
+        /* STB130 */
+        {
+            .name        = "STB130",
+            .pvr         = CPU_PPC_STB130,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
+        /* Xilinx PowerPC 405 cores */
 #if defined (TODO)
-    /* PPC 603r */
-    {
-        .name        = "603r",
-        .pvr         = CPU_PPC_603R,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-    {
-        .name        = "Goldeneye",
-        .pvr         = CPU_PPC_603R,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
+        {
+            .name        = "x2vp4",
+            .pvr         = CPU_PPC_X2VP4,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
+        {
+            .name        = "x2vp7",
+            .pvr         = CPU_PPC_X2VP7,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
+        {
+            .name        = "x2vp20",
+            .pvr         = CPU_PPC_X2VP20,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
+        {
+            .name        = "x2vp50",
+            .pvr         = CPU_PPC_X2VP50,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_405,
+            .msr_mask    = 0x00000000020EFF30,
+        },
 #endif
 #if defined (TODO)
-    /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
-    {
-        .name        = "G2",
-        .pvr         = CPU_PPC_G2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_G2,
-        .flags       = PPC_FLAGS_G2,
-        .msr_mask    = 0x000000000006FFF2,
-    },
-    { /* Same as G2, with LE mode support */
-        .name        = "G2le",
-        .pvr         = CPU_PPC_G2LE,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_G2,
-        .flags       = PPC_FLAGS_G2,
-        .msr_mask    = 0x000000000007FFF3,
-    },
-#endif
-    /* PPC 604 */
-    {
-        .name        = "604",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* PPC 604e */
-    {
-        .name        = "604e",
-        .pvr         = CPU_PPC_604E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* PPC 604r */
-    {
-        .name        = "604r",
-        .pvr         = CPU_PPC_604R,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* generic G3 */
-    {
-        .name        = "G3",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC740 (G3) */
-    {
-        .name        = "740",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Arthur",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
+        /* PowerPC 440 EP */
+        {
+            .name        = "440ep",
+            .pvr         = CPU_PPC_440EP,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_440,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* MPC745 (G3) */
-    {
-        .name        = "745",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Goldfinger",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* MPC750 (G3) */
-    {
-        .name        = "750",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC755 (G3) */
-    {
-        .name        = "755",
-        .pvr         = CPU_PPC_755,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
+        /* PowerPC 440 GR */
+        {
+            .name        = "440gr",
+            .pvr         = CPU_PPC_440GR,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_440,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* MPC740P (G3) */
-    {
-        .name        = "740p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Conan/Doyle",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
+        /* PowerPC 440 GP */
+        {
+            .name        = "440gp",
+            .pvr         = CPU_PPC_440GP,
+            .pvr_mask    = 0xFFFFFF00,
+            .insns_flags = PPC_INSNS_440,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* MPC745P (G3) */
-    {
-        .name        = "745p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* MPC750P (G3) */
-    {
-        .name        = "750p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC755P (G3) */
-    {
-        .name        = "755p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* IBM 750CXe (G3 embedded) */
-    {
-        .name        = "750cxe",
-        .pvr         = CPU_PPC_750CXE,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    /* IBM 750FX (G3 embedded) */
-    {
-        .name        = "750fx",
-        .pvr         = CPU_PPC_750FX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    /* IBM 750GX (G3 embedded) */
-    {
-        .name        = "750gx",
-        .pvr         = CPU_PPC_750GX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* generic G4 */
-    {
-        .name        = "G4",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 GX */
+        {
+            .name        = "440gx",
+            .pvr         = CPU_PPC_440GX,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 7400 (G4) */
-    {
-        .name        = "7400",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Max",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 GXc */
+        {
+            .name        = "440gxc",
+            .pvr         = CPU_PPC_440GXC,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 7410 (G4) */
-    {
-        .name        = "7410",
-        .pvr         = CPU_PPC_7410,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Nitro",
-        .pvr         = CPU_PPC_7410,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-    /* XXX: 7441 */
-    /* XXX: 7445 */
-    /* XXX: 7447 */
-    /* XXX: 7447A */
-#if defined (TODO)
-    /* PPC 7450 (G4) */
-    {
-        .name        = "7450",
-        .pvr         = CPU_PPC_7450,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Vger",
-        .pvr         = CPU_PPC_7450,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 GXf */
+        {
+            .name        = "440gxf",
+            .pvr         = CPU_PPC_440GXF,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
-    /* XXX: 7451 */
 #if defined (TODO)
-    /* PPC 7455 (G4) */
-    {
-        .name        = "7455",
-        .pvr         = CPU_PPC_7455,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 6",
-        .pvr         = CPU_PPC_7455,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 SP */
+        {
+            .name        = "440sp",
+            .pvr         = CPU_PPC_440SP,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 7457 (G4) */
-    {
-        .name        = "7457",
-        .pvr         = CPU_PPC_7457,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 7",
-        .pvr         = CPU_PPC_7457,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 SP2 */
+        {
+            .name        = "440sp2",
+            .pvr         = CPU_PPC_440SP2,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 7457A (G4) */
-    {
-        .name        = "7457A",
-        .pvr         = CPU_PPC_7457A,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 7 PM",
-        .pvr         = CPU_PPC_7457A,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
+        /* PowerPC 440 SPE */
+        {
+            .name        = "440spe",
+            .pvr         = CPU_PPC_440SPE,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_405,
+            .flags       = PPC_FLAGS_440,
+            .msr_mask    = 0x000000000006D630,
+        },
 #endif
-    /* 64 bits PPC */
+        /* Fake generic BookE PowerPC */
+        {
+            .name        = "BookE",
+            .pvr         = CPU_PPC_e500,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_BOOKE,
+            .flags       = PPC_FLAGS_BOOKE,
+            .msr_mask    = 0x000000000006D630,
+        },
+        /* PowerPC 460 cores - TODO */
+        /* PowerPC MPC 5xx cores - TODO */
+        /* PowerPC MPC 8xx cores - TODO */
+        /* PowerPC MPC 8xxx cores - TODO */
+        /* e200 cores - TODO */
+        /* e500 cores - TODO */
+        /* e600 cores - TODO */
+
+        /* 32 bits "classic" PowerPC */
 #if defined (TODO)
-    /* PPC 620 */
-    {
-        .name        = "620",
-        .pvr         = CPU_PPC_620,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_620,
-        .flags       = PPC_FLAGS_620,
-        .msr_mask    = 0x800000000005FF73,
-    },
+        /* PowerPC 601 */
+        {
+            .name        = "601",
+            .pvr         = CPU_PPC_601,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_601,
+            .flags       = PPC_FLAGS_601,
+            .msr_mask    = 0x000000000000FD70,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 630 (POWER3) */
-    {
-        .name        = "630",
-        .pvr         = CPU_PPC_630,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_630,
-        .flags       = PPC_FLAGS_630,
-        .msr_mask    = xxx,
-    }
-    {
-        .name        = "POWER3",
-        .pvr         = CPU_PPC_630,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_630,
-        .flags       = PPC_FLAGS_630,
-        .msr_mask    = xxx,
-    }
+        /* PowerPC 602 */
+        {
+            .name        = "602",
+            .pvr         = CPU_PPC_602,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_602,
+            .flags       = PPC_FLAGS_602,
+            .msr_mask    = 0x0000000000C7FF73,
+        },
 #endif
+        /* PowerPC 603 */
+        {
+            .name        = "603",
+            .pvr         = CPU_PPC_603,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603e */
+        {
+            .name        = "603e",
+            .pvr         = CPU_PPC_603E,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        {
+            .name        = "Stretch",
+            .pvr         = CPU_PPC_603E,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603p */
+        {
+            .name        = "603p",
+            .pvr         = CPU_PPC_603P,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603e7 */
+        {
+            .name        = "603e7",
+            .pvr         = CPU_PPC_603E7,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603e7v */
+        {
+            .name        = "603e7v",
+            .pvr         = CPU_PPC_603E7v,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603e7v2 */
+        {
+            .name        = "603e7v2",
+            .pvr         = CPU_PPC_603E7v2,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        /* PowerPC 603r */
+        {
+            .name        = "603r",
+            .pvr         = CPU_PPC_603R,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
+        {
+            .name        = "Goldeneye",
+            .pvr         = CPU_PPC_603R,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_603,
+            .flags       = PPC_FLAGS_603,
+            .msr_mask    = 0x000000000007FF73,
+        },
 #if defined (TODO)
-    /* PPC 631 (Power 3+)*/
-    {
-        .name        = "631",
-        .pvr         = CPU_PPC_631,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_631,
-        .flags       = PPC_FLAGS_631,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "POWER3+",
-        .pvr         = CPU_PPC_631,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_631,
-        .flags       = PPC_FLAGS_631,
-        .msr_mask    = xxx,
-    },
+        /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
+        {
+            .name        = "G2",
+            .pvr         = CPU_PPC_G2,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000006FFF2,
+        },
+        {
+            .name        = "G2h4",
+            .pvr         = CPU_PPC_G2H4,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000006FFF2,
+        },
+        {
+            .name        = "G2gp",
+            .pvr         = CPU_PPC_G2gp,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000006FFF2,
+        },
+        {
+            .name        = "G2ls",
+            .pvr         = CPU_PPC_G2ls,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000006FFF2,
+        },
+        { /* Same as G2, with LE mode support */
+            .name        = "G2le",
+            .pvr         = CPU_PPC_G2LE,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000007FFF3,
+        },
+        {
+            .name        = "G2legp",
+            .pvr         = CPU_PPC_G2LEgp,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000007FFF3,
+        },
+        {
+            .name        = "G2lels",
+            .pvr         = CPU_PPC_G2LEls,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_G2,
+            .flags       = PPC_FLAGS_G2,
+            .msr_mask    = 0x000000000007FFF3,
+        },
 #endif
+        /* PowerPC 604 */
+        {
+            .name        = "604",
+            .pvr         = CPU_PPC_604,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_604,
+            .flags       = PPC_FLAGS_604,
+            .msr_mask    = 0x000000000005FF77,
+        },
+        /* PowerPC 604e */
+        {
+            .name        = "604e",
+            .pvr         = CPU_PPC_604E,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_604,
+            .flags       = PPC_FLAGS_604,
+            .msr_mask    = 0x000000000005FF77,
+        },
+        /* PowerPC 604r */
+        {
+            .name        = "604r",
+            .pvr         = CPU_PPC_604R,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_604,
+            .flags       = PPC_FLAGS_604,
+            .msr_mask    = 0x000000000005FF77,
+        },
+        /* generic G3 */
+        {
+            .name        = "G3",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        /* MPC740 (G3) */
+        {
+            .name        = "740",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        {
+            .name        = "Arthur",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #if defined (TODO)
-    /* POWER4 */
-    {
-        .name        = "POWER4",
-        .pvr         = CPU_PPC_POWER4,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER4,
-        .flags       = PPC_FLAGS_POWER4,
-        .msr_mask    = xxx,
-    },
+        /* MPC745 (G3) */
+        {
+            .name        = "745",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFF000,
+            .insns_flags = PPC_INSNS_7x5,
+            .flags       = PPC_FLAGS_7x5,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        {
+            .name        = "Goldfinger",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFF000,
+            .insns_flags = PPC_INSNS_7x5,
+            .flags       = PPC_FLAGS_7x5,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #endif
+        /* MPC750 (G3) */
+        {
+            .name        = "750",
+            .pvr         = CPU_PPC_74x,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #if defined (TODO)
-    /* POWER4p */
-    {
-        .name        = "POWER4+",
-        .pvr         = CPU_PPC_POWER4P,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER4,
-        .flags       = PPC_FLAGS_POWER4,
-        .msr_mask    = xxx,
-    },
+        /* MPC755 (G3) */
+        {
+            .name        = "755",
+            .pvr         = CPU_PPC_755,
+            .pvr_mask    = 0xFFFFF000,
+            .insns_flags = PPC_INSNS_7x5,
+            .flags       = PPC_FLAGS_7x5,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #endif
+        /* MPC740P (G3) */
+        {
+            .name        = "740p",
+            .pvr         = CPU_PPC_74xP,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        {
+            .name        = "Conan/Doyle",
+            .pvr         = CPU_PPC_74xP,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #if defined (TODO)
-    /* POWER5 */
-    {
-        .name        = "POWER5",
-        .pvr         = CPU_PPC_POWER5,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER5,
-        .flags       = PPC_FLAGS_POWER5,
-        .msr_mask    = xxx,
-    },
+        /* MPC745P (G3) */
+        {
+            .name        = "745p",
+            .pvr         = CPU_PPC_74xP,
+            .pvr_mask    = 0xFFFFF000,
+            .insns_flags = PPC_INSNS_7x5,
+            .flags       = PPC_FLAGS_7x5,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #endif
+        /* MPC750P (G3) */
+        {
+            .name        = "750p",
+            .pvr         = CPU_PPC_74xP,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #if defined (TODO)
-    /* POWER5+ */
-    {
-        .name        = "POWER5+",
-        .pvr         = CPU_PPC_POWER5P,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER5,
-        .flags       = PPC_FLAGS_POWER5,
-        .msr_mask    = xxx,
-    },
+        /* MPC755P (G3) */
+        {
+            .name        = "755p",
+            .pvr         = CPU_PPC_74xP,
+            .pvr_mask    = 0xFFFFF000,
+            .insns_flags = PPC_INSNS_7x5,
+            .flags       = PPC_FLAGS_7x5,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #endif
+        /* IBM 750CXe (G3 embedded) */
+        {
+            .name        = "750cxe",
+            .pvr         = CPU_PPC_750CXE,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        /* IBM 750FX (G3 embedded) */
+        {
+            .name        = "750fx",
+            .pvr         = CPU_PPC_750FX,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
+        /* IBM 750GX (G3 embedded) */
+        {
+            .name        = "750gx",
+            .pvr         = CPU_PPC_750GX,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_7x0,
+            .flags       = PPC_FLAGS_7x0,
+            .msr_mask    = 0x000000000007FF77,
+        },
 #if defined (TODO)
-    /* PPC 970 */
-    {
-        .name        = "970",
-        .pvr         = CPU_PPC_970,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_970,
-        .flags       = PPC_FLAGS_970,
-        .msr_mask    = 0x900000000204FF36,
-    },
+        /* generic G4 */
+        {
+            .name        = "G4",
+            .pvr         = CPU_PPC_7400,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
 #if defined (TODO)
-    /* PPC 970FX (G5) */
-    {
-        .name        = "970fx",
-        .pvr         = CPU_PPC_970FX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_970FX,
-        .flags       = PPC_FLAGS_970FX,
-        .msr_mask    = 0x800000000204FF36,
-    },
-#endif
-#if defined (TODO)
-    /* RS64 (Apache/A35) */
-    /* This one seems to support the whole POWER2 instruction set
-     * and the PowerPC 64 one.
-     */
-    {
-        .name        = "RS64",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "Apache",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "A35",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7400 (G4) */
+        {
+            .name        = "7400",
+            .pvr         = CPU_PPC_7400,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Max",
+            .pvr         = CPU_PPC_7400,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
 #if defined (TODO)
-    /* RS64-II (NorthStar/A50) */
-    {
-        .name        = "RS64-II",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "NortStar",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "A50",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7410 (G4) */
+        {
+            .name        = "7410",
+            .pvr         = CPU_PPC_7410,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Nitro",
+            .pvr         = CPU_PPC_7410,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
+        /* XXX: 7441 */
+        /* XXX: 7445 */
+        /* XXX: 7447 */
+        /* XXX: 7447A */
 #if defined (TODO)
-    /* RS64-III (Pulsar) */
-    {
-        .name        = "RS64-III",
-        .pvr         = CPU_PPC_RS64III,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "Pulsar",
-        .pvr         = CPU_PPC_RS64III,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7450 (G4) */
+        {
+            .name        = "7450",
+            .pvr         = CPU_PPC_7450,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Vger",
+            .pvr         = CPU_PPC_7450,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
+        /* XXX: 7451 */
 #if defined (TODO)
-    /* RS64-IV (IceStar/IStar/SStar) */
-    {
-        .name        = "RS64-IV",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "IceStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "IStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "SStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7455 (G4) */
+        {
+            .name        = "7455",
+            .pvr         = CPU_PPC_7455,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Apollo 6",
+            .pvr         = CPU_PPC_7455,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
-    /* POWER */
 #if defined (TODO)
-    /* Original POWER */
-    {
-        .name        = "POWER",
-        .pvr         = CPU_POWER,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER,
-        .flags       = PPC_FLAGS_POWER,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7457 (G4) */
+        {
+            .name        = "7457",
+            .pvr         = CPU_PPC_7457,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Apollo 7",
+            .pvr         = CPU_PPC_7457,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
 #if defined (TODO)
-    /* POWER2 */
-    {
-        .name        = "POWER2",
-        .pvr         = CPU_POWER2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER,
-        .flags       = PPC_FLAGS_POWER,
-        .msr_mask    = xxx,
-    },
+        /* PowerPC 7457A (G4) */
+        {
+            .name        = "7457A",
+            .pvr         = CPU_PPC_7457A,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
+        {
+            .name        = "Apollo 7 PM",
+            .pvr         = CPU_PPC_7457A,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_74xx,
+            .flags       = PPC_FLAGS_74xx,
+            .msr_mask    = 0x000000000205FF77,
+        },
 #endif
-    /* Generic PowerPCs */
+        /* 64 bits PowerPC */
 #if defined (TODO)
-    {
-        .name        = "ppc64",
-        .pvr         = CPU_PPC_970,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC64,
-        .flags       = PPC_FLAGS_PPC64,
-        .msr_mask    = 0xA00000000204FF36,
-    },
+        /* PowerPC 620 */
+        {
+            .name        = "620",
+            .pvr         = CPU_PPC_620,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_620,
+            .flags       = PPC_FLAGS_620,
+            .msr_mask    = 0x800000000005FF73,
+        },
 #endif
-    {
-        .name        = "ppc32",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC32,
-        .flags       = PPC_FLAGS_PPC32,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* Fallback */
-    {
-        .name        = "ppc",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC32,
-        .flags       = PPC_FLAGS_PPC32,
-        .msr_mask    = 0x000000000005FF77,
-    },
-};
+#if defined (TODO)
+        /* PowerPC 630 (POWER3) */
+        {
+            .name        = "630",
+            .pvr         = CPU_PPC_630,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_630,
+            .flags       = PPC_FLAGS_630,
+            .msr_mask    = xxx,
+        }
+        {
+            .name        = "POWER3",
+            .pvr         = CPU_PPC_630,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_630,
+            .flags       = PPC_FLAGS_630,
+            .msr_mask    = xxx,
+        }
+#endif
+#if defined (TODO)
+        /* PowerPC 631 (Power 3+)*/
+        {
+            .name        = "631",
+            .pvr         = CPU_PPC_631,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_631,
+            .flags       = PPC_FLAGS_631,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "POWER3+",
+            .pvr         = CPU_PPC_631,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_631,
+            .flags       = PPC_FLAGS_631,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* POWER4 */
+        {
+            .name        = "POWER4",
+            .pvr         = CPU_PPC_POWER4,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER4,
+            .flags       = PPC_FLAGS_POWER4,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* POWER4p */
+        {
+            .name        = "POWER4+",
+            .pvr         = CPU_PPC_POWER4P,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER4,
+            .flags       = PPC_FLAGS_POWER4,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* POWER5 */
+        {
+            .name        = "POWER5",
+            .pvr         = CPU_PPC_POWER5,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER5,
+            .flags       = PPC_FLAGS_POWER5,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* POWER5+ */
+        {
+            .name        = "POWER5+",
+            .pvr         = CPU_PPC_POWER5P,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER5,
+            .flags       = PPC_FLAGS_POWER5,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* PowerPC 970 */
+        {
+            .name        = "970",
+            .pvr         = CPU_PPC_970,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_970,
+            .flags       = PPC_FLAGS_970,
+            .msr_mask    = 0x900000000204FF36,
+        },
+#endif
+#if defined (TODO)
+        /* PowerPC 970FX (G5) */
+        {
+            .name        = "970fx",
+            .pvr         = CPU_PPC_970FX,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_970FX,
+            .flags       = PPC_FLAGS_970FX,
+            .msr_mask    = 0x800000000204FF36,
+        },
+#endif
+#if defined (TODO)
+        /* RS64 (Apache/A35) */
+        /* This one seems to support the whole POWER2 instruction set
+         * and the PowerPC 64 one.
+         */
+        {
+            .name        = "RS64",
+            .pvr         = CPU_PPC_RS64,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "Apache",
+            .pvr         = CPU_PPC_RS64,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "A35",
+            .pvr         = CPU_PPC_RS64,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* RS64-II (NorthStar/A50) */
+        {
+            .name        = "RS64-II",
+            .pvr         = CPU_PPC_RS64II,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "NortStar",
+            .pvr         = CPU_PPC_RS64II,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "A50",
+            .pvr         = CPU_PPC_RS64II,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* RS64-III (Pulsar) */
+        {
+            .name        = "RS64-III",
+            .pvr         = CPU_PPC_RS64III,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "Pulsar",
+            .pvr         = CPU_PPC_RS64III,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* RS64-IV (IceStar/IStar/SStar) */
+        {
+            .name        = "RS64-IV",
+            .pvr         = CPU_PPC_RS64IV,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "IceStar",
+            .pvr         = CPU_PPC_RS64IV,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "IStar",
+            .pvr         = CPU_PPC_RS64IV,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+        {
+            .name        = "SStar",
+            .pvr         = CPU_PPC_RS64IV,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_RS64,
+            .flags       = PPC_FLAGS_RS64,
+            .msr_mask    = xxx,
+        },
+#endif
+        /* POWER */
+#if defined (TODO)
+        /* Original POWER */
+        {
+            .name        = "POWER",
+            .pvr         = CPU_POWER,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER,
+            .flags       = PPC_FLAGS_POWER,
+            .msr_mask    = xxx,
+        },
+#endif
+#if defined (TODO)
+        /* POWER2 */
+        {
+            .name        = "POWER2",
+            .pvr         = CPU_POWER2,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_POWER,
+            .flags       = PPC_FLAGS_POWER,
+            .msr_mask    = xxx,
+        },
+#endif
+        /* Generic PowerPCs */
+#if defined (TODO)
+        {
+            .name        = "ppc64",
+            .pvr         = CPU_PPC_970,
+            .pvr_mask    = 0xFFFF0000,
+            .insns_flags = PPC_INSNS_PPC64,
+            .flags       = PPC_FLAGS_PPC64,
+            .msr_mask    = 0xA00000000204FF36,
+        },
+#endif
+        {
+            .name        = "ppc32",
+            .pvr         = CPU_PPC_604,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_PPC32,
+            .flags       = PPC_FLAGS_PPC32,
+            .msr_mask    = 0x000000000005FF77,
+        },
+        /* Fallback */
+        {
+            .name        = "ppc",
+            .pvr         = CPU_PPC_604,
+            .pvr_mask    = 0xFFFFFFFF,
+            .insns_flags = PPC_INSNS_PPC32,
+            .flags       = PPC_FLAGS_PPC32,
+            .msr_mask    = 0x000000000005FF77,
+        },
+    };
 
 int ppc_find_by_name (const unsigned char *name, ppc_def_t **def)
 {
@@ -2058,7 +3730,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
     int i;
 
     for (i = 0; ; i++) {
-        (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n",
+        (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n",
                        ppc_defs[i].name,
                        ppc_defs[i].pvr, ppc_defs[i].pvr_mask);
         if (strcmp(ppc_defs[i].name, "ppc") == 0)