preliminary patch to support more PowerPC CPUs (Jocelyn Mayer)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 2 Jul 2005 20:59:34 +0000 (20:59 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 2 Jul 2005 20:59:34 +0000 (20:59 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1489 c046a42c-6fe2-441c-8c8c-71466251a162

13 files changed:
Makefile.target
gdbstub.c
hw/ppc_chrp.c
hw/ppc_prep.c
linux-user/main.c
target-ppc/cpu.h
target-ppc/exec.h
target-ppc/helper.c
target-ppc/op.c
target-ppc/op_helper.c
target-ppc/op_template.h
target-ppc/translate.c
target-ppc/translate_init.c [new file with mode: 0644]

index c2fed53..59ce7eb 100644 (file)
@@ -468,6 +468,7 @@ endif
 ifeq ($(TARGET_ARCH), ppc)
 op.o: op.c op_template.h op_mem.h
 op_helper.o: op_helper_mem.h
+translate.o: translate.c translate_init.c
 endif
 
 ifeq ($(TARGET_ARCH), mips)
index 5586df2..cbae320 100644 (file)
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -253,14 +253,14 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
     registers[96] = tswapl(env->nip);
-    registers[97] = tswapl(_load_msr(env));
+    registers[97] = tswapl(do_load_msr(env));
     tmp = 0;
     for (i = 0; i < 8; i++)
         tmp |= env->crf[i] << (32 - ((i + 1) * 4));
     registers[98] = tswapl(tmp);
     registers[99] = tswapl(env->lr);
     registers[100] = tswapl(env->ctr);
-    registers[101] = tswapl(_load_xer(env));
+    registers[101] = tswapl(do_load_xer(env));
     registers[102] = 0;
 
     return 103 * 4;
@@ -282,13 +282,13 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
     }
     /* nip, msr, ccr, lnk, ctr, xer, mq */
     env->nip = tswapl(registers[96]);
-    _store_msr(env, tswapl(registers[97]));
+    do_store_msr(env, tswapl(registers[97]));
     registers[98] = tswapl(registers[98]);
     for (i = 0; i < 8; i++)
         env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
     env->lr = tswapl(registers[99]);
     env->ctr = tswapl(registers[100]);
-    _store_xer(env, tswapl(registers[101]));
+    do_store_xer(env, tswapl(registers[101]));
 }
 #elif defined (TARGET_SPARC)
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
index cd0283c..4437911 100644 (file)
@@ -235,6 +235,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
     int ret, linux_boot, i;
     unsigned long bios_offset;
     uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+    ppc_def_t *def;
     PCIBus *pci_bus;
     const char *arch_name;
 
@@ -286,7 +287,26 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         initrd_size = 0;
     }
     /* Register CPU as a 74x/75x */
-    cpu_ppc_register(cpu_single_env, 0x00080000);
+    /* XXX: CPU model (or PVR) should be provided on command line */
+    //    ppc_find_by_name("750gx", &def); // Linux boot OK
+    //    ppc_find_by_name("750fx", &def); // Linux boot OK
+    /* Linux does not boot on 750cxe (and probably other 750cx based)
+     * because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
+     */
+    //    ppc_find_by_name("750cxe", &def);
+    //    ppc_find_by_name("750p", &def);
+    //    ppc_find_by_name("740p", &def);
+    ppc_find_by_name("750", &def);
+    //    ppc_find_by_name("740", &def);
+    //    ppc_find_by_name("G3", &def);
+    //    ppc_find_by_name("604r", &def);
+    //    ppc_find_by_name("604e", &def);
+    //    ppc_find_by_name("604", &def);
+    if (def == NULL) {
+        cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
+    }
+    cpu_ppc_register(cpu_single_env, def);
+
     /* Set time-base frequency to 10 Mhz */
     cpu_ppc_tb_init(cpu_single_env, 10UL * 1000UL * 1000UL);
 
index b287c6f..141fa1e 100644 (file)
@@ -527,6 +527,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
     int ret, linux_boot, i, nb_nics1;
     unsigned long bios_offset;
     uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
+    ppc_def_t *def;
     PCIBus *pci_bus;
 
     sysctrl = qemu_mallocz(sizeof(sysctrl_t));
@@ -582,7 +583,14 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
     }
 
     /* Register CPU as a 604 */
-    cpu_ppc_register(cpu_single_env, 0x00040000);
+    /* XXX: CPU model (or PVR) should be provided on command line */
+    //    ppc_find_by_name("604r", &def);
+    //    ppc_find_by_name("604e", &def);
+    ppc_find_by_name("604", &def);
+    if (def == NULL) {
+        cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
+    }
+    cpu_ppc_register(cpu_single_env, def);
     /* Set time-base frequency to 100 Mhz */
     cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
 
index 5601a23..d8fd0e4 100644 (file)
@@ -700,10 +700,11 @@ void cpu_loop(CPUPPCState *env)
             info._sifields._sigfault._addr = env->nip - 4;
             queue_signal(info.si_signo, &info);
         case EXCP_DSI:
-            fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
+            fprintf(stderr, "Invalid data memory access: 0x%08x\n",
+                    env->spr[SPR_DAR]);
             if (loglevel) {
                 fprintf(logfile, "Invalid data memory access: 0x%08x\n",
-                        env->spr[DAR]);
+                        env->spr[SPR_DAR]);
             }
             switch (env->error_code & 0xF) {
             case EXCP_DSI_TRANSLATE:
@@ -1243,7 +1244,25 @@ int main(int argc, char **argv)
     }
 #elif defined(TARGET_PPC)
     {
+        ppc_def_t *def;
         int i;
+
+        /* Choose and initialise CPU */
+        /* XXX: CPU model (or PVR) should be provided on command line */
+        //        ppc_find_by_name("750gx", &def);
+        //        ppc_find_by_name("750fx", &def);
+        //        ppc_find_by_name("750p", &def);
+        ppc_find_by_name("750", &def);
+        //        ppc_find_by_name("G3", &def);
+        //        ppc_find_by_name("604r", &def);
+        //        ppc_find_by_name("604e", &def);
+        //        ppc_find_by_name("604", &def);
+        if (def == NULL) {
+            cpu_abort(cpu_single_env,
+                      "Unable to find PowerPC CPU definition\n");
+        }
+        cpu_ppc_register(cpu_single_env, def);
+
         for (i = 0; i < 32; i++) {
             if (i != 12 && i != 6 && i != 13)
                 env->msr[i] = (regs->msr >> i) & 1;
index 7df0c62..a7b4051 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation cpu definitions for qemu.
+ *  PowerPC emulation cpu definitions for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #if !defined (__CPU_PPC_H__)
 #define __CPU_PPC_H__
 
+#include "config.h"
+
 #define TARGET_LONG_BITS 32
 
 #include "cpu-defs.h"
 
-#include "config.h"
 #include <setjmp.h>
 
 #include "softfloat.h"
 
 #define TARGET_HAS_ICE 1
 
+/*****************************************************************************/
+/* PVR definitions for most known PowerPC */
+enum {
+    /* PowerPC 401 cores */
+    CPU_PPC_401A1     = 0x00210000,
+    CPU_PPC_401B2     = 0x00220000,
+    CPU_PPC_401C2     = 0x00230000,
+    CPU_PPC_401D2     = 0x00240000,
+    CPU_PPC_401E2     = 0x00250000,
+    CPU_PPC_401F2     = 0x00260000,
+    CPU_PPC_401G2     = 0x00270000,
+    CPU_PPC_IOP480    = 0x40100000,
+    /* PowerPC 403 cores */
+    CPU_PPC_403GA     = 0x00200000,
+    CPU_PPC_403GB     = 0x00200100,
+    CPU_PPC_403GC     = 0x00200200,
+    CPU_PPC_403GCX    = 0x00201400,
+    /* PowerPC 405 cores */
+    CPU_PPC_405       = 0x40110000,
+    CPU_PPC_405EP     = 0x51210000,
+    CPU_PPC_405GPR    = 0x50910000,
+    CPU_PPC_405D2     = 0x20010000,
+    CPU_PPC_405D4     = 0x41810000,
+    CPU_PPC_NPE405H   = 0x41410000,
+    CPU_PPC_NPE405L   = 0x41610000,
+#if 0
+    CPU_PPC_STB02     = xxx,
+#endif
+    CPU_PPC_STB03     = 0x40310000,
+#if 0
+    CPU_PPC_STB04     = xxx,
+#endif
+    CPU_PPC_STB25     = 0x51510000,
+#if 0
+    CPU_PPC_STB130    = xxx,
+#endif
+    /* 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_8xx       = 0x00500000,
+    CPU_PPC_8240      = 0x00810100,
+    CPU_PPC_8245      = 0x00811014,
+    /* 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_604       = 0x00040000,
+    CPU_PPC_604E      = 0x00090000,
+    CPU_PPC_604R      = 0x000a0000,
+    /* PowerPC 74x/75x cores (aka G3) */
+    CPU_PPC_74x       = 0x00080000,
+    CPU_PPC_755       = 0x00083000,
+    CPU_PPC_74xP      = 0x10080000,
+    CPU_PPC_750CXE22  = 0x00082202,
+    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,
+    /* PowerPC 74xx cores (aka G4) */
+    CPU_PPC_7400      = 0x000C0000,
+    CPU_PPC_7410      = 0x800C0000,
+    CPU_PPC_7441      = 0x80000200,
+    CPU_PPC_7450      = 0x80000000,
+    CPU_PPC_7451      = 0x80000203,
+    CPU_PPC_7455      = 0x80010000,
+    CPU_PPC_7457      = 0x80020000,
+    CPU_PPC_7457A     = 0x80030000,
+    /* 64 bits PowerPC */
+    CPU_PPC_620       = 0x00140000,
+    CPU_PPC_630       = 0x00400000,
+    CPU_PPC_631       = 0x00410000,
+    CPU_PPC_POWER4    = 0x00350000,
+    CPU_PPC_POWER4P   = 0x00380000,
+    CPU_PPC_POWER5    = 0x003A0000,
+    CPU_PPC_POWER5P   = 0x003B0000,
+    CPU_PPC_970       = 0x00390000,
+    CPU_PPC_970FX     = 0x003C0000,
+    CPU_PPC_RS64      = 0x00330000,
+    CPU_PPC_RS64II    = 0x00340000,
+    CPU_PPC_RS64III   = 0x00360000,
+    CPU_PPC_RS64IV    = 0x00370000,
+    /* Original POWER */
+    /* XXX: should be POWER (RIOS), RSC3308, RSC4608,
+     * POWER2 (RIOS2) & RSC2 (P2SC) here
+     */
+#if 0
+    CPU_POWER         = xxx,
+#endif
+#if 0
+    CPU_POWER2        = xxx,
+#endif
+};
+
+/* System version register (used on MPC 8xx) */
+enum {
+    PPC_SVR_8540      = 0x80300000,
+    PPC_SVR_8541E     = 0x807A0000,
+    PPC_SVR_8555E     = 0x80790000,
+    PPC_SVR_8560      = 0x80700000,
+};
+
+/*****************************************************************************/
 /* Instruction types */
 enum {
-    PPC_NONE     = 0x0000,
-    PPC_INTEGER  = 0x0001, /* CPU has integer operations instructions        */
-    PPC_FLOAT    = 0x0002, /* CPU has floating point operations instructions */
-    PPC_FLOW     = 0x0004, /* CPU has flow control instructions              */
-    PPC_MEM      = 0x0008, /* CPU has virtual memory instructions            */
-    PPC_RES      = 0x0010, /* CPU has ld/st with reservation instructions    */
-    PPC_CACHE    = 0x0020, /* CPU has cache control instructions             */
-    PPC_MISC     = 0x0040, /* CPU has spr/msr access instructions            */
-    PPC_EXTERN   = 0x0080, /* CPU has external control instructions          */
-    PPC_SEGMENT  = 0x0100, /* CPU has memory segment instructions            */
-    PPC_CACHE_OPT= 0x0200,
-    PPC_FLOAT_OPT= 0x0400,
-    PPC_MEM_OPT  = 0x0800,
+    PPC_NONE        = 0x00000000,
+    /* integer operations instructions             */
+    /* flow control instructions                   */
+    /* virtual memory instructions                 */
+    /* ld/st with reservation instructions         */
+    /* cache control instructions                  */
+    /* spr/msr access instructions                 */
+    PPC_INSNS_BASE  = 0x00000001,
+#define PPC_INTEGER PPC_INSNS_BASE
+#define PPC_FLOW    PPC_INSNS_BASE
+#define PPC_MEM     PPC_INSNS_BASE
+#define PPC_RES     PPC_INSNS_BASE
+#define PPC_CACHE   PPC_INSNS_BASE
+#define PPC_MISC    PPC_INSNS_BASE
+    /* floating point operations instructions      */
+    PPC_FLOAT       = 0x00000002,
+    /* more floating point operations instructions */
+    PPC_FLOAT_EXT   = 0x00000004,
+    /* external control instructions               */
+    PPC_EXTERN      = 0x00000008,
+    /* segment register access instructions        */
+    PPC_SEGMENT     = 0x00000010,
+    /* Optional cache control instructions         */
+    PPC_CACHE_OPT   = 0x00000020,
+    /* Optional floating point op instructions     */
+    PPC_FLOAT_OPT   = 0x00000040,
+    /* Optional memory control instructions        */
+    PPC_MEM_TLBIA   = 0x00000080,
+    PPC_MEM_TLBIE   = 0x00000100,
+    PPC_MEM_TLBSYNC = 0x00000200,
+    /* eieio & sync                                */
+    PPC_MEM_SYNC    = 0x00000400,
+    /* PowerPC 6xx TLB management instructions     */
+    PPC_6xx_TLB     = 0x00000800,
+    /* Altivec support                             */
+    PPC_ALTIVEC     = 0x00001000,
+    /* Time base support                           */
+    PPC_TB          = 0x00002000,
+    /* Embedded PowerPC dedicated instructions     */
+    PPC_4xx_COMMON  = 0x00004000,
+    /* PowerPC 40x exception model                 */
+    PPC_40x_EXCP    = 0x00008000,
+    /* PowerPC 40x specific instructions           */
+    PPC_40x_SPEC    = 0x00010000,
+    /* PowerPC 405 Mac instructions                */
+    PPC_405_MAC     = 0x00020000,
+    /* PowerPC 440 specific instructions           */
+    PPC_440_SPEC    = 0x00040000,
+    /* Specific extensions */
+    /* Power-to-PowerPC bridge (601)               */
+    PPC_POWER_BR    = 0x00080000,
+    /* PowerPC 602 specific */
+    PPC_602_SPEC    = 0x00100000,
+    /* Deprecated instructions                     */
+    /* Original POWER instruction set              */
+    PPC_POWER       = 0x00200000,
+    /* POWER2 instruction set extension            */
+    PPC_POWER2      = 0x00400000,
+    /* Power RTC support */
+    PPC_POWER_RTC   = 0x00800000,
+    /* 64 bits PowerPC instructions                */
+    /* 64 bits PowerPC instruction set             */
+    PPC_64B         = 0x01000000,
+    /* 64 bits hypervisor extensions               */
+    PPC_64H         = 0x02000000,
+    /* 64 bits PowerPC "bridge" features           */
+    PPC_64_BRIDGE   = 0x04000000,
 };
 
-#define PPC_COMMON  (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM |           \
-                     PPC_RES | PPC_CACHE | PPC_MISC | PPC_SEGMENT)
-/* PPC 604 */
-#define PPC_604 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM |               \
-                 PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT    \
-                 PPC_MEM_OPT)
-/* PPC 740/745/750/755 (aka G3) has external access instructions */
-#define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM |               \
-                 PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT)
+/* CPU run-time flags (MMU and exception model) */
+enum {
+    /* MMU model */
+#define PPC_FLAGS_MMU_MASK (0x0000000F)
+    /* Standard 32 bits PowerPC MMU */
+    PPC_FLAGS_MMU_32B      = 0x00000000,
+    /* Standard 64 bits PowerPC MMU */
+    PPC_FLAGS_MMU_64B      = 0x00000001,
+    /* PowerPC 601 MMU */
+    PPC_FLAGS_MMU_601      = 0x00000002,
+    /* PowerPC 6xx MMU with software TLB */
+    PPC_FLAGS_MMU_SOFT_6xx = 0x00000003,
+    /* PowerPC 4xx MMU with software TLB */
+    PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
+    /* PowerPC 403 MMU */
+    PPC_FLAGS_MMU_403      = 0x00000005,
+    /* Exception model */
+#define PPC_FLAGS_EXCP_MASK (0x000000F0)
+    /* Standard PowerPC exception model */
+    PPC_FLAGS_EXCP_STD     = 0x00000000,
+    /* PowerPC 40x exception model */
+    PPC_FLAGS_EXCP_40x     = 0x00000010,
+    /* PowerPC 601 exception model */
+    PPC_FLAGS_EXCP_601     = 0x00000020,
+    /* PowerPC 602 exception model */
+    PPC_FLAGS_EXCP_602     = 0x00000030,
+    /* PowerPC 603 exception model */
+    PPC_FLAGS_EXCP_603     = 0x00000040,
+    /* PowerPC 604 exception model */
+    PPC_FLAGS_EXCP_604     = 0x00000050,
+    /* PowerPC 7x0 exception model */
+    PPC_FLAGS_EXCP_7x0     = 0x00000060,
+    /* PowerPC 7x5 exception model */
+    PPC_FLAGS_EXCP_7x5     = 0x00000070,
+    /* PowerPC 74xx exception model */
+    PPC_FLAGS_EXCP_74xx    = 0x00000080,
+    /* PowerPC 970 exception model */
+    PPC_FLAGS_EXCP_970     = 0x00000090,
+};
+
+#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK)
+#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK)
+
+/*****************************************************************************/
+/* Supported instruction set definitions */
+/* This generates an empty opcode table... */
+#define PPC_INSNS_TODO (PPC_NONE)
+#define PPC_FLAGS_TODO (0x00000000)
+
+/* PowerPC 40x instruction set */
+#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_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_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 | \
+                       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_FLAGS_440 (PPC_FLAGS_TODO)
+/* Non-embedded PowerPC */
+#define PPC_INSNS_COMMON  (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC |        \
+                           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)
+#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 |       \
+                       PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
+#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
+/* PowerPC G2 */
+#define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |        \
+                      PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
+#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
+/* PowerPC 604 */
+#define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
+                       PPC_MEM_TLBSYNC | PPC_TB)
+#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604)
+/* PowerPC 740/750 (aka G3) */
+#define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
+                       PPC_MEM_TLBSYNC | PPC_TB)
+#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0)
+/* PowerPC 745/755 */
+#define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
+                       PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB)
+#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5)
+/* PowerPC 74xx (aka G4) */
+#define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC |      \
+                        PPC_MEM_TLBSYNC | PPC_TB)
+#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx)
+
+/* Default PowerPC will be 604/970 */
+#define PPC_INSNS_PPC32 PPC_INSNS_604
+#define PPC_FLAGS_PPC32 PPC_FLAGS_604
+#if 0
+#define PPC_INSNS_PPC64 PPC_INSNS_970
+#define PPC_FLAGS_PPC64 PPC_FLAGS_970
+#endif
+#define PPC_INSNS_DEFAULT PPC_INSNS_604
+#define PPC_FLAGS_DEFAULT PPC_FLAGS_604
+typedef struct ppc_def_t ppc_def_t;
 
+/*****************************************************************************/
+/* Types used to describe some PowerPC registers */
+typedef struct CPUPPCState CPUPPCState;
+typedef struct opc_handler_t opc_handler_t;
 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;
+
+/* 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);
+    void (*oea_read)(void *opaque, int spr_num);
+    void (*oea_write)(void *opaque, int spr_num);
+    const unsigned char *name;
+};
+
+/* Altivec registers (128 bits) */
+struct ppc_avr_t {
+    uint32_t u[4];
+};
 
-/* Supervisor mode registers */
-/* Machine state register */
-#define MSR_POW 18
-#define MSR_ILE 16
-#define MSR_EE  15
-#define MSR_PR  14
-#define MSR_FP  13
-#define MSR_ME  12
-#define MSR_FE0 11
-#define MSR_SE  10
-#define MSR_BE  9
-#define MSR_FE1 8
-#define MSR_IP 6
-#define MSR_IR 5
-#define MSR_DR 4
-#define MSR_RI 1
-#define MSR_LE 0
+/* 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;
+};
+
+/*****************************************************************************/
+/* Machine state register bits definition                                    */
+#define MSR_SF   63 /* Sixty-four-bit mode                                   */
+#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_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_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_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_DWE  10 /* Debug wait enable on 405                              */
+#define MSR_BE   9  /* Branch trace enable                                   */
+#define MSR_DE   9  /* Debug interrupts enable on embedded PowerPC           */
+#define MSR_FE1  8  /* Floating point exception mode 1                       */
+#define MSR_AL   7  /* AL bit on POWER                                       */
+#define MSR_IP   6  /* Interrupt prefix                                      */
+#define MSR_IR   5  /* Instruction relocate                                  */
+#define MSR_IS   5  /* Instruction address space on embedded PowerPC         */
+#define MSR_DR   4  /* Data relocate                                         */
+#define MSR_DS   4  /* Data address space on embedded PowerPC                */
+#define MSR_PE   3  /* Protection enable on 403                              */
+#define MSR_EP   3  /* Exception prefix on 601                               */
+#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_sf   env->msr[MSR_SF]
+#define msr_isf  env->msr[MSR_ISF]
+#define msr_hv   env->msr[MSR_HV]
+#define msr_vr   env->msr[MSR_VR]
+#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_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]
@@ -85,58 +424,72 @@ typedef struct ppc_tb_t ppc_tb_t;
 #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_de   env->msr[MSR_DE]
 #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_is   env->msr[MSR_IS]
 #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]
 
-/* Segment registers */
-typedef struct CPUPPCState {
+/*****************************************************************************/
+/* The whole PowerPC CPU context */
+struct CPUPPCState {
+    /* First are the most commonly used resources
+     * during translated code execution
+     */
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    /* temporary fixed-point registers
+     * used to emulate 64 bits target on 32 bits hosts
+     */
+    target_ulong t0, t1, t2;
+#endif
     /* general purpose registers */
-    uint32_t gpr[32];
-    /* floating point registers */
-    float64 fpr[32];
-    /* segment registers */
-    uint32_t sdr1;
-    uint32_t sr[16];
+    target_ulong gpr[32];
+    /* LR */
+    target_ulong lr;
+    /* CTR */
+    target_ulong ctr;
+    /* condition register */
+    uint8_t crf[8];
     /* XER */
-    uint8_t xer[4];
+    /* XXX: We use only 5 fields, but we want to keep the structure aligned */
+    uint8_t xer[8];
     /* Reservation address */
-    uint32_t reserve;
+    target_ulong reserve;
+
+    /* Those ones are used in supervisor mode only */
     /* machine state register */
-    uint8_t msr[32];
-    /* condition register */
-    uint8_t crf[8];
-    /* floating point status and control register */
-    uint8_t fpscr[8];
-    uint32_t nip;
-    /* special purpose registers */
-    uint32_t lr;
-    uint32_t ctr;
-    /* BATs */
-    uint32_t DBAT[2][8];
-    uint32_t IBAT[2][8];
-    /* all others */
-    uint32_t spr[1024];
-    /* qemu dedicated */
+    uint8_t msr[64];
+    /* temporary general purpose registers */
+    target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+
+    /* Floating point execution context */
      /* temporary float registers */
     float64 ft0;
     float64 ft1;
     float64 ft2;
     float_status fp_status;
+    /* floating point registers */
+    float64 fpr[32];
+    /* floating point status and control register */
+    uint8_t fpscr[8];
 
-    int interrupt_request;
-    jmp_buf jmp_env;
-    int exception_index;
-    int error_code;
+    /* soft mmu support */
+    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
+    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
+    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
     int access_type; /* when a memory exception occurs, the access
                         type is stored here */
-    int user_mode_only; /* user mode only simulation */
-    struct TranslationBlock *current_tb; /* currently executing TB */
-    /* soft mmu support */
     /* in order to avoid passing too many arguments to the memory
        write helpers, we store some rarely used information in the CPU
        context) */
@@ -144,17 +497,71 @@ typedef struct CPUPPCState {
                                    written */
     unsigned long mem_write_vaddr; /* target virtual addr at which the
                                       memory was written */
-    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
-    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
-    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
 
-    /* ice debug support */
-    uint32_t breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
+    /* MMU context */
+    /* Address space register */
+    target_ulong asr;
+    /* segment registers */
+    target_ulong sdr1;
+    target_ulong sr[16];
+    /* BATs */
+    int nb_BATs;
+    target_ulong DBAT[2][8];
+    target_ulong IBAT[2][8];
 
+    /* Other registers */
+    /* Special purpose registers */
+    target_ulong spr[1024];
+    /* Altivec registers */
+    ppc_avr_t avr[32];
+    uint32_t vscr;
+
+    /* Internal devices resources */
     /* Time base and decrementer */
     ppc_tb_t *tb_env;
+    /* Device control registers */
+    int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val);
+    int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val);
+    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];
+    /* 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,
+                          int is_user);
+    /* 403 dedicated access protection registers */
+    target_ulong pb[4];
+
+    /* Those resources are used during exception processing */
+    /* CPU model definition */
+    uint64_t msr_mask;
+    uint32_t flags;
+
+    int exception_index;
+    int error_code;
+    int interrupt_request;
+
+    /* Those resources are used only during code translation */
+    /* Next instruction pointer */
+    target_ulong nip;
+    /* SPR translation callbacks */
+    ppc_spr_t spr_cb[1024];
+    /* opcode handlers */
+    opc_handler_t *opcodes[0x40];
+
+    /* Those resources are used only in Qemu core */
+    jmp_buf jmp_env;
+    int user_mode_only; /* user mode only simulation */
+    struct TranslationBlock *current_tb; /* currently executing TB */
+    uint32_t hflags;
+
+    /* ice debug support */
+    target_ulong breakpoints[MAX_BREAKPOINTS];
+    int nb_breakpoints;
+    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
 
     /* Power management */
     int power_mode;
@@ -164,8 +571,9 @@ typedef struct CPUPPCState {
 
     /* user data */
     void *opaque;
-} CPUPPCState;
+};
 
+/*****************************************************************************/
 CPUPPCState *cpu_ppc_init(void);
 int cpu_ppc_exec(CPUPPCState *s);
 void cpu_ppc_close(CPUPPCState *s);
@@ -181,12 +589,38 @@ void cpu_loop_exit(void);
 
 void dump_stack (CPUPPCState *env);
 
-uint32_t _load_xer (CPUPPCState *env);
-void _store_xer (CPUPPCState *env, uint32_t value);
-uint32_t _load_msr (CPUPPCState *env);
-void _store_msr (CPUPPCState *env, uint32_t value);
+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);
+void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value);
+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);
+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);
 
-int cpu_ppc_register (CPUPPCState *env, uint32_t pvr);
+int ppc_find_by_name (const unsigned char *name, ppc_def_t **def);
+int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def);
+void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def);
 
 /* Time-base and decrementer management */
 #ifndef NO_CPU_IO_DEFS
@@ -201,132 +635,276 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
 #define TARGET_PAGE_BITS 12
 #include "cpu-all.h"
 
+/*****************************************************************************/
+/* Registers definitions */
 #define ugpr(n) (env->gpr[n])
-#define fprd(n) (env->fpr[n])
-#define fprs(n) ((float)env->fpr[n])
-#define fpru(n) ((uint32_t)env->fpr[n])
-#define fpri(n) ((int32_t)env->fpr[n])
-
-#define SPR_ENCODE(sprn)                               \
-(((sprn) >> 5) | (((sprn) & 0x1F) << 5))
 
-/* User mode SPR */
-#define spr(n) env->spr[n]
 #define XER_SO 31
 #define XER_OV 30
 #define XER_CA 29
+#define XER_CMP 8
 #define XER_BC 0
-#define xer_so env->xer[3]
-#define xer_ov env->xer[2]
-#define xer_ca env->xer[1]
+#define xer_so  env->xer[4]
+#define xer_ov  env->xer[6]
+#define xer_ca  env->xer[2]
+#define xer_cmp env->xer[1]
 #define xer_bc env->xer[0]
 
-#define MQ     SPR_ENCODE(0)
-#define XER    SPR_ENCODE(1)
-#define RTCUR  SPR_ENCODE(4)
-#define RTCLR  SPR_ENCODE(5)
-#define LR     SPR_ENCODE(8)
-#define CTR    SPR_ENCODE(9)
-/* VEA mode SPR */
-#define V_TBL  SPR_ENCODE(268)
-#define V_TBU  SPR_ENCODE(269)
-/* supervisor mode SPR */
-#define DSISR  SPR_ENCODE(18)
-#define DAR    SPR_ENCODE(19)
-#define RTCUW  SPR_ENCODE(20)
-#define RTCLW  SPR_ENCODE(21)
-#define DECR   SPR_ENCODE(22)
-#define SDR1   SPR_ENCODE(25)
-#define SRR0   SPR_ENCODE(26)
-#define SRR1   SPR_ENCODE(27)
-#define SPRG0  SPR_ENCODE(272)
-#define SPRG1  SPR_ENCODE(273)
-#define SPRG2  SPR_ENCODE(274)
-#define SPRG3  SPR_ENCODE(275)
-#define SPRG4  SPR_ENCODE(276)
-#define SPRG5  SPR_ENCODE(277)
-#define SPRG6  SPR_ENCODE(278)
-#define SPRG7  SPR_ENCODE(279)
-#define ASR    SPR_ENCODE(280)
-#define EAR    SPR_ENCODE(282)
-#define O_TBL  SPR_ENCODE(284)
-#define O_TBU  SPR_ENCODE(285)
-#define PVR    SPR_ENCODE(287)
-#define IBAT0U SPR_ENCODE(528)
-#define IBAT0L SPR_ENCODE(529)
-#define IBAT1U SPR_ENCODE(530)
-#define IBAT1L SPR_ENCODE(531)
-#define IBAT2U SPR_ENCODE(532)
-#define IBAT2L SPR_ENCODE(533)
-#define IBAT3U SPR_ENCODE(534)
-#define IBAT3L SPR_ENCODE(535)
-#define DBAT0U SPR_ENCODE(536)
-#define DBAT0L SPR_ENCODE(537)
-#define DBAT1U SPR_ENCODE(538)
-#define DBAT1L SPR_ENCODE(539)
-#define DBAT2U SPR_ENCODE(540)
-#define DBAT2L SPR_ENCODE(541)
-#define DBAT3U SPR_ENCODE(542)
-#define DBAT3L SPR_ENCODE(543)
-#define IBAT4U SPR_ENCODE(560)
-#define IBAT4L SPR_ENCODE(561)
-#define IBAT5U SPR_ENCODE(562)
-#define IBAT5L SPR_ENCODE(563)
-#define IBAT6U SPR_ENCODE(564)
-#define IBAT6L SPR_ENCODE(565)
-#define IBAT7U SPR_ENCODE(566)
-#define IBAT7L SPR_ENCODE(567)
-#define DBAT4U SPR_ENCODE(568)
-#define DBAT4L SPR_ENCODE(569)
-#define DBAT5U SPR_ENCODE(570)
-#define DBAT5L SPR_ENCODE(571)
-#define DBAT6U SPR_ENCODE(572)
-#define DBAT6L SPR_ENCODE(573)
-#define DBAT7U SPR_ENCODE(574)
-#define DBAT7L SPR_ENCODE(575)
-#define UMMCR0 SPR_ENCODE(936)
-#define UPMC1  SPR_ENCODE(937)
-#define UPMC2  SPR_ENCODE(938)
-#define USIA   SPR_ENCODE(939)
-#define UMMCR1 SPR_ENCODE(940)
-#define UPMC3  SPR_ENCODE(941)
-#define UPMC4  SPR_ENCODE(942)
-#define MMCR0  SPR_ENCODE(952)
-#define PMC1   SPR_ENCODE(953)
-#define PMC2   SPR_ENCODE(954)
-#define SIA    SPR_ENCODE(955)
-#define MMCR1  SPR_ENCODE(956)
-#define PMC3   SPR_ENCODE(957)
-#define PMC4   SPR_ENCODE(958)
-#define SDA    SPR_ENCODE(959)
-#define DMISS  SPR_ENCODE(976)
-#define DCMP   SPR_ENCODE(977)
-#define DHASH1 SPR_ENCODE(978)
-#define DHASH2 SPR_ENCODE(979)
-#define IMISS  SPR_ENCODE(980)
-#define ICMP   SPR_ENCODE(981)
-#define RPA    SPR_ENCODE(982)
-#define TCR    SPR_ENCODE(984)
-#define IBR    SPR_ENCODE(986)
-#define ESASRR SPR_ENCODE(987)
-#define SEBR   SPR_ENCODE(990)
-#define SER    SPR_ENCODE(991)
-#define HID0   SPR_ENCODE(1008)
-#define HID1   SPR_ENCODE(1009)
-#define IABR   SPR_ENCODE(1010)
-#define HID2   SPR_ENCODE(1011)
-#define DABR   SPR_ENCODE(1013)
-#define L2PM   SPR_ENCODE(1016)
-#define L2CR   SPR_ENCODE(1017)
-#define ICTC   SPR_ENCODE(1019)
-#define THRM1  SPR_ENCODE(1020)
-#define THRM2  SPR_ENCODE(1021)
-#define THRM3  SPR_ENCODE(1022)
-#define SP     SPR_ENCODE(1021)
-#define SPR_LP SPR_ENCODE(1022)
-#define DABR_MASK 0xFFFFFFF8
-#define FPECR  SPR_ENCODE(1022)
-#define PIR    SPR_ENCODE(1023)
+/* 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 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)
 
 /* Memory access type :
  * may be needed for precise access rights control and precise exceptions.
@@ -348,7 +926,7 @@ enum {
 /* Exceptions */
 enum {
     EXCP_NONE          = -1,
-    /* PPC hardware exceptions : exception vector / 0x100 */
+    /* PowerPC hardware exceptions : exception vector / 0x100 */
     EXCP_RESET         = 0x01, /* System reset                     */
     EXCP_MACHINE_CHECK = 0x02, /* Machine check exception          */
     EXCP_DSI           = 0x03, /* Impossible memory access         */
index ad21c56..e559d5c 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation definitions for qemu.
+ *  PowerPC emulation definitions for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -119,15 +119,6 @@ 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_load_cr (void);
-void do_store_cr (uint32_t mask);
-void do_load_xer (void);
-void do_store_xer (void);
-void do_load_msr (void);
-void do_store_msr (void);
-void do_load_fpscr (void);
-void do_store_fpscr (uint32_t mask);
-
 void do_sraw(void);
 
 void do_fctiw (void);
@@ -143,20 +134,9 @@ void do_fcmpo (void);
 
 void do_check_reservation (void);
 void do_icbi (void);
-void do_store_sr (uint32_t srnum);
-void do_store_ibat (int ul, int nr);
-void do_store_dbat (int ul, int nr);
 void do_tlbia (void);
 void do_tlbie (void);
 
-void dump_state (void);
-void dump_rfi (void);
-void dump_store_sr (int srnum);
-void dump_store_ibat (int ul, int nr);
-void dump_store_dbat (int ul, int nr);
-void dump_store_tb (int ul);
-void dump_update_tb(uint32_t param);
-
 static inline void env_to_regs(void)
 {
 }
index 52aad95..6ddc0f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation helpers for qemu.
+ *  PowerPC emulation helpers for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,7 +26,7 @@
 //#define ACCURATE_TLB_FLUSH
 
 /*****************************************************************************/
-/* PPC MMU emulation */
+/* PowerPC MMU emulation */
 
 /* Perform BAT hit & translation */
 static int get_bat (CPUState *env, uint32_t *real, int *prot,
@@ -580,7 +580,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
             if (rw)
                 error_code |= EXCP_DSI_STORE;
            /* Store fault address */
-           env->spr[DAR] = address;
+           env->spr[SPR_DAR] = address;
         }
 #if 0
         printf("%s: set exception to %d %02x\n",
@@ -593,25 +593,239 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
     return ret;
 }
 
-uint32_t _load_xer (CPUState *env)
+/*****************************************************************************/
+/* BATs management */
+#if !defined(FLUSH_ALL_TLBS)
+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);
+#endif
+    for (page = base; page != end; page += TARGET_PAGE_SIZE)
+        tlb_flush_page(env, page);
+#if defined (DEBUG_BATS)
+    if (loglevel != 0)
+        fprintf(logfile, "Flush done\n");
+#endif
+}
+#endif
+
+static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr,
+                                   target_ulong value)
+{
+#if defined (DEBUG_BATS)
+    if (loglevel != 0) {
+        fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n",
+                ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value,
+                (unsigned long)env->nip);
+    }
+#endif
+}
+
+target_ulong do_load_ibatu (CPUPPCState *env, int nr)
+{
+    return env->IBAT[0][nr];
+}
+
+target_ulong do_load_ibatl (CPUPPCState *env, int nr)
+{
+    return env->IBAT[1][nr];
+}
+
+void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+
+    dump_store_bat(env, 'I', 0, nr, value);
+    if (env->IBAT[0][nr] != value) {
+        mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->IBAT[0][nr], mask);
+#endif
+        /* When storing valid upper BAT, mask BEPI and BRPN
+         * and invalidate all TLBs covered by this BAT
+         */
+        mask = (value << 15) & 0x0FFE0000UL;
+        env->IBAT[0][nr] = (value & 0x00001FFFUL) |
+            (value & ~0x0001FFFFUL & ~mask);
+        env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
+            (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)
+        tlb_flush(env, 1);
+#endif
+    }
+}
+
+void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
+{
+    dump_store_bat(env, 'I', 1, nr, value);
+    env->IBAT[1][nr] = value;
+}
+
+target_ulong do_load_dbatu (CPUPPCState *env, int nr)
+{
+    return env->DBAT[0][nr];
+}
+
+target_ulong do_load_dbatl (CPUPPCState *env, int nr)
+{
+    return env->DBAT[1][nr];
+}
+
+void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
+{
+    target_ulong mask;
+
+    dump_store_bat(env, 'D', 0, nr, value);
+    if (env->DBAT[0][nr] != value) {
+        /* When storing valid upper BAT, mask BEPI and BRPN
+         * and invalidate all TLBs covered by this BAT
+         */
+        mask = (value << 15) & 0x0FFE0000UL;
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#endif
+        mask = (value << 15) & 0x0FFE0000UL;
+        env->DBAT[0][nr] = (value & 0x00001FFFUL) |
+            (value & ~0x0001FFFFUL & ~mask);
+        env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
+            (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
+#if !defined(FLUSH_ALL_TLBS)
+        do_invalidate_BAT(env, env->DBAT[0][nr], mask);
+#else
+        tlb_flush(env, 1);
+#endif
+    }
+}
+
+void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
+{
+    dump_store_bat(env, 'D', 1, nr, 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;
+}
+
+void do_store_sdr1 (CPUPPCState *env, target_ulong value)
+{
+#if defined (DEBUG_MMU)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value);
+    }
+#endif
+    if (env->sdr1 != value) {
+        env->sdr1 = value;
+        invalidate_all_tlbs(env);
+    }
+}
+
+target_ulong do_load_sr (CPUPPCState *env, int srnum)
+{
+    return env->sr[srnum];
+}
+
+void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
+{
+#if defined (DEBUG_MMU)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n",
+                __func__, srnum, (unsigned long)value, env->sr[srnum]);
+    }
+#endif
+    if (env->sr[srnum] != value) {
+        env->sr[srnum] = value;
+#if !defined(FLUSH_ALL_TLBS) && 0
+        {
+            target_ulong page, end;
+            /* Invalidate 256 MB of virtual memory */
+            page = (16 << 20) * srnum;
+            end = page + (16 << 20);
+            for (; page != end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+        }
+#else
+        invalidate_all_tlbs(env);
+#endif
+    }
+}
+
+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)
 {
     return (xer_so << XER_SO) |
         (xer_ov << XER_OV) |
         (xer_ca << XER_CA) |
-        (xer_bc << XER_BC);
+        (xer_bc << XER_BC) |
+        (xer_cmp << XER_CMP);
 }
 
-void _store_xer (CPUState *env, uint32_t value)
+void do_store_xer (CPUPPCState *env, uint32_t value)
 {
     xer_so = (value >> XER_SO) & 0x01;
     xer_ov = (value >> XER_OV) & 0x01;
     xer_ca = (value >> XER_CA) & 0x01;
-    xer_bc = (value >> XER_BC) & 0x3f;
+    xer_cmp = (value >> XER_CMP) & 0xFF;
+    xer_bc = (value >> XER_BC) & 0x3F;
 }
 
-uint32_t _load_msr (CPUState *env)
+target_ulong do_load_msr (CPUPPCState *env)
 {
-    return (msr_pow << MSR_POW) |
+    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) |
@@ -621,41 +835,141 @@ uint32_t _load_msr (CPUState *env)
         (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);
 }
 
-void _store_msr (CPUState *env, uint32_t value)
+void do_compute_hflags (CPUPPCState *env)
 {
-#ifdef ACCURATE_TLB_FLUSH
-    if (((value >> MSR_IR) & 0x01) != msr_ir ||
-        ((value >> MSR_DR) & 0x01) != msr_dr)
+    /* 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);
+}
+
+void do_store_msr (CPUPPCState *env, target_ulong value)
     {
-        /* Flush all tlb when changing translation mode or privilege level */
+    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
+         */
         tlb_flush(env, 1);
+        env->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
+#if 0
+    if (loglevel != 0) {
+        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;
+    do_compute_hflags(env);
+}
+
+float64 do_load_fpscr (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
 #endif
-    msr_pow = (value >> MSR_POW) & 0x03;
-    msr_ile = (value >> MSR_ILE) & 0x01;
-    msr_ee = (value >> MSR_EE) & 0x01;
-    msr_pr = (value >> MSR_PR) & 0x01;
-    msr_fp = (value >> MSR_FP) & 0x01;
-    msr_me = (value >> MSR_ME) & 0x01;
-    msr_fe0 = (value >> MSR_FE0) & 0x01;
-    msr_se = (value >> MSR_SE) & 0x01;
-    msr_be = (value >> MSR_BE) & 0x01;
-    msr_fe1 = (value >> MSR_FE1) & 0x01;
-    msr_ip = (value >> MSR_IP) & 0x01;
-    msr_ir = (value >> MSR_IR) & 0x01;
-    msr_dr = (value >> MSR_DR) & 0x01;
-    msr_ri = (value >> MSR_RI) & 0x01;
-    msr_le = (value >> MSR_LE) & 0x01;
-    /* XXX: should enter PM state if msr_pow has been set */
+    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);
+}
+
+/*****************************************************************************/
+/* Exception processing */
 #if defined (CONFIG_USER_ONLY)
 void do_interrupt (CPUState *env)
 {
@@ -675,7 +989,7 @@ void do_interrupt (CPUState *env)
     int excp;
 
     excp = env->exception_index;
-    msr = _load_msr(env);
+    msr = do_load_msr(env);
 #if defined (DEBUG_EXCEPTIONS)
     if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) 
     {
@@ -715,29 +1029,29 @@ void do_interrupt (CPUState *env)
          * when the fault has been detected
      */
        msr &= ~0xFFFF0000;
-       env->spr[DSISR] = 0;
+       env->spr[SPR_DSISR] = 0;
        if ((env->error_code & 0x0f) ==  EXCP_DSI_TRANSLATE)
-           env->spr[DSISR] |= 0x40000000;
+           env->spr[SPR_DSISR] |= 0x40000000;
        else if ((env->error_code & 0x0f) ==  EXCP_DSI_PROT)
-           env->spr[DSISR] |= 0x08000000;
+           env->spr[SPR_DSISR] |= 0x08000000;
        else if ((env->error_code & 0x0f) ==  EXCP_DSI_NOTSUP) {
-           env->spr[DSISR] |= 0x80000000;
+           env->spr[SPR_DSISR] |= 0x80000000;
            if (env->error_code & EXCP_DSI_DIRECT)
-               env->spr[DSISR] |= 0x04000000;
+               env->spr[SPR_DSISR] |= 0x04000000;
        }
        if (env->error_code & EXCP_DSI_STORE)
-           env->spr[DSISR] |= 0x02000000;
+           env->spr[SPR_DSISR] |= 0x02000000;
        if ((env->error_code & 0xF) == EXCP_DSI_DABR)
-           env->spr[DSISR] |= 0x00400000;
+           env->spr[SPR_DSISR] |= 0x00400000;
        if (env->error_code & EXCP_DSI_ECXW)
-           env->spr[DSISR] |= 0x00100000;
+           env->spr[SPR_DSISR] |= 0x00100000;
 #if defined (DEBUG_EXCEPTIONS)
        if (loglevel) {
            fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
-                   env->spr[DSISR], env->spr[DAR]);
+                   env->spr[SPR_DSISR], env->spr[SPR_DAR]);
        } else {
            printf("DSI exception: DSISR=0x%08x, DAR=0x%08x nip=0x%08x\n",
-                  env->spr[DSISR], env->spr[DAR], env->nip);
+                  env->spr[SPR_DSISR], env->spr[SPR_DAR], env->nip);
        }
 #endif
         goto store_next;
@@ -777,7 +1091,7 @@ void do_interrupt (CPUState *env)
     case EXCP_ALIGN:
         /* Store exception cause */
         /* Get rS/rD and rA from faulting opcode */
-        env->spr[DSISR] |=
+        env->spr[SPR_DSISR] |=
             (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
         /* data location address has been stored
          * when the fault has been detected
@@ -858,14 +1172,14 @@ void do_interrupt (CPUState *env)
         return;
     store_current:
         /* SRR0 is set to current instruction */
-        env->spr[SRR0] = (uint32_t)env->nip - 4;
+        env->spr[SPR_SRR0] = (uint32_t)env->nip - 4;
         break;
     store_next:
         /* SRR0 is set to next instruction */
-        env->spr[SRR0] = (uint32_t)env->nip;
+        env->spr[SPR_SRR0] = (uint32_t)env->nip;
         break;
     }
-    env->spr[SRR1] = msr;
+    env->spr[SPR_SRR1] = msr;
     /* reload MSR with correct bits */
     msr_pow = 0;
     msr_ee = 0;
@@ -879,6 +1193,7 @@ void do_interrupt (CPUState *env)
     msr_dr = 0;
     msr_ri = 0;
     msr_le = msr_ile;
+    do_compute_hflags(env);
     /* Jump to handler */
     env->nip = excp << 8;
     env->exception_index = EXCP_NONE;
index 8c8021e..38ed13a 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation micro-operations for qemu.
+ *  PowerPC emulation micro-operations for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #define REG 31
 #include "op_template.h"
 
-/* PPC state maintenance operations */
+/* PowerPC state maintenance operations */
 /* set_Rc0 */
 PPC_OP(set_Rc0)
 {
@@ -223,7 +223,7 @@ PPC_OP(load_srin)
 
 PPC_OP(store_srin)
 {
-    do_store_sr(T1 >> 28);
+    do_store_sr(env, ((uint32_t)T1 >> 28), T0);
     RETURN();
 }
 
@@ -235,7 +235,7 @@ PPC_OP(load_sdr1)
 
 PPC_OP(store_sdr1)
 {
-    regs->sdr1 = T0;
+    do_store_sdr1(env, T0);
     RETURN();
 }
 
@@ -247,13 +247,13 @@ PPC_OP(exit_tb)
 /* Load/store special registers */
 PPC_OP(load_cr)
 {
-    do_load_cr();
+    T0 = do_load_cr(env);
     RETURN();
 }
 
 PPC_OP(store_cr)
 {
-    do_store_cr(PARAM(1));
+    do_store_cr(env, T0, PARAM(1));
     RETURN();
 }
 
@@ -279,25 +279,25 @@ PPC_OP(load_xer_bc)
 
 PPC_OP(load_xer)
 {
-    do_load_xer();
+    T0 = do_load_xer(env);
     RETURN();
 }
 
 PPC_OP(store_xer)
 {
-    do_store_xer();
+    do_store_xer(env, T0);
     RETURN();
 }
 
 PPC_OP(load_msr)
 {
-    do_load_msr();
+    T0 = do_load_msr(env);
     RETURN();
 }
 
 PPC_OP(store_msr)
 {
-    do_store_msr();
+    do_store_msr(env, T0);
     RETURN();
 }
 
@@ -378,9 +378,20 @@ PPC_OP(load_ibat)
     T0 = regs->IBAT[PARAM(1)][PARAM(2)];
 }
 
-PPC_OP(store_ibat)
+void op_store_ibatu (void)
 {
-    do_store_ibat(PARAM(1), PARAM(2));
+    do_store_ibatu(env, PARAM1, T0);
+    RETURN();
+}
+
+void op_store_ibatl (void)
+{
+#if 1
+    env->IBAT[1][PARAM1] = T0;
+#else
+    do_store_ibatl(env, PARAM1, T0);
+#endif
+    RETURN();
 }
 
 PPC_OP(load_dbat)
@@ -388,21 +399,32 @@ PPC_OP(load_dbat)
     T0 = regs->DBAT[PARAM(1)][PARAM(2)];
 }
 
-PPC_OP(store_dbat)
+void op_store_dbatu (void)
+{
+    do_store_dbatu(env, PARAM1, T0);
+    RETURN();
+}
+
+void op_store_dbatl (void)
 {
-    do_store_dbat(PARAM(1), PARAM(2));
+#if 1
+    env->DBAT[1][PARAM1] = T0;
+#else
+    do_store_dbatl(env, PARAM1, T0);
+#endif
+    RETURN();
 }
 
 /* FPSCR */
 PPC_OP(load_fpscr)
 {
-    do_load_fpscr();
+    FT0 = do_load_fpscr(env);
     RETURN();
 }
 
 PPC_OP(store_fpscr)
 {
-    do_store_fpscr(PARAM(1));
+    do_store_fpscr(env, FT0, PARAM1);
     RETURN();
 }
 
@@ -1362,17 +1384,13 @@ PPC_OP(check_reservation)
 /* Return from interrupt */
 PPC_OP(rfi)
 {
-    regs->nip = regs->spr[SRR0] & ~0x00000003;
+    regs->nip = regs->spr[SPR_SRR0] & ~0x00000003;
 #if 1 // TRY
-    T0 = regs->spr[SRR1] & ~0xFFF00000;
+    T0 = regs->spr[SPR_SRR1] & ~0xFFF00000;
 #else
-    T0 = regs->spr[SRR1] & ~0xFFFF0000;
-#endif
-    do_store_msr();
-#if defined (DEBUG_OP)
-    dump_rfi();
+    T0 = regs->spr[SPR_SRR1] & ~0xFFFF0000;
 #endif
-    //    do_tlbia();
+    do_store_msr(env, T0);
     do_raise_exception(EXCP_RFI);
     RETURN();
 }
@@ -1420,3 +1438,9 @@ PPC_OP(tlbie)
     do_tlbie();
     RETURN();
 }
+
+void op_store_pir (void)
+{
+    env->spr[SPR_PIR] = T0 & 0x0000000FUL;
+    RETURN();
+}
index 3f5fb0b..670e278 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation helpers for qemu.
+ *  PowerPC emulation helpers for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -67,91 +67,6 @@ void do_raise_exception (uint32_t exception)
 
 /*****************************************************************************/
 /* Helpers for "fat" micro operations */
-/* Special registers load and store */
-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)) & 0xF;
-    }
-}
-
-void do_load_xer (void)
-{
-    T0 = (xer_so << XER_SO) |
-        (xer_ov << XER_OV) |
-        (xer_ca << XER_CA) |
-        (xer_bc << XER_BC);
-}
-
-void do_store_xer (void)
-{
-    xer_so = (T0 >> XER_SO) & 0x01;
-    xer_ov = (T0 >> XER_OV) & 0x01;
-    xer_ca = (T0 >> XER_CA) & 0x01;
-    xer_bc = (T0 >> XER_BC) & 0x3f;
-}
-
-void do_load_msr (void)
-{
-    T0 = (msr_pow << MSR_POW) |
-        (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_ip << MSR_IP) |
-        (msr_ir << MSR_IR) |
-        (msr_dr << MSR_DR) |
-        (msr_ri << MSR_RI) |
-        (msr_le << MSR_LE);
-}
-
-void do_store_msr (void)
-{
-#if 1 // TRY
-    if (((T0 >> MSR_IR) & 0x01) != msr_ir ||
-        ((T0 >> MSR_DR) & 0x01) != msr_dr ||
-        ((T0 >> MSR_PR) & 0x01) != msr_pr)
-    {
-        do_tlbia();
-    }
-#endif
-    msr_pow = (T0 >> MSR_POW) & 0x03;
-    msr_ile = (T0 >> MSR_ILE) & 0x01;
-    msr_ee = (T0 >> MSR_EE) & 0x01;
-    msr_pr = (T0 >> MSR_PR) & 0x01;
-    msr_fp = (T0 >> MSR_FP) & 0x01;
-    msr_me = (T0 >> MSR_ME) & 0x01;
-    msr_fe0 = (T0 >> MSR_FE0) & 0x01;
-    msr_se = (T0 >> MSR_SE) & 0x01;
-    msr_be = (T0 >> MSR_BE) & 0x01;
-    msr_fe1 = (T0 >> MSR_FE1) & 0x01;
-    msr_ip = (T0 >> MSR_IP) & 0x01;
-    msr_ir = (T0 >> MSR_IR) & 0x01;
-    msr_dr = (T0 >> MSR_DR) & 0x01;
-    msr_ri = (T0 >> MSR_RI) & 0x01;
-    msr_le = (T0 >> MSR_LE) & 0x01;
-}
-
 /* shift right arithmetic helper */
 void do_sraw (void)
 {
@@ -175,77 +90,6 @@ void do_sraw (void)
 }
 
 /* Floating point operations helpers */
-void do_load_fpscr (void)
-{
-    /* The 32 MSB of the target fpr are undefined.
-     * They'll be zero...
-     */
-    union {
-        double 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);
-}
-
 void do_fctiw (void)
 {
     union {
@@ -254,7 +98,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 PPC 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;
@@ -269,7 +113,7 @@ void do_fctiwz (void)
     } p;
 
     /* XXX: higher bits are not supposed to be significant.
-     *      to make tests easier, return the same as a real PPC 750 (aka G3)
+     *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
      */
     p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
     p.i |= 0xFFF80000ULL << 32;
@@ -455,116 +299,3 @@ void do_tlbie (void)
     tlb_flush_page(env, T0);
 }
 
-void do_store_sr (uint32_t srnum)
-{
-#if defined (DEBUG_OP)
-    dump_store_sr(srnum);
-#endif
-#if 0 // TRY
-    {
-        uint32_t base, page;
-        
-        base = srnum << 28;
-        for (page = base; page != base + 0x100000000; page += 0x1000)
-            tlb_flush_page(env, page);
-    }
-#else
-    tlb_flush(env, 1);
-#endif
-    env->sr[srnum] = T0;
-}
-
-/* For BATs, we may not invalidate any TLBs if the change is only on
- * protection bits for user mode.
- */
-void do_store_ibat (int ul, int nr)
-{
-#if defined (DEBUG_OP)
-    dump_store_ibat(ul, nr);
-#endif
-#if 0 // TRY
-    {
-        uint32_t base, length, page;
-
-        base = env->IBAT[0][nr];
-        length = (((base >> 2) & 0x000007FF) + 1) << 17;
-        base &= 0xFFFC0000;
-        for (page = base; page != base + length; page += 0x1000)
-            tlb_flush_page(env, page);
-    }
-#else
-    tlb_flush(env, 1);
-#endif
-    env->IBAT[ul][nr] = T0;
-}
-
-void do_store_dbat (int ul, int nr)
-{
-#if defined (DEBUG_OP)
-    dump_store_dbat(ul, nr);
-#endif
-#if 0 // TRY
-    {
-        uint32_t base, length, page;
-        base = env->DBAT[0][nr];
-        length = (((base >> 2) & 0x000007FF) + 1) << 17;
-        base &= 0xFFFC0000;
-        for (page = base; page != base + length; page += 0x1000)
-            tlb_flush_page(env, page);
-    }
-#else
-    tlb_flush(env, 1);
-#endif
-    env->DBAT[ul][nr] = T0;
-}
-
-/*****************************************************************************/
-/* Special helpers for debug */
-void dump_state (void)
-{
-    //    cpu_dump_state(env, stdout, fprintf, 0);
-}
-
-void dump_rfi (void)
-{
-#if 0
-    printf("Return from interrupt => 0x%08x\n", env->nip);
-    //    cpu_dump_state(env, stdout, fprintf, 0);
-#endif
-}
-
-void dump_store_sr (int srnum)
-{
-#if 0
-    printf("%s: reg=%d 0x%08x\n", __func__, srnum, T0);
-#endif
-}
-
-static void _dump_store_bat (char ID, int ul, int nr)
-{
-    printf("Set %cBAT%d%c to 0x%08x (0x%08x)\n",
-           ID, nr, ul == 0 ? 'u' : 'l', T0, env->nip);
-}
-
-void dump_store_ibat (int ul, int nr)
-{
-    _dump_store_bat('I', ul, nr);
-}
-
-void dump_store_dbat (int ul, int nr)
-{
-    _dump_store_bat('D', ul, nr);
-}
-
-void dump_store_tb (int ul)
-{
-    printf("Set TB%c to 0x%08x\n", ul == 0 ? 'L' : 'U', T0);
-}
-
-void dump_update_tb(uint32_t param)
-{
-#if 0
-    printf("Update TB: 0x%08x + %d => 0x%08x\n", T1, param, T0);
-#endif
-}
-
index 338b7aa..1be640d 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation micro-operations for qemu.
+ *  PowerPC emulation micro-operations for qemu.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -175,7 +175,7 @@ void OPPROTO glue(op_load_sr, REG)(void)
 
 void OPPROTO glue(op_store_sr, REG)(void)
 {
-    do_store_sr(REG);
+    do_store_sr(env, REG, T0);
     RETURN();
 }
 #endif
index b2006df..52a28de 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *  PPC emulation for qemu: main translation routines.
+ *  PowerPC emulation for qemu: main translation routines.
  * 
- *  Copyright (c) 2003 Jocelyn Mayer
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -141,16 +141,17 @@ typedef struct DisasContext {
     int supervisor;
 #endif
     int fpu_enabled;
+    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
 } DisasContext;
 
-typedef struct opc_handler_t {
+struct opc_handler_t {
     /* invalid bits */
     uint32_t inval;
     /* instruction type */
     uint32_t type;
     /* handler */
     void (*handler)(DisasContext *ctx);
-} opc_handler_t;
+};
 
 #define RET_EXCP(ctx, excp, error)                                            \
 do {                                                                          \
@@ -173,6 +174,11 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
 #define RET_MTMSR(ctx)                                                        \
 RET_EXCP((ctx), EXCP_MTMSR, 0)
 
+static inline void RET_STOP (DisasContext *ctx)
+{
+    RET_EXCP(ctx, EXCP_MTMSR, 0);
+}
+
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
 static void gen_##name (DisasContext *ctx);                                   \
 GEN_OPCODE(name, opc1, opc2, opc3, inval, type);                              \
@@ -186,6 +192,7 @@ typedef struct opcode_t {
     unsigned char pad[1];
 #endif
     opc_handler_t handler;
+    const unsigned char *oname;
 } opcode_t;
 
 /***                           Instruction decoding                        ***/
@@ -226,7 +233,13 @@ EXTRACT_HELPER(crbD, 21, 5);
 EXTRACT_HELPER(crbA, 16, 5);
 EXTRACT_HELPER(crbB, 11, 5);
 /* SPR / TBL */
-EXTRACT_HELPER(SPR, 11, 10);
+EXTRACT_HELPER(_SPR, 11, 10);
+static inline uint32_t SPR (uint32_t opcode)
+{
+    uint32_t sprn = _SPR(opcode);
+
+    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+}
 /***                              Get constants                            ***/
 EXTRACT_HELPER(IMM, 12, 8);
 /* 16 bits signed immediate value */
@@ -282,12 +295,17 @@ static inline uint32_t MASK (uint32_t start, uint32_t end)
     return ret;
 }
 
+#if HOST_LONG_BITS == 64
+#define OPC_ALIGN 8
+#else
+#define OPC_ALIGN 4
+#endif
 #if defined(__APPLE__)
 #define OPCODES_SECTION \
-    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (8) ))
+    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
 #else
 #define OPCODES_SECTION \
-    __attribute__ ((section(".opcodes"), unused, aligned (8) ))
+    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
 #endif
 
 #define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
@@ -301,6 +319,7 @@ OPCODES_SECTION opcode_t opc_##name = {                                       \
         .type = _typ,                                                         \
         .handler = &gen_##name,                                               \
     },                                                                        \
+    .oname = stringify(name),                                                 \
 }
 
 #define GEN_OPCODE_MARK(name)                                                 \
@@ -314,6 +333,7 @@ OPCODES_SECTION opcode_t opc_##name = {                                       \
         .type = 0x00,                                                         \
         .handler = NULL,                                                      \
     },                                                                        \
+    .oname = stringify(name),                                                 \
 }
 
 /* Start opcode list */
@@ -1344,7 +1364,7 @@ static GenOpFunc1 *gen_op_stsw[] = {
 #endif
 
 /* lswi */
-/* PPC32 specification says we must generate an exception if
+/* PowerPC32 specification says we must generate an exception if
  * rA is in the range of registers to be loaded.
  * In an other hand, IBM says this is valid, but rA won't be loaded.
  * For now, I'll follow the spec...
@@ -1965,169 +1985,54 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
 #endif
 }
 
+#if 0
+#define SPR_NOACCESS ((void *)(-1))
+#else
+static void spr_noaccess (void *opaque, int sprn)
+{
+    sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
+    printf("ERROR: try to access SPR %d !\n", sprn);
+}
+#define SPR_NOACCESS (&spr_noaccess)
+#endif
+
 /* mfspr */
-GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
+static inline void gen_op_mfspr (DisasContext *ctx)
 {
+    void (*read_cb)(void *opaque, int sprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if defined(CONFIG_USER_ONLY)
-    switch (check_spr_access(sprn, 0, 0))
-#else
-    switch (check_spr_access(sprn, 0, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->supervisor)
+        read_cb = ctx->spr_cb[sprn].oea_read;
+    else
 #endif
-    {
-    case -1:
-        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
-        return;
-    case 0:
+        read_cb = ctx->spr_cb[sprn].uea_read;
+    if (read_cb != NULL) {
+        if (read_cb != SPR_NOACCESS) {
+            (*read_cb)(ctx, sprn);
+            gen_op_store_T0_gpr(rD(ctx->opcode));
+        } else {
+            /* Privilege exception */
+            printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
-        return;
-    default:
-        break;
         }
-    switch (sprn) {
-    case XER:
-        gen_op_load_xer();
-        break;
-    case LR:
-        gen_op_load_lr();
-        break;
-    case CTR:
-        gen_op_load_ctr();
-        break;
-    case IBAT0U:
-        gen_op_load_ibat(0, 0);
-        break;
-    case IBAT1U:
-        gen_op_load_ibat(0, 1);
-        break;
-    case IBAT2U:
-        gen_op_load_ibat(0, 2);
-        break;
-    case IBAT3U:
-        gen_op_load_ibat(0, 3);
-        break;
-    case IBAT4U:
-        gen_op_load_ibat(0, 4);
-        break;
-    case IBAT5U:
-        gen_op_load_ibat(0, 5);
-        break;
-    case IBAT6U:
-        gen_op_load_ibat(0, 6);
-        break;
-    case IBAT7U:
-        gen_op_load_ibat(0, 7);
-        break;
-    case IBAT0L:
-        gen_op_load_ibat(1, 0);
-        break;
-    case IBAT1L:
-        gen_op_load_ibat(1, 1);
-        break;
-    case IBAT2L:
-        gen_op_load_ibat(1, 2);
-        break;
-    case IBAT3L:
-        gen_op_load_ibat(1, 3);
-        break;
-    case IBAT4L:
-        gen_op_load_ibat(1, 4);
-        break;
-    case IBAT5L:
-        gen_op_load_ibat(1, 5);
-        break;
-    case IBAT6L:
-        gen_op_load_ibat(1, 6);
-        break;
-    case IBAT7L:
-        gen_op_load_ibat(1, 7);
-        break;
-    case DBAT0U:
-        gen_op_load_dbat(0, 0);
-        break;
-    case DBAT1U:
-        gen_op_load_dbat(0, 1);
-        break;
-    case DBAT2U:
-        gen_op_load_dbat(0, 2);
-        break;
-    case DBAT3U:
-        gen_op_load_dbat(0, 3);
-        break;
-    case DBAT4U:
-        gen_op_load_dbat(0, 4);
-        break;
-    case DBAT5U:
-        gen_op_load_dbat(0, 5);
-        break;
-    case DBAT6U:
-        gen_op_load_dbat(0, 6);
-        break;
-    case DBAT7U:
-        gen_op_load_dbat(0, 7);
-        break;
-    case DBAT0L:
-        gen_op_load_dbat(1, 0);
-        break;
-    case DBAT1L:
-        gen_op_load_dbat(1, 1);
-        break;
-    case DBAT2L:
-        gen_op_load_dbat(1, 2);
-        break;
-    case DBAT3L:
-        gen_op_load_dbat(1, 3);
-        break;
-    case DBAT4L:
-        gen_op_load_dbat(1, 4);
-        break;
-    case DBAT5L:
-        gen_op_load_dbat(1, 5);
-        break;
-    case DBAT6L:
-        gen_op_load_dbat(1, 6);
-        break;
-    case DBAT7L:
-        gen_op_load_dbat(1, 7);
-        break;
-    case SDR1:
-        gen_op_load_sdr1();
-        break;
-    case V_TBL:
-        gen_op_load_tbl();
-        break;
-    case V_TBU:
-        gen_op_load_tbu();
-        break;
-    case DECR:
-        gen_op_load_decr();
-        break;
-    default:
-        gen_op_load_spr(sprn);
-        break;
+    } else {
+        /* Not defined */
+        printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
-    gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
-/* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
+GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
 {
-    uint32_t sprn = SPR(ctx->opcode);
-
-        /* We need to update the time base before reading it */
-    switch (sprn) {
-    case V_TBL:
-        gen_op_load_tbl();
-        break;
-    case V_TBU:
-        gen_op_load_tbu();
-        break;
-    default:
-        RET_INVAL(ctx);
-        return;
+    gen_op_mfspr(ctx);
     }
-    gen_op_store_T0_gpr(rD(ctx->opcode));
+
+/* mftb */
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
+{
+    gen_op_mfspr(ctx);
 }
 
 /* mtcrf */
@@ -2158,184 +2063,28 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
 /* mtspr */
 GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
 {
+    void (*write_cb)(void *opaque, int sprn);
     uint32_t sprn = SPR(ctx->opcode);
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn),
-                rS(ctx->opcode), sprn);
-    }
-#endif
-#if defined(CONFIG_USER_ONLY)
-    switch (check_spr_access(sprn, 1, 0))
-#else
-    switch (check_spr_access(sprn, 1, ctx->supervisor))
+#if !defined(CONFIG_USER_ONLY)
+    if (ctx->supervisor)
+        write_cb = ctx->spr_cb[sprn].oea_write;
+    else
 #endif
-    {
-    case -1:
-        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
-        break;
-    case 0:
+        write_cb = ctx->spr_cb[sprn].uea_write;
+    if (write_cb != NULL) {
+        if (write_cb != SPR_NOACCESS) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            (*write_cb)(ctx, sprn);
+        } else {
+            /* Privilege exception */
+            printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
-        break;
-    default:
-        break;
     }
-    gen_op_load_gpr_T0(rS(ctx->opcode));
-    switch (sprn) {
-    case XER:
-        gen_op_store_xer();
-        break;
-    case LR:
-        gen_op_store_lr();
-        break;
-    case CTR:
-        gen_op_store_ctr();
-        break;
-    case IBAT0U:
-        gen_op_store_ibat(0, 0);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT1U:
-        gen_op_store_ibat(0, 1);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT2U:
-        gen_op_store_ibat(0, 2);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT3U:
-        gen_op_store_ibat(0, 3);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT4U:
-        gen_op_store_ibat(0, 4);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT5U:
-        gen_op_store_ibat(0, 5);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT6U:
-        gen_op_store_ibat(0, 6);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT7U:
-        gen_op_store_ibat(0, 7);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT0L:
-        gen_op_store_ibat(1, 0);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT1L:
-        gen_op_store_ibat(1, 1);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT2L:
-        gen_op_store_ibat(1, 2);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT3L:
-        gen_op_store_ibat(1, 3);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT4L:
-        gen_op_store_ibat(1, 4);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT5L:
-        gen_op_store_ibat(1, 5);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT6L:
-        gen_op_store_ibat(1, 6);
-        RET_MTMSR(ctx);
-        break;
-    case IBAT7L:
-        gen_op_store_ibat(1, 7);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT0U:
-        gen_op_store_dbat(0, 0);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT1U:
-        gen_op_store_dbat(0, 1);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT2U:
-        gen_op_store_dbat(0, 2);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT3U:
-        gen_op_store_dbat(0, 3);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT4U:
-        gen_op_store_dbat(0, 4);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT5U:
-        gen_op_store_dbat(0, 5);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT6U:
-        gen_op_store_dbat(0, 6);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT7U:
-        gen_op_store_dbat(0, 7);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT0L:
-        gen_op_store_dbat(1, 0);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT1L:
-        gen_op_store_dbat(1, 1);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT2L:
-        gen_op_store_dbat(1, 2);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT3L:
-        gen_op_store_dbat(1, 3);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT4L:
-        gen_op_store_dbat(1, 4);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT5L:
-        gen_op_store_dbat(1, 5);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT6L:
-        gen_op_store_dbat(1, 6);
-        RET_MTMSR(ctx);
-        break;
-    case DBAT7L:
-        gen_op_store_dbat(1, 7);
-        RET_MTMSR(ctx);
-        break;
-    case SDR1:
-        gen_op_store_sdr1();
-        RET_MTMSR(ctx);
-        break;
-    case O_TBL:
-        gen_op_store_tbl();
-        break;
-    case O_TBU:
-        gen_op_store_tbu();
-        break;
-    case DECR:
-        gen_op_store_decr();
-        break;
-    default:
-        gen_op_store_spr(sprn);
-        break;
+    } else {
+        /* Not defined */
+        printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
+        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
     }
 }
 
@@ -2514,7 +2263,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 /***                      Lookaside buffer management                      ***/
 /* Optional & supervisor only: */
 /* tlbia */
-GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
+GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
 {
 #if defined(CONFIG_USER_ONLY)
     RET_PRIVOPC(ctx);
@@ -2624,510 +2373,41 @@ GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
 /* End opcode list */
 GEN_OPCODE_MARK(end);
 
-/*****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-
-int fflush (FILE *stream);
-
-/* Main ppc opcodes table:
- * at init, all opcodes are invalids
- */
-static opc_handler_t *ppc_opcodes[0x40];
-
-/* Opcode types */
-enum {
-    PPC_DIRECT   = 0, /* Opcode routine        */
-    PPC_INDIRECT = 1, /* Indirect opcode table */
-};
-
-static inline int is_indirect_opcode (void *handler)
-{
-    return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
-}
-
-static inline opc_handler_t **ind_table(void *handler)
-{
-    return (opc_handler_t **)((unsigned long)handler & ~3);
-}
-
-/* Instruction table creation */
-/* Opcodes tables creation */
-static void fill_new_table (opc_handler_t **table, int len)
-{
-    int i;
-
-    for (i = 0; i < len; i++)
-        table[i] = &invalid_handler;
-}
-
-static int create_new_table (opc_handler_t **table, unsigned char idx)
-{
-    opc_handler_t **tmp;
-
-    tmp = malloc(0x20 * sizeof(opc_handler_t));
-    if (tmp == NULL)
-        return -1;
-    fill_new_table(tmp, 0x20);
-    table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
-
-    return 0;
-}
-
-static int insert_in_table (opc_handler_t **table, unsigned char idx,
-                            opc_handler_t *handler)
-{
-    if (table[idx] != &invalid_handler)
-        return -1;
-    table[idx] = handler;
-
-    return 0;
-}
-
-static int register_direct_insn (opc_handler_t **ppc_opcodes,
-                                 unsigned char idx, opc_handler_t *handler)
-{
-    if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
-        printf("*** ERROR: opcode %02x already assigned in main "
-                "opcode table\n", idx);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_ind_in_table (opc_handler_t **table,
-                                  unsigned char idx1, unsigned char idx2,
-                                  opc_handler_t *handler)
-{
-    if (table[idx1] == &invalid_handler) {
-        if (create_new_table(table, idx1) < 0) {
-            printf("*** ERROR: unable to create indirect table "
-                    "idx=%02x\n", idx1);
-            return -1;
-        }
-    } else {
-        if (!is_indirect_opcode(table[idx1])) {
-            printf("*** ERROR: idx %02x already assigned to a direct "
-                    "opcode\n", idx1);
-            return -1;
-        }
-    }
-    if (handler != NULL &&
-        insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
-        printf("*** ERROR: opcode %02x already assigned in "
-                "opcode table %02x\n", idx2, idx1);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_ind_insn (opc_handler_t **ppc_opcodes,
-                              unsigned char idx1, unsigned char idx2,
-                               opc_handler_t *handler)
-{
-    int ret;
-
-    ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
-
-    return ret;
-}
-
-static int register_dblind_insn (opc_handler_t **ppc_opcodes, 
-                                 unsigned char idx1, unsigned char idx2,
-                                  unsigned char idx3, opc_handler_t *handler)
-{
-    if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
-        printf("*** ERROR: unable to join indirect table idx "
-                "[%02x-%02x]\n", idx1, idx2);
-        return -1;
-    }
-    if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
-                              handler) < 0) {
-        printf("*** ERROR: unable to insert opcode "
-                "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
-        return -1;
-    }
-
-    return 0;
-}
-
-static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
-{
-    if (insn->opc2 != 0xFF) {
-        if (insn->opc3 != 0xFF) {
-            if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
-                                     insn->opc3, &insn->handler) < 0)
-                return -1;
-        } else {
-            if (register_ind_insn(ppc_opcodes, insn->opc1,
-                                  insn->opc2, &insn->handler) < 0)
-                return -1;
-        }
-    } else {
-        if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-static int test_opcode_table (opc_handler_t **table, int len)
-{
-    int i, count, tmp;
-
-    for (i = 0, count = 0; i < len; i++) {
-        /* Consistency fixup */
-        if (table[i] == NULL)
-            table[i] = &invalid_handler;
-        if (table[i] != &invalid_handler) {
-            if (is_indirect_opcode(table[i])) {
-                tmp = test_opcode_table(ind_table(table[i]), 0x20);
-                if (tmp == 0) {
-                    free(table[i]);
-                    table[i] = &invalid_handler;
-                } else {
-                    count++;
-                }
-            } else {
-                count++;
-            }
-        }
-    }
-
-    return count;
-}
-
-static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
-{
-    if (test_opcode_table(ppc_opcodes, 0x40) == 0)
-        printf("*** WARNING: no opcode defined !\n");
-}
-
-#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw)))
-#define SPR_UR SPR_RIGHTS(0, 0)
-#define SPR_UW SPR_RIGHTS(1, 0)
-#define SPR_SR SPR_RIGHTS(0, 1)
-#define SPR_SW SPR_RIGHTS(1, 1)
-
-#define spr_set_rights(spr, rights)                            \
-do {                                                           \
-    spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
-} while (0)
-
-static void init_spr_rights (uint32_t pvr)
-{
-    /* XER    (SPR 1) */
-    spr_set_rights(XER,    SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* LR     (SPR 8) */
-    spr_set_rights(LR,     SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* CTR    (SPR 9) */
-    spr_set_rights(CTR,    SPR_UR | SPR_UW | SPR_SR | SPR_SW);
-    /* TBL    (SPR 268) */
-    spr_set_rights(V_TBL,  SPR_UR | SPR_SR);
-    /* TBU    (SPR 269) */
-    spr_set_rights(V_TBU,  SPR_UR | SPR_SR);
-    /* DSISR  (SPR 18) */
-    spr_set_rights(DSISR,  SPR_SR | SPR_SW);
-    /* DAR    (SPR 19) */
-    spr_set_rights(DAR,    SPR_SR | SPR_SW);
-    /* DEC    (SPR 22) */
-    spr_set_rights(DECR,   SPR_SR | SPR_SW);
-    /* SDR1   (SPR 25) */
-    spr_set_rights(SDR1,   SPR_SR | SPR_SW);
-    /* SRR0   (SPR 26) */
-    spr_set_rights(SRR0,   SPR_SR | SPR_SW);
-    /* SRR1   (SPR 27) */
-    spr_set_rights(SRR1,   SPR_SR | SPR_SW);
-    /* SPRG0  (SPR 272) */
-    spr_set_rights(SPRG0,  SPR_SR | SPR_SW);
-    /* SPRG1  (SPR 273) */
-    spr_set_rights(SPRG1,  SPR_SR | SPR_SW);
-    /* SPRG2  (SPR 274) */
-    spr_set_rights(SPRG2,  SPR_SR | SPR_SW);
-    /* SPRG3  (SPR 275) */
-    spr_set_rights(SPRG3,  SPR_SR | SPR_SW);
-    /* ASR    (SPR 280) */
-    spr_set_rights(ASR,    SPR_SR | SPR_SW);
-    /* EAR    (SPR 282) */
-    spr_set_rights(EAR,    SPR_SR | SPR_SW);
-    /* TBL    (SPR 284) */
-    spr_set_rights(O_TBL,  SPR_SW);
-    /* TBU    (SPR 285) */
-    spr_set_rights(O_TBU,  SPR_SW);
-    /* PVR    (SPR 287) */
-    spr_set_rights(PVR,    SPR_SR);
-    /* IBAT0U (SPR 528) */
-    spr_set_rights(IBAT0U, SPR_SR | SPR_SW);
-    /* IBAT0L (SPR 529) */
-    spr_set_rights(IBAT0L, SPR_SR | SPR_SW);
-    /* IBAT1U (SPR 530) */
-    spr_set_rights(IBAT1U, SPR_SR | SPR_SW);
-    /* IBAT1L (SPR 531) */
-    spr_set_rights(IBAT1L, SPR_SR | SPR_SW);
-    /* IBAT2U (SPR 532) */
-    spr_set_rights(IBAT2U, SPR_SR | SPR_SW);
-    /* IBAT2L (SPR 533) */
-    spr_set_rights(IBAT2L, SPR_SR | SPR_SW);
-    /* IBAT3U (SPR 534) */
-    spr_set_rights(IBAT3U, SPR_SR | SPR_SW);
-    /* IBAT3L (SPR 535) */
-    spr_set_rights(IBAT3L, SPR_SR | SPR_SW);
-    /* DBAT0U (SPR 536) */
-    spr_set_rights(DBAT0U, SPR_SR | SPR_SW);
-    /* DBAT0L (SPR 537) */
-    spr_set_rights(DBAT0L, SPR_SR | SPR_SW);
-    /* DBAT1U (SPR 538) */
-    spr_set_rights(DBAT1U, SPR_SR | SPR_SW);
-    /* DBAT1L (SPR 539) */
-    spr_set_rights(DBAT1L, SPR_SR | SPR_SW);
-    /* DBAT2U (SPR 540) */
-    spr_set_rights(DBAT2U, SPR_SR | SPR_SW);
-    /* DBAT2L (SPR 541) */
-    spr_set_rights(DBAT2L, SPR_SR | SPR_SW);
-    /* DBAT3U (SPR 542) */
-    spr_set_rights(DBAT3U, SPR_SR | SPR_SW);
-    /* DBAT3L (SPR 543) */
-    spr_set_rights(DBAT3L, SPR_SR | SPR_SW);
-    /* FPECR  (SPR 1022) */
-    spr_set_rights(FPECR,  SPR_SR | SPR_SW);
-    /* Special registers for PPC 604 */
-    if ((pvr & 0xFFFF0000) == 0x00040000) {
-        /* IABR */
-        spr_set_rights(IABR ,  SPR_SR | SPR_SW);
-        /* DABR   (SPR 1013) */
-        spr_set_rights(DABR,   SPR_SR | SPR_SW);
-        /* HID0 */
-        spr_set_rights(HID0,   SPR_SR | SPR_SW);
-        /* PIR */
-    spr_set_rights(PIR,    SPR_SR | SPR_SW);
-        /* PMC1 */
-        spr_set_rights(PMC1,   SPR_SR | SPR_SW);
-        /* PMC2 */
-        spr_set_rights(PMC2,   SPR_SR | SPR_SW);
-        /* MMCR0 */
-        spr_set_rights(MMCR0,  SPR_SR | SPR_SW);
-        /* SIA */
-        spr_set_rights(SIA,    SPR_SR | SPR_SW);
-        /* SDA */
-        spr_set_rights(SDA,    SPR_SR | SPR_SW);
-    }
-    /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */
-    if ((pvr & 0xFFFF0000) == 0x00080000 ||
-        (pvr & 0xFFFF0000) == 0x70000000) {
-        /* HID0 */
-        spr_set_rights(HID0,   SPR_SR | SPR_SW);
-        /* HID1 */
-        spr_set_rights(HID1,   SPR_SR | SPR_SW);
-        /* IABR */
-        spr_set_rights(IABR,   SPR_SR | SPR_SW);
-        /* ICTC */
-        spr_set_rights(ICTC,   SPR_SR | SPR_SW);
-        /* L2CR */
-        spr_set_rights(L2CR,   SPR_SR | SPR_SW);
-        /* MMCR0 */
-        spr_set_rights(MMCR0,  SPR_SR | SPR_SW);
-        /* MMCR1 */
-        spr_set_rights(MMCR1,  SPR_SR | SPR_SW);
-        /* PMC1 */
-        spr_set_rights(PMC1,   SPR_SR | SPR_SW);
-        /* PMC2 */
-        spr_set_rights(PMC2,   SPR_SR | SPR_SW);
-        /* PMC3 */
-        spr_set_rights(PMC3,   SPR_SR | SPR_SW);
-        /* PMC4 */
-        spr_set_rights(PMC4,   SPR_SR | SPR_SW);
-        /* SIA */
-        spr_set_rights(SIA,    SPR_SR | SPR_SW);
-        /* SDA */
-        spr_set_rights(SDA,    SPR_SR | SPR_SW);
-        /* THRM1 */
-        spr_set_rights(THRM1,  SPR_SR | SPR_SW);
-        /* THRM2 */
-        spr_set_rights(THRM2,  SPR_SR | SPR_SW);
-        /* THRM3 */
-        spr_set_rights(THRM3,  SPR_SR | SPR_SW);
-        /* UMMCR0 */
-        spr_set_rights(UMMCR0, SPR_UR | SPR_UW);
-        /* UMMCR1 */
-        spr_set_rights(UMMCR1, SPR_UR | SPR_UW);
-        /* UPMC1 */
-        spr_set_rights(UPMC1,  SPR_UR | SPR_UW);
-        /* UPMC2 */
-        spr_set_rights(UPMC2,  SPR_UR | SPR_UW);
-        /* UPMC3 */
-        spr_set_rights(UPMC3,  SPR_UR | SPR_UW);
-        /* UPMC4 */
-        spr_set_rights(UPMC4,  SPR_UR | SPR_UW);
-        /* USIA */
-        spr_set_rights(USIA,   SPR_UR | SPR_UW);
-    }
-    /* MPC755 has special registers */
-    if (pvr == 0x00083100) {
-        /* SPRG4 */
-        spr_set_rights(SPRG4, SPR_SR | SPR_SW);
-        /* SPRG5 */
-        spr_set_rights(SPRG5, SPR_SR | SPR_SW);
-        /* SPRG6 */
-        spr_set_rights(SPRG6, SPR_SR | SPR_SW);
-        /* SPRG7 */
-        spr_set_rights(SPRG7, SPR_SR | SPR_SW);
-        /* IBAT4U */
-        spr_set_rights(IBAT4U, SPR_SR | SPR_SW);
-        /* IBAT4L */
-        spr_set_rights(IBAT4L, SPR_SR | SPR_SW);
-        /* IBAT5U */
-        spr_set_rights(IBAT5U, SPR_SR | SPR_SW);
-        /* IBAT5L */
-        spr_set_rights(IBAT5L, SPR_SR | SPR_SW);
-        /* IBAT6U */
-        spr_set_rights(IBAT6U, SPR_SR | SPR_SW);
-        /* IBAT6L */
-        spr_set_rights(IBAT6L, SPR_SR | SPR_SW);
-        /* IBAT7U */
-        spr_set_rights(IBAT7U, SPR_SR | SPR_SW);
-        /* IBAT7L */
-        spr_set_rights(IBAT7L, SPR_SR | SPR_SW);
-        /* DBAT4U */
-        spr_set_rights(DBAT4U, SPR_SR | SPR_SW);
-        /* DBAT4L */
-        spr_set_rights(DBAT4L, SPR_SR | SPR_SW);
-        /* DBAT5U */
-        spr_set_rights(DBAT5U, SPR_SR | SPR_SW);
-        /* DBAT5L */
-        spr_set_rights(DBAT5L, SPR_SR | SPR_SW);
-        /* DBAT6U */
-        spr_set_rights(DBAT6U, SPR_SR | SPR_SW);
-        /* DBAT6L */
-        spr_set_rights(DBAT6L, SPR_SR | SPR_SW);
-        /* DBAT7U */
-        spr_set_rights(DBAT7U, SPR_SR | SPR_SW);
-        /* DBAT7L */
-        spr_set_rights(DBAT7L, SPR_SR | SPR_SW);
-        /* DMISS */
-        spr_set_rights(DMISS,  SPR_SR | SPR_SW);
-        /* DCMP */
-        spr_set_rights(DCMP,   SPR_SR | SPR_SW);
-        /* DHASH1 */
-        spr_set_rights(DHASH1, SPR_SR | SPR_SW);
-        /* DHASH2 */
-        spr_set_rights(DHASH2, SPR_SR | SPR_SW);
-        /* IMISS */
-        spr_set_rights(IMISS,  SPR_SR | SPR_SW);
-        /* ICMP */
-        spr_set_rights(ICMP,   SPR_SR | SPR_SW);
-        /* RPA */
-        spr_set_rights(RPA,    SPR_SR | SPR_SW);
-        /* HID2 */
-        spr_set_rights(HID2,   SPR_SR | SPR_SW);
-        /* L2PM */
-        spr_set_rights(L2PM,   SPR_SR | SPR_SW);
-    }
-}
-
-/*****************************************************************************/
-/* PPC "main stream" common instructions (no optional ones) */
-
-typedef struct ppc_proc_t {
-    int flags;
-    void *specific;
-} ppc_proc_t;
-
-typedef struct ppc_def_t {
-    unsigned long pvr;
-    unsigned long pvr_mask;
-    ppc_proc_t *proc;
-} ppc_def_t;
-
-static ppc_proc_t ppc_proc_common = {
-    .flags    = PPC_COMMON,
-    .specific = NULL,
-};
-
-static ppc_proc_t ppc_proc_G3 = {
-    .flags    = PPC_750,
-    .specific = NULL,
-};
-
-static ppc_def_t ppc_defs[] =
-{
-    /* MPC740/745/750/755 (G3) */
-    {
-        .pvr      = 0x00080000,
-        .pvr_mask = 0xFFFF0000,
-        .proc     = &ppc_proc_G3,
-    },
-    /* IBM 750FX (G3 embedded) */
-    {
-        .pvr      = 0x70000000,
-        .pvr_mask = 0xFFFF0000,
-        .proc     = &ppc_proc_G3,
-    },
-    /* Fallback (generic PPC) */
-    {
-        .pvr      = 0x00000000,
-        .pvr_mask = 0x00000000,
-        .proc     = &ppc_proc_common,
-    },
-};
-
-static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr)
-{
-    opcode_t *opc, *start, *end;
-    int i, flags;
-
-    fill_new_table(ppc_opcodes, 0x40);
-    for (i = 0; ; i++) {
-        if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
-            (pvr & ppc_defs[i].pvr_mask)) {
-            flags = ppc_defs[i].proc->flags;
-            break;
-        }
-    }
-    
-    if (&opc_start < &opc_end) {
-       start = &opc_start;
-       end = &opc_end;
-    } else {
-       start = &opc_end;
-       end = &opc_start;
-    }
-    for (opc = start + 1; opc != end; opc++) {
-        if ((opc->handler.type & flags) != 0)
-            if (register_insn(ppc_opcodes, opc) < 0) {
-                printf("*** ERROR initializing PPC instruction "
-                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
-                        opc->opc3);
-                return -1;
-            }
-    }
-    fix_opcode_tables(ppc_opcodes);
-
-    return 0;
-}
-
+#include "translate_init.c"
 
 /*****************************************************************************/
-/* Misc PPC helpers */
-
+/* Misc PowerPC helpers */
 void cpu_dump_state(CPUState *env, FILE *f, 
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
+#if defined(TARGET_PPC64) || 1
+#define FILL ""
+#define REGX "%016llx"
+#define RGPL  4
+#define RFPL  4
+#else
+#define FILL "        "
+#define REGX "%08llx"
+#define RGPL  8
+#define RFPL  4
+#endif
+
     int i;
 
-    cpu_fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x "
-            "MSR=0x%08x\n", env->nip, env->lr, env->ctr,
-            _load_xer(env), _load_msr(env));
+    cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
+                env->nip, env->lr, env->ctr);
+    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      TB %08x %08x DECR %08x\n",
+                do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
+                cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
         for (i = 0; i < 32; i++) {
-            if ((i & 7) == 0)
-            cpu_fprintf(f, "GPR%02d:", i);
-        cpu_fprintf(f, " %08x", env->gpr[i]);
-            if ((i & 7) == 7)
+        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: 0x");
+    cpu_fprintf(f, "CR ");
         for (i = 0; i < 8; i++)
         cpu_fprintf(f, "%01x", env->crf[i]);
     cpu_fprintf(f, "  [");
@@ -3141,65 +2421,22 @@ void cpu_dump_state(CPUState *env, FILE *f,
                 a = 'E';
         cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
         }
-    cpu_fprintf(f, " ] ");
-    cpu_fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env),
-            cpu_ppc_load_tbl(env));
-        for (i = 0; i < 16; i++) {
-            if ((i & 3) == 0)
-            cpu_fprintf(f, "FPR%02d:", i);
+    cpu_fprintf(f, " ]             " FILL "RES " REGX "\n", env->reserve);
+    for (i = 0; i < 32; i++) {
+        if ((i & (RFPL - 1)) == 0)
+            cpu_fprintf(f, "FPR%02d", i);
         cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
-            if ((i & 3) == 3)
+        if ((i & (RFPL - 1)) == (RFPL - 1))
             cpu_fprintf(f, "\n");
     }
-    cpu_fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n",
-            env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env));
-    cpu_fprintf(f, "reservation 0x%08x\n", env->reserve);
-}
-
-CPUPPCState *cpu_ppc_init(void)
-{
-    CPUPPCState *env;
-
-    cpu_exec_init();
-
-    env = qemu_mallocz(sizeof(CPUPPCState));
-    if (!env)
-        return NULL;
-//    env->spr[PVR] = 0; /* Basic PPC */
-    env->spr[PVR] = 0x00080100; /* G3 CPU */
-//    env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */
-//    env->spr[PVR] = 0x00070100; /* IBM 750FX */
-    tlb_flush(env, 1);
-#if defined (DO_SINGLE_STEP)
-    /* Single step trace mode */
-    msr_se = 1;
-#endif
-    msr_fp = 1; /* Allow floating point exceptions */
-    msr_me = 1; /* Allow machine check exceptions  */
-#if defined(CONFIG_USER_ONLY)
-    msr_pr = 1;
-    cpu_ppc_register(env, 0x00080000);
-#else
-    env->nip = 0xFFFFFFFC;
-#endif
-    cpu_single_env = env;
-    return env;
-}
-
-int cpu_ppc_register (CPUPPCState *env, uint32_t pvr)
-{
-    env->spr[PVR] = pvr;
-    if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0)
-        return -1;
-    init_spr_rights(env->spr[PVR]);
+    cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX "         " FILL FILL FILL
+                "SDR1 " REGX "\n",
+                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
 
-    return 0;
-}
-
-void cpu_ppc_close(CPUPPCState *env)
-{
-    /* Should also remove all opcode tables... */
-    free(env);
+#undef REGX
+#undef RGPL
+#undef RFPL
+#undef FILL
 }
 
 /*****************************************************************************/
@@ -3219,6 +2456,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     ctx.nip = pc_start;
     ctx.tb = tb;
     ctx.exception = EXCP_NONE;
+    ctx.spr_cb = env->spr_cb;
 #if defined(CONFIG_USER_ONLY)
     ctx.mem_idx = msr_le;
 #else
@@ -3226,7 +2464,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
 #endif
     ctx.fpu_enabled = msr_fp;
-#if defined (DO_SINGLE_STEP)
+#if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
     msr_se = 1;
 #endif
@@ -3264,7 +2502,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
         }
 #endif
         ctx.nip += 4;
-        table = ppc_opcodes;
+        table = env->opcodes;
         handler = table[opc1(ctx.opcode)];
         if (is_indirect_opcode(handler)) {
             table = ind_table(handler);
@@ -3322,9 +2560,13 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
             RET_EXCP(ctxp, EXCP_TRACE, 0);
         }
         /* if we reach a page boundary, stop generation */
-        if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) 
+        if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
             break;
     }
+#if defined (DO_SINGLE_STEP)
+        break;
+#endif
+    }
     if (ctx.exception == EXCP_NONE) {
         gen_op_b((unsigned long)ctx.tb, ctx.nip);
     } else if (ctx.exception != EXCP_BRANCH) {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
new file mode 100644 (file)
index 0000000..624527d
--- /dev/null
@@ -0,0 +1,2069 @@
+/*
+ *  PowerPC CPU initialization for qemu.
+ * 
+ *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License 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
+ */
+
+/* A lot of PowerPC definition have been included here.
+ * Most of them are not usable for now but have been kept
+ * inside "#if defined(TODO) ... #endif" statements to make tests easier.
+ */
+
+//#define PPC_DUMP_CPU
+//#define PPC_DEBUG_SPR
+
+struct ppc_def_t {
+    const unsigned char *name;
+    uint32_t pvr;
+    uint32_t pvr_mask;
+    uint32_t insns_flags;
+    uint32_t flags;
+    uint64_t msr_mask;
+};
+
+/* Generic callbacks:
+ * do nothing but store/retrieve spr value
+ */
+static void spr_read_generic (void *opaque, int sprn)
+{
+    gen_op_load_spr(sprn);
+}
+
+static void spr_write_generic (void *opaque, int sprn)
+{
+    gen_op_store_spr(sprn);
+}
+
+/* SPR common to all PPC */
+/* XER */
+static void spr_read_xer (void *opaque, int sprn)
+{
+    gen_op_load_xer();
+}
+
+static void spr_write_xer (void *opaque, int sprn)
+{
+    gen_op_store_xer();
+}
+
+/* LR */
+static void spr_read_lr (void *opaque, int sprn)
+{
+    gen_op_load_lr();
+}
+
+static void spr_write_lr (void *opaque, int sprn)
+{
+    gen_op_store_lr();
+}
+
+/* CTR */
+static void spr_read_ctr (void *opaque, int sprn)
+{
+    gen_op_load_ctr();
+}
+
+static void spr_write_ctr (void *opaque, int sprn)
+{
+    gen_op_store_ctr();
+}
+
+/* User read access to SPR */
+/* USPRx */
+/* UMMCRx */
+/* UPMCx */
+/* USIA */
+/* UDECR */
+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) */
+/* DECR */
+static void spr_read_decr (void *opaque, int sprn)
+{
+    gen_op_load_decr();
+}
+
+static void spr_write_decr (void *opaque, int sprn)
+{
+    gen_op_store_decr();
+}
+
+/* SPR common to all non-embedded PPC, 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)
+{
+    gen_op_store_tbl();
+}
+
+static void spr_read_tbu (void *opaque, int sprn)
+{
+    gen_op_load_tbu();
+}
+
+static void spr_write_tbu (void *opaque, int sprn)
+{
+    gen_op_store_tbu();
+}
+
+/* IBAT0U...IBAT0U */
+/* IBAT0L...IBAT7L */
+static void spr_read_ibat (void *opaque, int sprn)
+{
+    gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_read_ibat_h (void *opaque, int sprn)
+{
+    gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT4U) / 2);
+}
+
+static void spr_write_ibatu (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_ibatu_h (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_ibatl (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_ibatl_h (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2);
+    RET_STOP(ctx);
+}
+
+/* DBAT0U...DBAT7U */
+/* DBAT0L...DBAT7L */
+static void spr_read_dbat (void *opaque, int sprn)
+{
+    gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT0U) / 2);
+}
+
+static void spr_read_dbat_h (void *opaque, int sprn)
+{
+    gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT4U) / 2);
+}
+
+static void spr_write_dbatu (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_dbatu_h (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_dbatl (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2);
+    RET_STOP(ctx);
+}
+
+static void spr_write_dbatl_h (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2);
+    RET_STOP(ctx);
+}
+
+/* SDR1 */
+static void spr_read_sdr1 (void *opaque, int sprn)
+{
+    gen_op_load_sdr1();
+}
+
+static void spr_write_sdr1 (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    gen_op_store_sdr1();
+    RET_STOP(ctx);
+}
+
+static void spr_write_pir (void *opaque, int sprn)
+{
+    gen_op_store_pir();
+}
+
+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),
+                                 void (*oea_read)(void *opaque, int sprn),
+                                 void (*oea_write)(void *opaque, int sprn),
+                                 target_ulong initial_value)
+{
+    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) {
+        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 %08llx\n", num, num, name,
+           (unsigned long long)initial_value);
+#endif
+    spr->name = name;
+    spr->uea_read = uea_read;
+    spr->uea_write = uea_write;
+    spr->oea_read = oea_read;
+    spr->oea_write = oea_write;
+    env->spr[num] = initial_value;
+}
+
+/* Generic PowerPC SPRs */
+static void gen_spr_generic (CPUPPCState *env)
+{
+    /* Integer processing */
+    spr_register(env, SPR_XER, "XER",
+                 &spr_read_xer, &spr_write_xer,
+                 &spr_read_xer, &spr_write_xer,
+                 0x00000000);
+    /* Branch contol */
+    spr_register(env, SPR_LR, "LR",
+                 &spr_read_lr, &spr_write_lr,
+                 &spr_read_lr, &spr_write_lr,
+                 0x00000000);
+    spr_register(env, SPR_CTR, "CTR",
+                 &spr_read_ctr, &spr_write_ctr,
+                 &spr_read_ctr, &spr_write_ctr,
+                 0x00000000);
+    /* Interrupt processing */
+    spr_register(env, SPR_SRR0, "SRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SRR1, "SRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Processor control */
+    spr_register(env, SPR_SPRG0, "SPRG0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG1, "SPRG1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG2, "SPRG2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG3, "SPRG3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR common to all non-embedded PowerPC, including 601 */
+static void gen_spr_ne_601 (CPUPPCState *env)
+{
+    /* Exception processing */
+    spr_register(env, SPR_DSISR, "DSISR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_DAR, "DAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    /* Memory management */
+    spr_register(env, SPR_SDR1, "SDR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_sdr1, &spr_write_sdr1,
+                 0x00000000);
+}
+
+/* BATs 0-3 */
+static void gen_low_BATs (CPUPPCState *env)
+{
+    spr_register(env, SPR_IBAT0U, "IBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT0L, "IBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1U, "IBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1L, "IBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2U, "IBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2L, "IBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3U, "IBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3L, "IBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat, &spr_write_ibatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT0U, "DBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT0L, "DBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT1U, "DBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT1L, "DBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT2U, "DBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT2L, "DBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    spr_register(env, SPR_DBAT3U, "DBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatu,
+                 0x00000000);
+    spr_register(env, SPR_DBAT3L, "DBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat, &spr_write_dbatl,
+                 0x00000000);
+    env->nb_BATs = 4;
+}
+
+/* BATs 4-7 */
+static void gen_high_BATs (CPUPPCState *env)
+{
+    spr_register(env, SPR_IBAT4U, "IBAT4U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT4L, "IBAT4L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT5U, "IBAT5U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT5L, "IBAT5L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT6U, "IBAT6U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT6L, "IBAT6L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT7U, "IBAT7U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatu_h,
+                 0x00000000);
+    spr_register(env, SPR_IBAT7L, "IBAT7L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_ibat_h, &spr_write_ibatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT4U, "DBAT4U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT4L, "DBAT4L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT5U, "DBAT5U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT5L, "DBAT5L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT6U, "DBAT6U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT6L, "DBAT6L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT7U, "DBAT7U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatu_h,
+                 0x00000000);
+    spr_register(env, SPR_DBAT7L, "DBAT7L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_dbat_h, &spr_write_dbatl_h,
+                 0x00000000);
+    env->nb_BATs = 8;
+}
+
+/* Generic PowerPC time base */
+static void gen_tbl (CPUPPCState *env)
+{
+    spr_register(env, SPR_VTBL,  "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_TBL,   "TBL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbl,
+                 0x00000000);
+    spr_register(env, SPR_VTBU,  "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_TBU,   "TBU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbu,
+                 0x00000000);
+}
+
+/* SPR common to all 7xx PowerPC implementations */
+static void gen_spr_7xx (CPUPPCState *env)
+{
+    /* 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_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Cache management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTC, "ICTC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Performance monitors */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR0, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR1, "MMCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC1, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC2, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC3, "PMC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC4, "PMC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SIA, "SIA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UMMCR0, "UMMCR0",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UMMCR1, "UMMCR1",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UPMC1, "UPMC1",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UPMC2, "UPMC2",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UPMC3, "UPMC3",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_UPMC4, "UPMC4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_USIA, "USIA",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Thermal management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM1, "THRM1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM2, "THRM2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_THRM3, "THRM3",
+                 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 specific to PowerPC 604 implementation */
+static void gen_spr_604 (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* Breakpoints */
+    /* 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_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Performance counters */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR0, "MMCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR1, "MMCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC1, "PMC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC2, "PMC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC3, "PMC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC4, "PMC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SIA, "SIA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SDA, "SDA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 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)
+{
+    /* 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",
+                 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;
+}
+
+#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];
+            sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
+            sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
+            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) {
+                printf("%4d (%03x) %8s s%c%c u%c%c\n",
+                       (i << 5) | j, (i << 5) | j, spr->name,
+                       sw ? 'w' : '-', sr ? 'r' : '-',
+                       uw ? 'w' : '-', ur ? 'r' : '-');
+            }
+        }
+    }
+    fflush(stdout);
+    fflush(stderr);
+}
+#endif
+
+/*****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+
+int fflush (FILE *stream);
+
+/* Opcode types */
+enum {
+    PPC_DIRECT   = 0, /* Opcode routine        */
+    PPC_INDIRECT = 1, /* Indirect opcode table */
+};
+
+static inline int is_indirect_opcode (void *handler)
+{
+    return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
+}
+
+static inline opc_handler_t **ind_table(void *handler)
+{
+    return (opc_handler_t **)((unsigned long)handler & ~3);
+}
+
+/* Instruction table creation */
+/* Opcodes tables creation */
+static void fill_new_table (opc_handler_t **table, int len)
+{
+    int i;
+
+    for (i = 0; i < len; i++)
+        table[i] = &invalid_handler;
+}
+
+static int create_new_table (opc_handler_t **table, unsigned char idx)
+{
+    opc_handler_t **tmp;
+
+    tmp = malloc(0x20 * sizeof(opc_handler_t));
+    if (tmp == NULL)
+        return -1;
+    fill_new_table(tmp, 0x20);
+    table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
+
+    return 0;
+}
+
+static int insert_in_table (opc_handler_t **table, unsigned char idx,
+                            opc_handler_t *handler)
+{
+    if (table[idx] != &invalid_handler)
+        return -1;
+    table[idx] = handler;
+
+    return 0;
+}
+
+static int register_direct_insn (opc_handler_t **ppc_opcodes,
+                                 unsigned char idx, opc_handler_t *handler)
+{
+    if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
+        printf("*** ERROR: opcode %02x already assigned in main "
+                "opcode table\n", idx);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_in_table (opc_handler_t **table,
+                                  unsigned char idx1, unsigned char idx2,
+                                  opc_handler_t *handler)
+{
+    if (table[idx1] == &invalid_handler) {
+        if (create_new_table(table, idx1) < 0) {
+            printf("*** ERROR: unable to create indirect table "
+                    "idx=%02x\n", idx1);
+            return -1;
+        }
+    } else {
+        if (!is_indirect_opcode(table[idx1])) {
+            printf("*** ERROR: idx %02x already assigned to a direct "
+                    "opcode\n", idx1);
+            return -1;
+        }
+    }
+    if (handler != NULL &&
+        insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
+        printf("*** ERROR: opcode %02x already assigned in "
+                "opcode table %02x\n", idx2, idx1);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_ind_insn (opc_handler_t **ppc_opcodes,
+                              unsigned char idx1, unsigned char idx2,
+                               opc_handler_t *handler)
+{
+    int ret;
+
+    ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
+
+    return ret;
+}
+
+static int register_dblind_insn (opc_handler_t **ppc_opcodes, 
+                                 unsigned char idx1, unsigned char idx2,
+                                  unsigned char idx3, opc_handler_t *handler)
+{
+    if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
+        printf("*** ERROR: unable to join indirect table idx "
+                "[%02x-%02x]\n", idx1, idx2);
+        return -1;
+    }
+    if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
+                              handler) < 0) {
+        printf("*** ERROR: unable to insert opcode "
+                "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
+{
+    if (insn->opc2 != 0xFF) {
+        if (insn->opc3 != 0xFF) {
+            if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
+                                     insn->opc3, &insn->handler) < 0)
+                return -1;
+        } else {
+            if (register_ind_insn(ppc_opcodes, insn->opc1,
+                                  insn->opc2, &insn->handler) < 0)
+                return -1;
+        }
+    } else {
+        if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+static int test_opcode_table (opc_handler_t **table, int len)
+{
+    int i, count, tmp;
+
+    for (i = 0, count = 0; i < len; i++) {
+        /* Consistency fixup */
+        if (table[i] == NULL)
+            table[i] = &invalid_handler;
+        if (table[i] != &invalid_handler) {
+            if (is_indirect_opcode(table[i])) {
+                tmp = test_opcode_table(ind_table(table[i]), 0x20);
+                if (tmp == 0) {
+                    free(table[i]);
+                    table[i] = &invalid_handler;
+                } else {
+                    count++;
+                }
+            } else {
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
+
+static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
+{
+    if (test_opcode_table(ppc_opcodes, 0x40) == 0)
+        printf("*** WARNING: no opcode defined !\n");
+}
+
+/*****************************************************************************/
+static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
+{
+    opcode_t *opc, *start, *end;
+
+    fill_new_table(env->opcodes, 0x40);
+#if defined(PPC_DUMP_CPU)
+    printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
+#endif
+    if (&opc_start < &opc_end) {
+       start = &opc_start;
+       end = &opc_end;
+    } else {
+       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);
+                return -1;
+            }
+#if defined(PPC_DUMP_CPU)
+            if (opc1 != 0x00) {
+                if (opc->opc3 == 0xFF) {
+                    if (opc->opc2 == 0xFF) {
+                        printf(" %02x -- -- (%2d ----) : %s\n",
+                               opc->opc1, opc->opc1, opc->oname);
+                    } else {
+                        printf(" %02x %02x -- (%2d %4d) : %s\n",
+                               opc->opc1, opc->opc2, opc->opc1, opc->opc2,
+                                    opc->oname);
+                    }
+                } else {
+                    printf(" %02x %02x %02x (%2d %4d) : %s\n",
+                           opc->opc1, opc->opc2, opc->opc3,
+                           opc->opc1, (opc->opc3 << 5) | opc->opc2,
+                           opc->oname);
+                }
+            }
+#endif
+        }
+    }
+    fix_opcode_tables(env->opcodes);
+    fflush(stdout);
+    fflush(stderr);
+
+    return 0;
+}
+
+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);
+        return -1;
+    }
+    init_ppc_proc(env, def);
+#if defined(PPC_DUMP_CPU)
+    dump_sprs(env);
+#endif
+    fflush(stdout);
+    fflush(stderr);
+
+    return 0;
+}
+
+CPUPPCState *cpu_ppc_init(void)
+{
+    CPUPPCState *env;
+
+    cpu_exec_init();
+
+    env = qemu_mallocz(sizeof(CPUPPCState));
+    if (!env)
+        return NULL;
+    tlb_flush(env, 1);
+#if defined (DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr_se = 1;
+    msr_be = 1;
+#endif
+    msr_fp = 1; /* Allow floating point exceptions */
+    msr_me = 1; /* Allow machine check exceptions  */
+#if defined(CONFIG_USER_ONLY)
+    msr_pr = 1;
+#else
+    env->nip = 0xFFFFFFFC;
+#endif
+    do_compute_hflags(env);
+    env->reserve = -1;
+    cpu_single_env = env;
+    return env;
+}
+
+void cpu_ppc_close(CPUPPCState *env)
+{
+    /* Should also remove all opcode tables... */
+    free(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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#endif
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#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,
+    },
+#endif
+    /* 64 bits PPC */
+#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,
+    },
+#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,
+    }
+#endif
+#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,
+    },
+#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)
+    /* PPC 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)
+    /* 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,
+    },
+#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    = 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,
+    },
+};
+
+int ppc_find_by_name (const unsigned char *name, ppc_def_t **def)
+{
+    int i, ret;
+
+    ret = -1;
+    *def = NULL;
+    for (i = 0; strcmp(ppc_defs[i].name, "ppc") != 0; i++) {
+        if (strcasecmp(name, ppc_defs[i].name) == 0) {
+            *def = &ppc_defs[i];
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def)
+{
+    int i, ret;
+
+    ret = -1;
+    *def = NULL;
+    for (i = 0; ppc_defs[i].name != NULL; i++) {
+        if ((pvr & ppc_defs[i].pvr_mask) ==
+            (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) {
+            *def = &ppc_defs[i];
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+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",
+                       ppc_defs[i].name,
+                       ppc_defs[i].pvr, ppc_defs[i].pvr_mask);
+        if (strcmp(ppc_defs[i].name, "ppc") == 0)
+            break;
+    }
+}