aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-07-02 20:59:34 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2005-07-02 20:59:34 +0000
commit3fc6c082e3aad85addf25d36740030982963c0c8 (patch)
tree04d750a5bdbdd36654df3fa52e58127de90b7eaf
parent2f636b458f6c5e40f8ab2615ae1e8a1cde7e86b8 (diff)
preliminary patch to support more PowerPC CPUs (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1489 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--Makefile.target1
-rw-r--r--gdbstub.c8
-rw-r--r--hw/ppc_chrp.c22
-rw-r--r--hw/ppc_prep.c10
-rw-r--r--linux-user/main.c23
-rw-r--r--target-ppc/cpu.h990
-rw-r--r--target-ppc/exec.h24
-rw-r--r--target-ppc/helper.c407
-rw-r--r--target-ppc/op.c74
-rw-r--r--target-ppc/op_helper.c277
-rw-r--r--target-ppc/op_template.h6
-rw-r--r--target-ppc/translate.c1010
-rw-r--r--target-ppc/translate_init.c2069
13 files changed, 3454 insertions, 1467 deletions
diff --git a/Makefile.target b/Makefile.target
index c2fed5342d..59ce7eb49a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -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)
diff --git a/gdbstub.c b/gdbstub.c
index 5586df29fb..cbae3208cf 100644
--- 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)
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index cd0283c5b6..4437911bd3 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -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);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index b287c6f918..141fa1eee6 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -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);
diff --git a/linux-user/main.c b/linux-user/main.c
index 5601a23e67..d8fd0e4087 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -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;
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 7df0c62691..a7b4051e1e 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -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
@@ -20,64 +20,403 @@
#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 */
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index ad21c56696..e559d5c8c4 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -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)
{
}
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 52aad95327..6ddc0f47ff 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -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;
diff --git a/target-ppc/op.c b/target-ppc/op.c
index 8c8021e1a6..38ed13aa13 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -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
@@ -130,7 +130,7 @@
#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();
+}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 3f5fb0bbcd..670e278947 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -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
-}
-
diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h
index 338b7aa239..1be640d6de 100644
--- a/target-ppc/op_template.h
+++ b/target-ppc/op_template.h
@@ -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
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index b2006df532..52a28def14 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -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
index 0000000000..624527d5f9
--- /dev/null
+++ b/target-ppc/translate_init.c
@@ -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;
+ }
+}