aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-07 08:32:30 +0000
committerj_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>2007-03-07 08:32:30 +0000
commit76a66253e5e48f1744f689041c1c21cedcaff630 (patch)
treec1003bd73ab8e2cbfe4a05c5b3f497bc2573fa4e /target-ppc
parent1c7b3754f68382941a1921e578ead25d97d116fb (diff)
Great PowerPC emulation code resynchronisation and improvments:
- Add status file to make regression tracking easier - Move all micro-operations helpers definitions into a separate header: should never be seen outside of op.c - Update copyrights - Add new / missing PowerPC CPU definitions - Add definitions for PowerPC BookE - Add support for PowerPC 6xx/7xx software driven TLBs Allow use of PowerPC 603 as an example - Add preliminary code for POWER, POWER2, PowerPC 403, 405, 440, 601, 602 and BookE support - Avoid compiling priviledged only resources support for user-mode emulation - Remove unused helpers / micro-ops / dead code - Add instructions usage statistics dump: useful to figure which instructions need strong optimizations. - Micro-operation fixes: * add missing RETURN in some micro-ops * fix prototypes * use softfloat routines for all floating-point operations * fix tlbie instruction * move some huge micro-operations into helpers - emulation fixes: * fix inverted opcodes for fcmpo / fcmpu * condition register update is always to be done after the whole instruction has completed * add missing NIP updates when calling helpers that may generate an exception - optimizations and improvments: * optimize very often used instructions (li, mr, rlwixx...) * remove specific micro-ops for rarely used instructions * add routines for addresses computations to avoid bugs due to multiple different implementations * fix TB linking: do not reset T0 at the end of every TB. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2473 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/STATUS91
-rw-r--r--target-ppc/cpu.h926
-rw-r--r--target-ppc/exec.h76
-rw-r--r--target-ppc/helper.c1089
-rw-r--r--target-ppc/mfrom_table.c79
-rw-r--r--target-ppc/mfrom_table_gen.c33
-rw-r--r--target-ppc/op.c896
-rw-r--r--target-ppc/op_helper.c696
-rw-r--r--target-ppc/op_helper.h132
-rw-r--r--target-ppc/op_helper_mem.h206
-rw-r--r--target-ppc/op_mem.h142
-rw-r--r--target-ppc/op_template.h73
-rw-r--r--target-ppc/translate.c2220
-rw-r--r--target-ppc/translate_init.c3394
14 files changed, 7529 insertions, 2524 deletions
diff --git a/target-ppc/STATUS b/target-ppc/STATUS
new file mode 100644
index 0000000000..d5089f766f
--- /dev/null
+++ b/target-ppc/STATUS
@@ -0,0 +1,91 @@
+PowerPC emulation status.
+The goal of this file is to provide a reference status to avoid regressions.
+
+===============================================================================
+PowerPC core emulation status
+
+PowerPC CPU known to work (ie booting at least Linux 2.4):
+* main stream PowerPC cores
+- PowerPC 603 & derivatives
+- PowerPC 604 & derivatives
+- PowerPC 740 & derivatives
+- PowerPC 750 & derivatives
+
+PowerPC that should work but are not supported by standard Linux kernel
+(then remain mostly untested)
+- PowerPC 745
+- PowerPC 755
+
+Work in progress:
+* embedded PowerPC cores
+- PowerPC 405
+- BookE PowerPC
+- e500 core (Freescale PowerQUICC)
+* main stream PowerPC cores
+- PowerPC 601
+- PowerPC 602
+
+TODO:
+* embedded PowerPC cores
+- PowerPC 401
+- PowerPC 403
+- PowerPC 440
+- PowerPC 460
+* main stream PowerPC cores
+- PowerPC 7400 (aka G4)
+- PowerPC 7410
+- PowerPC 7450
+- PowerPC 7455
+- PowerPC 7457
+- PowerPC 7457A
+* original POWER
+- POWER
+- POWER2
+* 64 bits PowerPC cores
+- PowerPC 620
+- PowerPC 630 (aka POWER3)
+- PowerPC 631 (aka POWER3+)
+- POWER4
+- POWER4+
+- POWER5
+- POWER5+
+- PowerPC 970
+* RS64 series
+- RS64
+- RS64-II
+- RS64-III
+- RS64-IV
+
+===============================================================================
+PowerPC microcontrollers emulation status
+
+TODO:
+- PowerPC 40x microcontrollers emulation
+- PowerQUICC microcontrollers emulation
+
+===============================================================================
+PowerPC based platforms emulation status
+
+* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* mac99 platform (white and blue PowerMac, ...)
+- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
+- Debian Linux woody - boots from CDROM and HDD
+- Mandrake Linux 9 - boots from CDROM, freezes during install
+
+TODO:
+- MCA based RS/6000 emulation
+- CHRP emulation (not PowerMac)
+- PPAR emulation
+- misc PowerPC reference boards emulation
+
+===============================================================================
+(to be completed)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b294e31468..8abb32492f 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1,7 +1,7 @@
/*
* PowerPC emulation cpu definitions for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,8 +21,22 @@
#define __CPU_PPC_H__
#include "config.h"
+#include <stdint.h>
+#if defined (TARGET_PPC64)
+typedef uint64_t ppc_gpr_t;
+#define TARGET_LONG_BITS 64
+#define REGX "%016" PRIx64
+#elif defined(TARGET_E500)
+/* GPR are 64 bits: used by vector extension */
+typedef uint64_t ppc_gpr_t;
#define TARGET_LONG_BITS 32
+#define REGX "%08" PRIx32
+#else
+typedef uint32_t ppc_gpr_t;
+#define TARGET_LONG_BITS 32
+#define REGX "%08" PRIx32
+#endif
#include "cpu-defs.h"
@@ -32,7 +46,11 @@
#define TARGET_HAS_ICE 1
-#define ELF_MACHINE EM_PPC
+#if defined (TARGET_PPC64)
+#define ELF_MACHINE EM_PPC64
+#else
+#define ELF_MACHINE EM_PPC
+#endif
/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
* have different cache line sizes
@@ -42,6 +60,7 @@
/* XXX: put this in a common place */
#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
/*****************************************************************************/
/* PVR definitions for most known PowerPC */
@@ -54,72 +73,155 @@ enum {
CPU_PPC_401E2 = 0x00250000,
CPU_PPC_401F2 = 0x00260000,
CPU_PPC_401G2 = 0x00270000,
- CPU_PPC_IOP480 = 0x40100000,
+#define CPU_PPC_401 CPU_PPC_401G2
+ CPU_PPC_IOP480 = 0x40100000, /* 401B2 ? */
+ CPU_PPC_COBRA = 0x10100000, /* IBM Processor for Network Resources */
/* PowerPC 403 cores */
- CPU_PPC_403GA = 0x00200000,
+ CPU_PPC_403GA = 0x00200011,
CPU_PPC_403GB = 0x00200100,
CPU_PPC_403GC = 0x00200200,
CPU_PPC_403GCX = 0x00201400,
+#define CPU_PPC_403 CPU_PPC_403GCX
/* PowerPC 405 cores */
- CPU_PPC_405 = 0x40110000,
- CPU_PPC_405EP = 0x51210000,
- CPU_PPC_405GPR = 0x50910000,
+ CPU_PPC_405CR = 0x40110145,
+#define CPU_PPC_405GP CPU_PPC_405CR
+ CPU_PPC_405EP = 0x51210950,
+ CPU_PPC_405GPR = 0x50910951,
CPU_PPC_405D2 = 0x20010000,
CPU_PPC_405D4 = 0x41810000,
- CPU_PPC_NPE405H = 0x41410000,
- CPU_PPC_NPE405L = 0x41610000,
+#define CPU_PPC_405 CPU_PPC_405D4
+ CPU_PPC_NPE405H = 0x414100C0,
+ CPU_PPC_NPE405H2 = 0x41410140,
+ CPU_PPC_NPE405L = 0x416100C0,
+ /* XXX: missing 405LP, LC77700 */
+ /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */
+#if 0
+ CPU_PPC_STB01000 = xxx,
+#endif
#if 0
- CPU_PPC_STB02 = xxx,
+ CPU_PPC_STB01010 = xxx,
+#endif
+#if 0
+ CPU_PPC_STB0210 = xxx,
#endif
CPU_PPC_STB03 = 0x40310000,
#if 0
- CPU_PPC_STB04 = xxx,
+ CPU_PPC_STB043 = xxx,
#endif
- CPU_PPC_STB25 = 0x51510000,
+#if 0
+ CPU_PPC_STB045 = xxx,
+#endif
+ CPU_PPC_STB25 = 0x51510950,
#if 0
CPU_PPC_STB130 = xxx,
#endif
+ /* Xilinx cores */
+ CPU_PPC_X2VP4 = 0x20010820,
+#define CPU_PPC_X2VP7 CPU_PPC_X2VP4
+ CPU_PPC_X2VP20 = 0x20010860,
+#define CPU_PPC_X2VP50 CPU_PPC_X2VP20
/* PowerPC 440 cores */
- CPU_PPC_440EP = 0x42220000,
- CPU_PPC_440GP = 0x40120400,
- CPU_PPC_440GX = 0x51B20000,
- /* PowerPC MPC 8xx cores */
- CPU_PPC_8540 = 0x80200000,
+ CPU_PPC_440EP = 0x422218D3,
+#define CPU_PPC_440GR CPU_PPC_440EP
+ CPU_PPC_440GP = 0x40120481,
+ CPU_PPC_440GX = 0x51B21850,
+ CPU_PPC_440GXc = 0x51B21892,
+ CPU_PPC_440GXf = 0x51B21894,
+ CPU_PPC_440SP = 0x53221850,
+ CPU_PPC_440SP2 = 0x53221891,
+ CPU_PPC_440SPE = 0x53421890,
+ /* XXX: missing 440GRX */
+ /* PowerPC 460 cores - TODO */
+ /* PowerPC MPC 5xx cores */
+ CPU_PPC_5xx = 0x00020020,
+ /* PowerPC MPC 8xx cores (aka PowerQUICC) */
CPU_PPC_8xx = 0x00500000,
- CPU_PPC_8240 = 0x00810100,
- CPU_PPC_8245 = 0x00811014,
+ /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */
+ CPU_PPC_82xx_HIP3 = 0x00810101,
+ CPU_PPC_82xx_HIP4 = 0x80811014,
+ CPU_PPC_827x = 0x80822013,
+ /* eCores */
+ CPU_PPC_e200 = 0x81120000,
+ CPU_PPC_e500v110 = 0x80200010,
+ CPU_PPC_e500v120 = 0x80200020,
+ CPU_PPC_e500v210 = 0x80210010,
+ CPU_PPC_e500v220 = 0x80210020,
+#define CPU_PPC_e500 CPU_PPC_e500v220
+ CPU_PPC_e600 = 0x80040010,
/* PowerPC 6xx cores */
- CPU_PPC_601 = 0x00010000,
- CPU_PPC_602 = 0x00050000,
- CPU_PPC_603 = 0x00030000,
- CPU_PPC_603E = 0x00060000,
- CPU_PPC_603EV = 0x00070000,
- CPU_PPC_603R = 0x00071000,
- CPU_PPC_G2 = 0x80810000,
- CPU_PPC_G2LE = 0x80820000,
+ CPU_PPC_601 = 0x00010001,
+ CPU_PPC_602 = 0x00050100,
+ CPU_PPC_603 = 0x00030100,
+ CPU_PPC_603E = 0x00060101,
+ CPU_PPC_603P = 0x00070000,
+ CPU_PPC_603E7v = 0x00070100,
+ CPU_PPC_603E7v2 = 0x00070201,
+ CPU_PPC_603E7 = 0x00070200,
+ CPU_PPC_603R = 0x00071201,
+ CPU_PPC_G2 = 0x00810011,
+ CPU_PPC_G2H4 = 0x80811010,
+ CPU_PPC_G2gp = 0x80821010,
+ CPU_PPC_G2ls = 0x90810010,
+ CPU_PPC_G2LE = 0x80820010,
+ CPU_PPC_G2LEgp = 0x80822010,
+ CPU_PPC_G2LEls = 0xA0822010,
CPU_PPC_604 = 0x00040000,
- CPU_PPC_604E = 0x00090000,
- CPU_PPC_604R = 0x000a0000,
+ CPU_PPC_604E = 0x00090100, /* Also 2110 & 2120 */
+ CPU_PPC_604R = 0x000a0101,
/* PowerPC 74x/75x cores (aka G3) */
CPU_PPC_74x = 0x00080000,
- CPU_PPC_755 = 0x00083000,
+ CPU_PPC_740E = 0x00080100,
+ CPU_PPC_750E = 0x00080200,
+ CPU_PPC_755_10 = 0x00083100,
+ CPU_PPC_755_11 = 0x00083101,
+ CPU_PPC_755_20 = 0x00083200,
+ CPU_PPC_755D = 0x00083202,
+ CPU_PPC_755E = 0x00083203,
+#define CPU_PPC_755 CPU_PPC_755E
CPU_PPC_74xP = 0x10080000,
- CPU_PPC_750CXE22 = 0x00082202,
+ CPU_PPC_750CXE21 = 0x00082201,
+ CPU_PPC_750CXE22 = 0x00082212,
+ CPU_PPC_750CXE23 = 0x00082203,
CPU_PPC_750CXE24 = 0x00082214,
CPU_PPC_750CXE24b = 0x00083214,
CPU_PPC_750CXE31 = 0x00083211,
CPU_PPC_750CXE31b = 0x00083311,
#define CPU_PPC_750CXE CPU_PPC_750CXE31b
- CPU_PPC_750FX = 0x70000000,
- CPU_PPC_750GX = 0x70020000,
+ CPU_PPC_750CXR = 0x00083410,
+ CPU_PPC_750FX10 = 0x70000100,
+ CPU_PPC_750FX20 = 0x70000200,
+ CPU_PPC_750FX21 = 0x70000201,
+ CPU_PPC_750FX22 = 0x70000202,
+ CPU_PPC_750FX23 = 0x70000203,
+#define CPU_PPC_750FX CPU_PPC_750FX23
+ CPU_PPC_750FL = 0x700A0203,
+ CPU_PPC_750GX10 = 0x70020100,
+ CPU_PPC_750GX11 = 0x70020101,
+ CPU_PPC_750GX12 = 0x70020102,
+#define CPU_PPC_750GX CPU_PPC_750GX12
+ CPU_PPC_750GL = 0x70020102,
+ CPU_PPC_750L30 = 0x00088300,
+ CPU_PPC_750L32 = 0x00088302,
+ CPU_PPC_750CL = 0x00087200,
/* PowerPC 74xx cores (aka G4) */
- CPU_PPC_7400 = 0x000C0000,
- CPU_PPC_7410 = 0x800C0000,
- CPU_PPC_7441 = 0x80000200,
- CPU_PPC_7450 = 0x80000000,
+ CPU_PPC_7400 = 0x000C0100,
+ CPU_PPC_7410C = 0x800C1102,
+ CPU_PPC_7410D = 0x800C1103,
+ CPU_PPC_7410E = 0x800C1104,
+ CPU_PPC_7441 = 0x80000210,
+ CPU_PPC_7445 = 0x80010100,
+ CPU_PPC_7447 = 0x80020100,
+ CPU_PPC_7447A = 0x80030101,
+ CPU_PPC_7448 = 0x80040100,
+ CPU_PPC_7450 = 0x80000200,
+ CPU_PPC_7450b = 0x80000201,
CPU_PPC_7451 = 0x80000203,
- CPU_PPC_7455 = 0x80010000,
- CPU_PPC_7457 = 0x80020000,
+ CPU_PPC_7451G = 0x80000210,
+ CPU_PPC_7455 = 0x80010201,
+ CPU_PPC_7455F = 0x80010303,
+ CPU_PPC_7455G = 0x80010304,
+ CPU_PPC_7457 = 0x80020101,
+ CPU_PPC_7457C = 0x80020102,
CPU_PPC_7457A = 0x80030000,
/* 64 bits PowerPC */
CPU_PPC_620 = 0x00140000,
@@ -130,7 +232,21 @@ enum {
CPU_PPC_POWER5 = 0x003A0000,
CPU_PPC_POWER5P = 0x003B0000,
CPU_PPC_970 = 0x00390000,
- CPU_PPC_970FX = 0x003C0000,
+ CPU_PPC_970FX10 = 0x00391100,
+ CPU_PPC_970FX20 = 0x003C0200,
+ CPU_PPC_970FX21 = 0x003C0201,
+ CPU_PPC_970FX30 = 0x003C0300,
+ CPU_PPC_970FX31 = 0x003C0301,
+#define CPU_PPC_970FX CPU_PPC_970FX31
+ CPU_PPC_970MP10 = 0x00440100,
+ CPU_PPC_970MP11 = 0x00440101,
+#define CPU_PPC_970MP CPU_PPC_970MP11
+ CPU_PPC_CELL10 = 0x00700100,
+ CPU_PPC_CELL20 = 0x00700400,
+ CPU_PPC_CELL30 = 0x00700500,
+ CPU_PPC_CELL31 = 0x00700501,
+#define CPU_PPC_CELL32 CPU_PPC_CELL31
+#define CPU_PPC_CELL CPU_PPC_CELL32
CPU_PPC_RS64 = 0x00330000,
CPU_PPC_RS64II = 0x00340000,
CPU_PPC_RS64III = 0x00360000,
@@ -147,12 +263,28 @@ enum {
#endif
};
-/* System version register (used on MPC 8xx) */
+/* System version register (used on MPC 8xxx) */
enum {
PPC_SVR_8540 = 0x80300000,
- PPC_SVR_8541E = 0x807A0000,
- PPC_SVR_8555E = 0x80790000,
- PPC_SVR_8560 = 0x80700000,
+ PPC_SVR_8541E = 0x807A0010,
+ PPC_SVR_8543v10 = 0x80320010,
+ PPC_SVR_8543v11 = 0x80320011,
+ PPC_SVR_8543v20 = 0x80320020,
+ PPC_SVR_8543Ev10 = 0x803A0010,
+ PPC_SVR_8543Ev11 = 0x803A0011,
+ PPC_SVR_8543Ev20 = 0x803A0020,
+ PPC_SVR_8545 = 0x80310220,
+ PPC_SVR_8545E = 0x80390220,
+ PPC_SVR_8547E = 0x80390120,
+ PPC_SCR_8548v10 = 0x80310010,
+ PPC_SCR_8548v11 = 0x80310011,
+ PPC_SCR_8548v20 = 0x80310020,
+ PPC_SVR_8548Ev10 = 0x80390010,
+ PPC_SVR_8548Ev11 = 0x80390011,
+ PPC_SVR_8548Ev20 = 0x80390020,
+ PPC_SVR_8555E = 0x80790010,
+ PPC_SVR_8560v10 = 0x80700010,
+ PPC_SVR_8560v20 = 0x80700020,
};
/*****************************************************************************/
@@ -197,7 +329,7 @@ enum {
/* Time base support */
PPC_TB = 0x00002000,
/* Embedded PowerPC dedicated instructions */
- PPC_4xx_COMMON = 0x00004000,
+ PPC_EMB_COMMON = 0x00004000,
/* PowerPC 40x exception model */
PPC_40x_EXCP = 0x00008000,
/* PowerPC 40x specific instructions */
@@ -225,12 +357,20 @@ enum {
PPC_64H = 0x02000000,
/* 64 bits PowerPC "bridge" features */
PPC_64_BRIDGE = 0x04000000,
+ /* BookE (embedded) PowerPC specification */
+ PPC_BOOKE = 0x08000000,
+ /* eieio */
+ PPC_MEM_EIEIO = 0x10000000,
+ /* e500 vector instructions */
+ PPC_E500_VECTOR = 0x20000000,
+ /* PowerPC 4xx dedicated instructions */
+ PPC_4xx_COMMON = 0x40000000,
};
/* CPU run-time flags (MMU and exception model) */
enum {
/* MMU model */
-#define PPC_FLAGS_MMU_MASK (0x0000000F)
+ PPC_FLAGS_MMU_MASK = 0x0000000F,
/* Standard 32 bits PowerPC MMU */
PPC_FLAGS_MMU_32B = 0x00000000,
/* Standard 64 bits PowerPC MMU */
@@ -243,8 +383,10 @@ enum {
PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
/* PowerPC 403 MMU */
PPC_FLAGS_MMU_403 = 0x00000005,
+ /* Freescale e500 MMU model */
+ PPC_FLAGS_MMU_e500 = 0x00000006,
/* Exception model */
-#define PPC_FLAGS_EXCP_MASK (0x000000F0)
+ PPC_FLAGS_EXCP_MASK = 0x000000F0,
/* Standard PowerPC exception model */
PPC_FLAGS_EXCP_STD = 0x00000000,
/* PowerPC 40x exception model */
@@ -277,32 +419,42 @@ enum {
#define PPC_FLAGS_TODO (0x00000000)
/* PowerPC 40x instruction set */
-#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON)
+#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_EMB_COMMON)
/* PowerPC 401 */
#define PPC_INSNS_401 (PPC_INSNS_TODO)
#define PPC_FLAGS_401 (PPC_FLAGS_TODO)
/* PowerPC 403 */
-#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA | \
- PPC_40x_EXCP | PPC_40x_SPEC)
+#define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \
+ PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP | \
+ PPC_40x_SPEC)
#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x)
/* PowerPC 405 */
-#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT | \
- PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \
+#define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \
+ PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB | \
+ PPC_4xx_COMMON | PPC_40x_SPEC | PPC_40x_EXCP | \
PPC_405_MAC)
#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
/* PowerPC 440 */
-#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC | \
- PPC_440_SPEC)
+#define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \
+ PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC)
#define PPC_FLAGS_440 (PPC_FLAGS_TODO)
+/* Generic BookE PowerPC */
+#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \
+ PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT)
+#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
+/* e500 core */
+#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \
+ PPC_CACHE_OPT | PPC_E500_VECTOR)
+#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
/* Non-embedded PowerPC */
#define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \
- PPC_SEGMENT | PPC_MEM_TLBIE)
+ PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE)
/* PowerPC 601 */
#define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR)
#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601)
/* PowerPC 602 */
#define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \
- PPC_MEM_TLBSYNC | PPC_TB)
+ PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC)
#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602)
/* PowerPC 603 */
#define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \
@@ -348,13 +500,17 @@ typedef struct ppc_tb_t ppc_tb_t;
typedef struct ppc_spr_t ppc_spr_t;
typedef struct ppc_dcr_t ppc_dcr_t;
typedef struct ppc_avr_t ppc_avr_t;
+typedef struct ppc_tlb_t ppc_tlb_t;
+
/* SPR access micro-ops generations callbacks */
struct ppc_spr_t {
void (*uea_read)(void *opaque, int spr_num);
void (*uea_write)(void *opaque, int spr_num);
+#if !defined(CONFIG_USER_ONLY)
void (*oea_read)(void *opaque, int spr_num);
void (*oea_write)(void *opaque, int spr_num);
+#endif
const unsigned char *name;
};
@@ -364,46 +520,42 @@ struct ppc_avr_t {
};
/* Software TLB cache */
-typedef struct ppc_tlb_t ppc_tlb_t;
struct ppc_tlb_t {
- /* Physical page number */
- target_phys_addr_t RPN;
- /* Virtual page number */
- target_ulong VPN;
- /* Page size */
- target_ulong size;
- /* Protection bits */
- int prot;
- int is_user;
- uint32_t private;
- uint32_t flags;
+ target_ulong pte0;
+ target_ulong pte1;
+ target_ulong EPN;
+ target_ulong PID;
+ int size;
};
/*****************************************************************************/
/* Machine state register bits definition */
-#define MSR_SF 63 /* Sixty-four-bit mode */
+#define MSR_SF 63 /* Sixty-four-bit mode hflags */
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
-#define MSR_HV 60 /* hypervisor state */
-#define MSR_VR 25 /* altivec available */
-#define MSR_AP 23 /* Access privilege state on 602 */
-#define MSR_SA 22 /* Supervisor access mode on 602 */
+#define MSR_HV 60 /* hypervisor state hflags */
+#define MSR_UCLE 26 /* User-mode cache lock enable on e500 */
+#define MSR_VR 25 /* altivec available hflags */
+#define MSR_SPE 25 /* SPE enable on e500 hflags */
+#define MSR_AP 23 /* Access privilege state on 602 hflags */
+#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
#define MSR_KEY 19 /* key bit on 603e */
#define MSR_POW 18 /* Power management */
#define MSR_WE 18 /* Wait state enable on embedded PowerPC */
#define MSR_TGPR 17 /* TGPR usage on 602/603 */
-#define MSR_TLB 17 /* TLB on ? */
+#define MSR_TLB 17 /* TLB update on ? */
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC */
#define MSR_ILE 16 /* Interrupt little-endian mode */
#define MSR_EE 15 /* External interrupt enable */
-#define MSR_PR 14 /* Problem state */
-#define MSR_FP 13 /* Floating point available */
+#define MSR_PR 14 /* Problem state hflags */
+#define MSR_FP 13 /* Floating point available hflags */
#define MSR_ME 12 /* Machine check interrupt enable */
-#define MSR_FE0 11 /* Floating point exception mode 0 */
-#define MSR_SE 10 /* Single-step trace enable */
+#define MSR_FE0 11 /* Floating point exception mode 0 hflags */
+#define MSR_SE 10 /* Single-step trace enable hflags */
#define MSR_DWE 10 /* Debug wait enable on 405 */
-#define MSR_BE 9 /* Branch trace enable */
+#define MSR_UBLE 10 /* User BTB lock enable on e500 */
+#define MSR_BE 9 /* Branch trace enable hflags */
#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */
-#define MSR_FE1 8 /* Floating point exception mode 1 */
+#define MSR_FE1 8 /* Floating point exception mode 1 hflags */
#define MSR_AL 7 /* AL bit on POWER */
#define MSR_IP 6 /* Interrupt prefix */
#define MSR_IR 5 /* Instruction relocate */
@@ -415,42 +567,45 @@ struct ppc_tlb_t {
#define MSR_PX 2 /* Protection exclusive on 403 */
#define MSR_PMM 2 /* Performance monitor mark on POWER */
#define MSR_RI 1 /* Recoverable interrupt */
-#define MSR_LE 0 /* Little-endian mode */
+#define MSR_LE 0 /* Little-endian mode hflags */
#define msr_sf env->msr[MSR_SF]
#define msr_isf env->msr[MSR_ISF]
#define msr_hv env->msr[MSR_HV]
+#define msr_ucle env->msr[MSR_UCLE]
#define msr_vr env->msr[MSR_VR]
+#define msr_spe env->msr[MSR_SPE]
#define msr_ap env->msr[MSR_AP]
#define msr_sa env->msr[MSR_SA]
#define msr_key env->msr[MSR_KEY]
-#define msr_pow env->msr[MSR_POW]
+#define msr_pow env->msr[MSR_POW]
#define msr_we env->msr[MSR_WE]
#define msr_tgpr env->msr[MSR_TGPR]
#define msr_tlb env->msr[MSR_TLB]
#define msr_ce env->msr[MSR_CE]
-#define msr_ile env->msr[MSR_ILE]
-#define msr_ee env->msr[MSR_EE]
-#define msr_pr env->msr[MSR_PR]
-#define msr_fp env->msr[MSR_FP]
-#define msr_me env->msr[MSR_ME]
-#define msr_fe0 env->msr[MSR_FE0]
-#define msr_se env->msr[MSR_SE]
+#define msr_ile env->msr[MSR_ILE]
+#define msr_ee env->msr[MSR_EE]
+#define msr_pr env->msr[MSR_PR]
+#define msr_fp env->msr[MSR_FP]
+#define msr_me env->msr[MSR_ME]
+#define msr_fe0 env->msr[MSR_FE0]
+#define msr_se env->msr[MSR_SE]
#define msr_dwe env->msr[MSR_DWE]
-#define msr_be env->msr[MSR_BE]
+#define msr_uble env->msr[MSR_UBLE]
+#define msr_be env->msr[MSR_BE]
#define msr_de env->msr[MSR_DE]
-#define msr_fe1 env->msr[MSR_FE1]
+#define msr_fe1 env->msr[MSR_FE1]
#define msr_al env->msr[MSR_AL]
-#define msr_ip env->msr[MSR_IP]
-#define msr_ir env->msr[MSR_IR]
+#define msr_ip env->msr[MSR_IP]
+#define msr_ir env->msr[MSR_IR]
#define msr_is env->msr[MSR_IS]
-#define msr_dr env->msr[MSR_DR]
+#define msr_dr env->msr[MSR_DR]
#define msr_ds env->msr[MSR_DS]
#define msr_pe env->msr[MSR_PE]
#define msr_ep env->msr[MSR_EP]
#define msr_px env->msr[MSR_PX]
#define msr_pmm env->msr[MSR_PMM]
-#define msr_ri env->msr[MSR_RI]
-#define msr_le env->msr[MSR_LE]
+#define msr_ri env->msr[MSR_RI]
+#define msr_le env->msr[MSR_LE]
/*****************************************************************************/
/* The whole PowerPC CPU context */
@@ -465,7 +620,7 @@ struct CPUPPCState {
target_ulong t0, t1, t2;
#endif
/* general purpose registers */
- target_ulong gpr[32];
+ ppc_gpr_t gpr[32];
/* LR */
target_ulong lr;
/* CTR */
@@ -482,10 +637,10 @@ struct CPUPPCState {
/* machine state register */
uint8_t msr[64];
/* temporary general purpose registers */
- target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+ ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */
/* Floating point execution context */
- /* temporary float registers */
+ /* temporary float registers */
float64 ft0;
float64 ft1;
float64 ft2;
@@ -529,9 +684,12 @@ struct CPUPPCState {
ppc_dcr_t *dcr_env;
/* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
- int nb_tlb;
- int nb_ways, last_way;
- ppc_tlb_t tlb[128];
+ int nb_tlb; /* Total number of TLB */
+ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
+ int nb_ways; /* Number of ways in the TLB set */
+ int last_way; /* Last used way used to allocate TLB in a LRU way */
+ int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
+ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */
/* Callbacks for specific checks on some implementations */
int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot,
target_ulong vaddr, int rw, int acc_type,
@@ -568,6 +726,16 @@ struct CPUPPCState {
int (*osi_call)(struct CPUPPCState *env);
};
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+ target_phys_addr_t raddr; /* Real address */
+ int prot; /* Protection bits */
+ target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+ target_ulong ptem; /* Virtual segment ID | API */
+ int key; /* Access key */
+};
+
/*****************************************************************************/
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
@@ -583,6 +751,7 @@ void cpu_loop_exit(void);
void dump_stack (CPUPPCState *env);
+#if !defined(CONFIG_USER_ONLY)
target_ulong do_load_ibatu (CPUPPCState *env, int nr);
target_ulong do_load_ibatl (CPUPPCState *env, int nr);
void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
@@ -591,23 +760,17 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr);
target_ulong do_load_dbatl (CPUPPCState *env, int nr);
void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
-
-target_ulong do_load_nip (CPUPPCState *env);
-void do_store_nip (CPUPPCState *env, target_ulong value);
target_ulong do_load_sdr1 (CPUPPCState *env);
void do_store_sdr1 (CPUPPCState *env, target_ulong value);
target_ulong do_load_asr (CPUPPCState *env);
void do_store_asr (CPUPPCState *env, target_ulong value);
target_ulong do_load_sr (CPUPPCState *env, int srnum);
void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
-uint32_t do_load_cr (CPUPPCState *env);
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask);
-uint32_t do_load_xer (CPUPPCState *env);
-void do_store_xer (CPUPPCState *env, uint32_t value);
+#endif
+uint32_t ppc_load_xer (CPUPPCState *env);
+void ppc_store_xer (CPUPPCState *env, uint32_t value);
target_ulong do_load_msr (CPUPPCState *env);
void do_store_msr (CPUPPCState *env, target_ulong value);
-float64 do_load_fpscr (CPUPPCState *env);
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask);
void do_compute_hflags (CPUPPCState *env);
@@ -645,261 +808,294 @@ void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
#define xer_bc env->xer[0]
/* SPR definitions */
-#define SPR_MQ (0x000)
-#define SPR_XER (0x001)
-#define SPR_601_VRTCU (0x004)
-#define SPR_601_VRTCL (0x005)
-#define SPR_601_UDECR (0x006)
-#define SPR_LR (0x008)
-#define SPR_CTR (0x009)
-#define SPR_DSISR (0x012)
-#define SPR_DAR (0x013)
-#define SPR_601_RTCU (0x014)
-#define SPR_601_RTCL (0x015)
-#define SPR_DECR (0x016)
-#define SPR_SDR1 (0x019)
-#define SPR_SRR0 (0x01A)
-#define SPR_SRR1 (0x01B)
-#define SPR_440_PID (0x030)
-#define SPR_440_DECAR (0x036)
-#define SPR_CSRR0 (0x03A)
-#define SPR_CSRR1 (0x03B)
-#define SPR_440_DEAR (0x03D)
-#define SPR_440_ESR (0x03E)
-#define SPR_440_IVPR (0x03F)
-#define SPR_8xx_EIE (0x050)
-#define SPR_8xx_EID (0x051)
-#define SPR_8xx_NRE (0x052)
-#define SPR_58x_CMPA (0x090)
-#define SPR_58x_CMPB (0x091)
-#define SPR_58x_CMPC (0x092)
-#define SPR_58x_CMPD (0x093)
-#define SPR_58x_ICR (0x094)
-#define SPR_58x_DER (0x094)
-#define SPR_58x_COUNTA (0x096)
-#define SPR_58x_COUNTB (0x097)
-#define SPR_58x_CMPE (0x098)
-#define SPR_58x_CMPF (0x099)
-#define SPR_58x_CMPG (0x09A)
-#define SPR_58x_CMPH (0x09B)
-#define SPR_58x_LCTRL1 (0x09C)
-#define SPR_58x_LCTRL2 (0x09D)
-#define SPR_58x_ICTRL (0x09E)
-#define SPR_58x_BAR (0x09F)
-#define SPR_VRSAVE (0x100)
-#define SPR_USPRG0 (0x100)
-#define SPR_USPRG4 (0x104)
-#define SPR_USPRG5 (0x105)
-#define SPR_USPRG6 (0x106)
-#define SPR_USPRG7 (0x107)
-#define SPR_VTBL (0x10C)
-#define SPR_VTBU (0x10D)
-#define SPR_SPRG0 (0x110)
-#define SPR_SPRG1 (0x111)
-#define SPR_SPRG2 (0x112)
-#define SPR_SPRG3 (0x113)
-#define SPR_SPRG4 (0x114)
-#define SPR_SCOMC (0x114)
-#define SPR_SPRG5 (0x115)
-#define SPR_SCOMD (0x115)
-#define SPR_SPRG6 (0x116)
-#define SPR_SPRG7 (0x117)
-#define SPR_ASR (0x118)
-#define SPR_EAR (0x11A)
-#define SPR_TBL (0x11C)
-#define SPR_TBU (0x11D)
-#define SPR_SVR (0x11E)
-#define SPR_440_PIR (0x11E)
-#define SPR_PVR (0x11F)
-#define SPR_HSPRG0 (0x130)
-#define SPR_440_DBSR (0x130)
-#define SPR_HSPRG1 (0x131)
-#define SPR_440_DBCR0 (0x134)
-#define SPR_IBCR (0x135)
-#define SPR_440_DBCR1 (0x135)
-#define SPR_DBCR (0x136)
-#define SPR_HDEC (0x136)
-#define SPR_440_DBCR2 (0x136)
-#define SPR_HIOR (0x137)
-#define SPR_MBAR (0x137)
-#define SPR_RMOR (0x138)
-#define SPR_440_IAC1 (0x138)
-#define SPR_HRMOR (0x139)
-#define SPR_440_IAC2 (0x139)
-#define SPR_HSSR0 (0x13A)
-#define SPR_440_IAC3 (0x13A)
-#define SPR_HSSR1 (0x13B)
-#define SPR_440_IAC4 (0x13B)
-#define SPR_LPCR (0x13C)
-#define SPR_440_DAC1 (0x13C)
-#define SPR_LPIDR (0x13D)
-#define SPR_DABR2 (0x13D)
-#define SPR_440_DAC2 (0x13D)
-#define SPR_440_DVC1 (0x13E)
-#define SPR_440_DVC2 (0x13F)
-#define SPR_440_TSR (0x150)
-#define SPR_440_TCR (0x154)
-#define SPR_440_IVOR0 (0x190)
-#define SPR_440_IVOR1 (0x191)
-#define SPR_440_IVOR2 (0x192)
-#define SPR_440_IVOR3 (0x193)
-#define SPR_440_IVOR4 (0x194)
-#define SPR_440_IVOR5 (0x195)
-#define SPR_440_IVOR6 (0x196)
-#define SPR_440_IVOR7 (0x197)
-#define SPR_440_IVOR8 (0x198)
-#define SPR_440_IVOR9 (0x199)
-#define SPR_440_IVOR10 (0x19A)
-#define SPR_440_IVOR11 (0x19B)
-#define SPR_440_IVOR12 (0x19C)
-#define SPR_440_IVOR13 (0x19D)
-#define SPR_440_IVOR14 (0x19E)
-#define SPR_440_IVOR15 (0x19F)
-#define SPR_IBAT0U (0x210)
-#define SPR_IBAT0L (0x211)
-#define SPR_IBAT1U (0x212)
-#define SPR_IBAT1L (0x213)
-#define SPR_IBAT2U (0x214)
-#define SPR_IBAT2L (0x215)
-#define SPR_IBAT3U (0x216)
-#define SPR_IBAT3L (0x217)
-#define SPR_DBAT0U (0x218)
-#define SPR_DBAT0L (0x219)
-#define SPR_DBAT1U (0x21A)
-#define SPR_DBAT1L (0x21B)
-#define SPR_DBAT2U (0x21C)
-#define SPR_DBAT2L (0x21D)
-#define SPR_DBAT3U (0x21E)
-#define SPR_DBAT3L (0x21F)
-#define SPR_IBAT4U (0x230)
-#define SPR_IBAT4L (0x231)
-#define SPR_IBAT5U (0x232)
-#define SPR_IBAT5L (0x233)
-#define SPR_IBAT6U (0x234)
-#define SPR_IBAT6L (0x235)
-#define SPR_IBAT7U (0x236)
-#define SPR_IBAT7L (0x237)
-#define SPR_DBAT4U (0x238)
-#define SPR_DBAT4L (0x239)
-#define SPR_DBAT5U (0x23A)
-#define SPR_DBAT5L (0x23B)
-#define SPR_DBAT6U (0x23C)
-#define SPR_DBAT6L (0x23D)
-#define SPR_DBAT7U (0x23E)
-#define SPR_DBAT7L (0x23F)
-#define SPR_440_INV0 (0x370)
-#define SPR_440_INV1 (0x371)
-#define SPR_440_INV2 (0x372)
-#define SPR_440_INV3 (0x373)
-#define SPR_440_IVT0 (0x374)
-#define SPR_440_IVT1 (0x375)
-#define SPR_440_IVT2 (0x376)
-#define SPR_440_IVT3 (0x377)
-#define SPR_440_DNV0 (0x390)
-#define SPR_440_DNV1 (0x391)
-#define SPR_440_DNV2 (0x392)
-#define SPR_440_DNV3 (0x393)
-#define SPR_440_DVT0 (0x394)
-#define SPR_440_DVT1 (0x395)
-#define SPR_440_DVT2 (0x396)
-#define SPR_440_DVT3 (0x397)
-#define SPR_440_DVLIM (0x398)
-#define SPR_440_IVLIM (0x399)
-#define SPR_440_RSTCFG (0x39B)
-#define SPR_440_DCBTRL (0x39C)
-#define SPR_440_DCBTRH (0x39D)
-#define SPR_440_ICBTRL (0x39E)
-#define SPR_440_ICBTRH (0x39F)
-#define SPR_UMMCR0 (0x3A8)
-#define SPR_UPMC1 (0x3A9)
-#define SPR_UPMC2 (0x3AA)
-#define SPR_USIA (0x3AB)
-#define SPR_UMMCR1 (0x3AC)
-#define SPR_UPMC3 (0x3AD)
-#define SPR_UPMC4 (0x3AE)
-#define SPR_USDA (0x3AF)
-#define SPR_40x_ZPR (0x3B0)
-#define SPR_40x_PID (0x3B1)
-#define SPR_440_MMUCR (0x3B2)
-#define SPR_4xx_CCR0 (0x3B3)
-#define SPR_405_IAC3 (0x3B4)
-#define SPR_405_IAC4 (0x3B5)
-#define SPR_405_DVC1 (0x3B6)
-#define SPR_405_DVC2 (0x3B7)
-#define SPR_MMCR0 (0x3B8)
-#define SPR_PMC1 (0x3B9)
-#define SPR_40x_SGR (0x3B9)
-#define SPR_PMC2 (0x3BA)
-#define SPR_40x_DCWR (0x3BA)
-#define SPR_SIA (0x3BB)
-#define SPR_405_SLER (0x3BB)
-#define SPR_MMCR1 (0x3BC)
-#define SPR_405_SU0R (0x3BC)
-#define SPR_PMC3 (0x3BD)
-#define SPR_405_DBCR1 (0x3BD)
-#define SPR_PMC4 (0x3BE)
-#define SPR_SDA (0x3BF)
-#define SPR_403_VTBL (0x3CC)
-#define SPR_403_VTBU (0x3CD)
-#define SPR_DMISS (0x3D0)
-#define SPR_DCMP (0x3D1)
-#define SPR_DHASH1 (0x3D2)
-#define SPR_DHASH2 (0x3D3)
-#define SPR_4xx_ICDBDR (0x3D3)
-#define SPR_IMISS (0x3D4)
-#define SPR_40x_ESR (0x3D4)
-#define SPR_ICMP (0x3D5)
-#define SPR_40x_DEAR (0x3D5)
-#define SPR_RPA (0x3D6)
-#define SPR_40x_EVPR (0x3D6)
-#define SPR_403_CDBCR (0x3D7)
-#define SPR_TCR (0x3D8)
-#define SPR_40x_TSR (0x3D8)
-#define SPR_IBR (0x3DA)
-#define SPR_40x_TCR (0x3DA)
-#define SPR_ESASR (0x3DB)
-#define SPR_40x_PIT (0x3DB)
-#define SPR_403_TBL (0x3DC)
-#define SPR_403_TBU (0x3DD)
-#define SPR_SEBR (0x3DE)
-#define SPR_40x_SRR2 (0x3DE)
-#define SPR_SER (0x3DF)
-#define SPR_40x_SRR3 (0x3DF)
-#define SPR_HID0 (0x3F0)
-#define SPR_40x_DBSR (0x3F0)
-#define SPR_HID1 (0x3F1)
-#define SPR_IABR (0x3F2)
-#define SPR_40x_DBCR0 (0x3F2)
-#define SPR_601_HID2 (0x3F2)
-#define SPR_HID2 (0x3F3)
-#define SPR_440_DBDR (0x3F3)
-#define SPR_40x_IAC1 (0x3F4)
-#define SPR_DABR (0x3F5)
+#define SPR_MQ (0x000)
+#define SPR_XER (0x001)
+#define SPR_601_VRTCU (0x004)
+#define SPR_601_VRTCL (0x005)
+#define SPR_601_UDECR (0x006)
+#define SPR_LR (0x008)
+#define SPR_CTR (0x009)
+#define SPR_DSISR (0x012)
+#define SPR_DAR (0x013)
+#define SPR_601_RTCU (0x014)
+#define SPR_601_RTCL (0x015)
+#define SPR_DECR (0x016)
+#define SPR_SDR1 (0x019)
+#define SPR_SRR0 (0x01A)
+#define SPR_SRR1 (0x01B)
+#define SPR_BOOKE_PID (0x030)
+#define SPR_BOOKE_DECAR (0x036)
+#define SPR_CSRR0 (0x03A)
+#define SPR_CSRR1 (0x03B)
+#define SPR_BOOKE_DEAR (0x03D)
+#define SPR_BOOKE_ESR (0x03E)
+#define SPR_BOOKE_EVPR (0x03F)
+#define SPR_8xx_EIE (0x050)
+#define SPR_8xx_EID (0x051)
+#define SPR_8xx_NRE (0x052)
+#define SPR_58x_CMPA (0x090)
+#define SPR_58x_CMPB (0x091)
+#define SPR_58x_CMPC (0x092)
+#define SPR_58x_CMPD (0x093)
+#define SPR_58x_ICR (0x094)
+#define SPR_58x_DER (0x094)
+#define SPR_58x_COUNTA (0x096)
+#define SPR_58x_COUNTB (0x097)
+#define SPR_58x_CMPE (0x098)
+#define SPR_58x_CMPF (0x099)
+#define SPR_58x_CMPG (0x09A)
+#define SPR_58x_CMPH (0x09B)
+#define SPR_58x_LCTRL1 (0x09C)
+#define SPR_58x_LCTRL2 (0x09D)
+#define SPR_58x_ICTRL (0x09E)
+#define SPR_58x_BAR (0x09F)
+#define SPR_VRSAVE (0x100)
+#define SPR_USPRG0 (0x100)
+#define SPR_USPRG4 (0x104)
+#define SPR_USPRG5 (0x105)
+#define SPR_USPRG6 (0x106)
+#define SPR_USPRG7 (0x107)
+#define SPR_VTBL (0x10C)
+#define SPR_VTBU (0x10D)
+#define SPR_SPRG0 (0x110)
+#define SPR_SPRG1 (0x111)
+#define SPR_SPRG2 (0x112)
+#define SPR_SPRG3 (0x113)
+#define SPR_SPRG4 (0x114)
+#define SPR_SCOMC (0x114)
+#define SPR_SPRG5 (0x115)
+#define SPR_SCOMD (0x115)
+#define SPR_SPRG6 (0x116)
+#define SPR_SPRG7 (0x117)
+#define SPR_ASR (0x118)
+#define SPR_EAR (0x11A)
+#define SPR_TBL (0x11C)
+#define SPR_TBU (0x11D)
+#define SPR_SVR (0x11E)
+#define SPR_BOOKE_PIR (0x11E)
+#define SPR_PVR (0x11F)
+#define SPR_HSPRG0 (0x130)
+#define SPR_BOOKE_DBSR (0x130)
+#define SPR_HSPRG1 (0x131)
+#define SPR_BOOKE_DBCR0 (0x134)
+#define SPR_IBCR (0x135)
+#define SPR_BOOKE_DBCR1 (0x135)
+#define SPR_DBCR (0x136)
+#define SPR_HDEC (0x136)
+#define SPR_BOOKE_DBCR2 (0x136)
+#define SPR_HIOR (0x137)
+#define SPR_MBAR (0x137)
+#define SPR_RMOR (0x138)
+#define SPR_BOOKE_IAC1 (0x138)
+#define SPR_HRMOR (0x139)
+#define SPR_BOOKE_IAC2 (0x139)
+#define SPR_HSSR0 (0x13A)
+#define SPR_BOOKE_IAC3 (0x13A)
+#define SPR_HSSR1 (0x13B)
+#define SPR_BOOKE_IAC4 (0x13B)
+#define SPR_LPCR (0x13C)
+#define SPR_BOOKE_DAC1 (0x13C)
+#define SPR_LPIDR (0x13D)
+#define SPR_DABR2 (0x13D)
+#define SPR_BOOKE_DAC2 (0x13D)
+#define SPR_BOOKE_DVC1 (0x13E)
+#define SPR_BOOKE_DVC2 (0x13F)
+#define SPR_BOOKE_TSR (0x150)
+#define SPR_BOOKE_TCR (0x154)
+#define SPR_BOOKE_IVOR0 (0x190)
+#define SPR_BOOKE_IVOR1 (0x191)
+#define SPR_BOOKE_IVOR2 (0x192)
+#define SPR_BOOKE_IVOR3 (0x193)
+#define SPR_BOOKE_IVOR4 (0x194)
+#define SPR_BOOKE_IVOR5 (0x195)
+#define SPR_BOOKE_IVOR6 (0x196)
+#define SPR_BOOKE_IVOR7 (0x197)
+#define SPR_BOOKE_IVOR8 (0x198)
+#define SPR_BOOKE_IVOR9 (0x199)
+#define SPR_BOOKE_IVOR10 (0x19A)
+#define SPR_BOOKE_IVOR11 (0x19B)
+#define SPR_BOOKE_IVOR12 (0x19C)
+#define SPR_BOOKE_IVOR13 (0x19D)
+#define SPR_BOOKE_IVOR14 (0x19E)
+#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_E500_SPEFSCR (0x200)
+#define SPR_E500_BBEAR (0x201)
+#define SPR_E500_BBTAR (0x202)
+#define SPR_BOOKE_ATBL (0x20E)
+#define SPR_BOOKE_ATBU (0x20F)
+#define SPR_IBAT0U (0x210)
+#define SPR_E500_IVOR32 (0x210)
+#define SPR_IBAT0L (0x211)
+#define SPR_E500_IVOR33 (0x211)
+#define SPR_IBAT1U (0x212)
+#define SPR_E500_IVOR34 (0x212)
+#define SPR_IBAT1L (0x213)
+#define SPR_E500_IVOR35 (0x213)
+#define SPR_IBAT2U (0x214)
+#define SPR_IBAT2L (0x215)
+#define SPR_E500_L1CFG0 (0x215)
+#define SPR_IBAT3U (0x216)
+#define SPR_E500_L1CFG1 (0x216)
+#define SPR_IBAT3L (0x217)
+#define SPR_DBAT0U (0x218)
+#define SPR_DBAT0L (0x219)
+#define SPR_DBAT1U (0x21A)
+#define SPR_DBAT1L (0x21B)
+#define SPR_DBAT2U (0x21C)
+#define SPR_DBAT2L (0x21D)
+#define SPR_DBAT3U (0x21E)
+#define SPR_DBAT3L (0x21F)
+#define SPR_IBAT4U (0x230)
+#define SPR_IBAT4L (0x231)
+#define SPR_IBAT5U (0x232)
+#define SPR_IBAT5L (0x233)
+#define SPR_IBAT6U (0x234)
+#define SPR_IBAT6L (0x235)
+#define SPR_IBAT7U (0x236)
+#define SPR_IBAT7L (0x237)
+#define SPR_DBAT4U (0x238)
+#define SPR_DBAT4L (0x239)
+#define SPR_DBAT5U (0x23A)
+#define SPR_E500_MCSRR0 (0x23A)
+#define SPR_DBAT5L (0x23B)
+#define SPR_E500_MCSRR1 (0x23B)
+#define SPR_DBAT6U (0x23C)
+#define SPR_E500_MCSR (0x23C)
+#define SPR_DBAT6L (0x23D)
+#define SPR_E500_MCAR (0x23D)
+#define SPR_DBAT7U (0x23E)
+#define SPR_DBAT7L (0x23F)
+#define SPR_E500_MAS0 (0x270)
+#define SPR_E500_MAS1 (0x271)
+#define SPR_E500_MAS2 (0x272)
+#define SPR_E500_MAS3 (0x273)
+#define SPR_E500_MAS4 (0x274)
+#define SPR_E500_MAS6 (0x276)
+#define SPR_E500_PID1 (0x279)
+#define SPR_E500_PID2 (0x27A)
+#define SPR_E500_TLB0CFG (0x2B0)
+#define SPR_E500_TLB1CFG (0x2B1)
+#define SPR_440_INV0 (0x370)
+#define SPR_440_INV1 (0x371)
+#define SPR_440_INV2 (0x372)
+#define SPR_440_INV3 (0x373)
+#define SPR_440_IVT0 (0x374)
+#define SPR_440_IVT1 (0x375)
+#define SPR_440_IVT2 (0x376)
+#define SPR_440_IVT3 (0x377)
+#define SPR_440_DNV0 (0x390)
+#define SPR_440_DNV1 (0x391)
+#define SPR_440_DNV2 (0x392)
+#define SPR_440_DNV3 (0x393)
+#define SPR_440_DVT0 (0x394)
+#define SPR_440_DVT1 (0x395)
+#define SPR_440_DVT2 (0x396)
+#define SPR_440_DVT3 (0x397)
+#define SPR_440_DVLIM (0x398)
+#define SPR_440_IVLIM (0x399)
+#define SPR_440_RSTCFG (0x39B)
+#define SPR_440_DCBTRL (0x39C)
+#define SPR_440_DCBTRH (0x39D)
+#define SPR_440_ICBTRL (0x39E)
+#define SPR_440_ICBTRH (0x39F)
+#define SPR_UMMCR0 (0x3A8)
+#define SPR_UPMC1 (0x3A9)
+#define SPR_UPMC2 (0x3AA)
+#define SPR_USIA (0x3AB)
+#define SPR_UMMCR1 (0x3AC)
+#define SPR_UPMC3 (0x3AD)
+#define SPR_UPMC4 (0x3AE)
+#define SPR_USDA (0x3AF)
+#define SPR_40x_ZPR (0x3B0)
+#define SPR_E500_MAS7 (0x3B0)
+#define SPR_40x_PID (0x3B1)
+#define SPR_440_MMUCR (0x3B2)
+#define SPR_4xx_CCR0 (0x3B3)
+#define SPR_405_IAC3 (0x3B4)
+#define SPR_405_IAC4 (0x3B5)
+#define SPR_405_DVC1 (0x3B6)
+#define SPR_405_DVC2 (0x3B7)
+#define SPR_MMCR0 (0x3B8)
+#define SPR_PMC1 (0x3B9)
+#define SPR_40x_SGR (0x3B9)
+#define SPR_PMC2 (0x3BA)
+#define SPR_40x_DCWR (0x3BA)
+#define SPR_SIA (0x3BB)
+#define SPR_405_SLER (0x3BB)
+#define SPR_MMCR1 (0x3BC)
+#define SPR_405_SU0R (0x3BC)
+#define SPR_PMC3 (0x3BD)
+#define SPR_405_DBCR1 (0x3BD)
+#define SPR_PMC4 (0x3BE)
+#define SPR_SDA (0x3BF)
+#define SPR_403_VTBL (0x3CC)
+#define SPR_403_VTBU (0x3CD)
+#define SPR_DMISS (0x3D0)
+#define SPR_DCMP (0x3D1)
+#define SPR_HASH1 (0x3D2)
+#define SPR_HASH2 (0x3D3)
+#define SPR_4xx_ICDBDR (0x3D3)
+#define SPR_IMISS (0x3D4)
+#define SPR_40x_ESR (0x3D4)
+#define SPR_ICMP (0x3D5)
+#define SPR_40x_DEAR (0x3D5)
+#define SPR_RPA (0x3D6)
+#define SPR_40x_EVPR (0x3D6)
+#define SPR_403_CDBCR (0x3D7)
+#define SPR_TCR (0x3D8)
+#define SPR_40x_TSR (0x3D8)
+#define SPR_IBR (0x3DA)
+#define SPR_40x_TCR (0x3DA)
+#define SPR_ESASR (0x3DB)
+#define SPR_40x_PIT (0x3DB)
+#define SPR_403_TBL (0x3DC)
+#define SPR_403_TBU (0x3DD)
+#define SPR_SEBR (0x3DE)
+#define SPR_40x_SRR2 (0x3DE)
+#define SPR_SER (0x3DF)
+#define SPR_40x_SRR3 (0x3DF)
+#define SPR_HID0 (0x3F0)
+#define SPR_40x_DBSR (0x3F0)
+#define SPR_HID1 (0x3F1)
+#define SPR_IABR (0x3F2)
+#define SPR_40x_DBCR0 (0x3F2)
+#define SPR_601_HID2 (0x3F2)
+#define SPR_E500_L1CSR0 (0x3F2)
+#define SPR_HID2 (0x3F3)
+#define SPR_E500_L1CSR1 (0x3F3)
+#define SPR_440_DBDR (0x3F3)
+#define SPR_40x_IAC1 (0x3F4)
+#define SPR_E500_MMUCSR0 (0x3F4)
+#define SPR_DABR (0x3F5)
#define DABR_MASK (~(target_ulong)0x7)
-#define SPR_40x_IAC2 (0x3F5)
-#define SPR_601_HID5 (0x3F5)
-#define SPR_40x_DAC1 (0x3F6)
-#define SPR_40x_DAC2 (0x3F7)
-#define SPR_L2PM (0x3F8)
-#define SPR_750_HID2 (0x3F8)
-#define SPR_L2CR (0x3F9)
-#define SPR_IABR2 (0x3FA)
-#define SPR_40x_DCCR (0x3FA)
-#define SPR_ICTC (0x3FB)
-#define SPR_40x_ICCR (0x3FB)
-#define SPR_THRM1 (0x3FC)
-#define SPR_403_PBL1 (0x3FC)
-#define SPR_SP (0x3FD)
-#define SPR_THRM2 (0x3FD)
-#define SPR_403_PBU1 (0x3FD)
-#define SPR_LT (0x3FE)
-#define SPR_THRM3 (0x3FE)
-#define SPR_FPECR (0x3FE)
-#define SPR_403_PBL2 (0x3FE)
-#define SPR_PIR (0x3FF)
-#define SPR_403_PBU2 (0x3FF)
-#define SPR_601_HID15 (0x3FF)
+#define SPR_E500_BUCSR (0x3F5)
+#define SPR_40x_IAC2 (0x3F5)
+#define SPR_601_HID5 (0x3F5)
+#define SPR_40x_DAC1 (0x3F6)
+#define SPR_40x_DAC2 (0x3F7)
+#define SPR_E500_MMUCFG (0x3F7)
+#define SPR_L2PM (0x3F8)
+#define SPR_750_HID2 (0x3F8)
+#define SPR_L2CR (0x3F9)
+#define SPR_IABR2 (0x3FA)
+#define SPR_40x_DCCR (0x3FA)
+#define SPR_ICTC (0x3FB)
+#define SPR_40x_ICCR (0x3FB)
+#define SPR_THRM1 (0x3FC)
+#define SPR_403_PBL1 (0x3FC)
+#define SPR_SP (0x3FD)
+#define SPR_THRM2 (0x3FD)
+#define SPR_403_PBU1 (0x3FD)
+#define SPR_LT (0x3FE)
+#define SPR_THRM3 (0x3FE)
+#define SPR_FPECR (0x3FE)
+#define SPR_403_PBL2 (0x3FE)
+#define SPR_PIR (0x3FF)
+#define SPR_403_PBU2 (0x3FF)
+#define SPR_601_HID15 (0x3FF)
+#define SPR_E500_SVR (0x3FF)
+/*****************************************************************************/
/* Memory access type :
* may be needed for precise access rights control and precise exceptions.
*/
@@ -977,7 +1173,7 @@ enum {
#define EXCP_PPC_MAX 0x4000
/* Qemu exceptions: special cases we want to stop translation */
#define EXCP_MTMSR 0x11000 /* mtmsr instruction: */
- /* may change privilege level */
+ /* may change privilege level */
#define EXCP_BRANCH 0x11001 /* branch instruction */
#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */
#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index 89171f9d3f..25e060fb6f 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -1,7 +1,7 @@
/*
* PowerPC emulation definitions for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,15 +24,34 @@
#include "dyngen-exec.h"
-#define TARGET_LONG_BITS 32
+#include "cpu.h"
+#include "exec-all.h"
register struct CPUPPCState *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-register uint32_t T2 asm(AREG3);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+#else
+/* This may be more efficient if HOST_LONG_BITS > TARGET_LONG_BITS
+ * To be set to one when we'll be sure it does not cause bugs....
+ */
+#if 0
+register unsigned long T0 asm(AREG1);
+register unsigned long T1 asm(AREG2);
+register unsigned long T2 asm(AREG3);
+#else
+register target_ulong T0 asm(AREG1);
+register target_ulong T1 asm(AREG2);
+register target_ulong T2 asm(AREG3);
+#endif
+#endif
+/* XXX: to clean: remove this mess */
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
+
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
@@ -43,14 +62,28 @@ register uint32_t T2 asm(AREG3);
# define RETURN() __asm__ __volatile__("" : : : "memory");
#endif
-#include "cpu.h"
-#include "exec-all.h"
+static inline target_ulong rotl8 (target_ulong i, int n)
+{
+ return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n)));
+}
+
+static inline target_ulong rotl16 (target_ulong i, int n)
+{
+ return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n)));
+}
-static inline uint32_t rotl (uint32_t i, int n)
+static inline target_ulong rotl32 (target_ulong i, int n)
{
- return ((i << n) | (i >> (32 - n)));
+ return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n)));
}
+#if defined(TARGET_PPC64)
+static inline target_ulong rotl64 (target_ulong i, int n)
+{
+ return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n)));
+}
+#endif
+
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
@@ -58,23 +91,14 @@ static inline uint32_t rotl (uint32_t i, int n)
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
-void do_sraw(void);
-
-void do_fctiw (void);
-void do_fctiwz (void);
-void do_fnmadd (void);
-void do_fnmsub (void);
-void do_fsqrt (void);
-void do_fres (void);
-void do_frsqrte (void);
-void do_fsel (void);
-void do_fcmpu (void);
-void do_fcmpo (void);
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr,
+ int rw, int access_type, int check_BATs);
-void do_check_reservation (void);
-void do_icbi (void);
-void do_tlbia (void);
-void do_tlbie (void);
+void ppc6xx_tlb_invalidate_all (CPUState *env);
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ int is_code);
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1);
static inline void env_to_regs(void)
{
@@ -84,7 +108,7 @@ static inline void regs_to_env(void)
{
}
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu);
#endif /* !defined (__PPC_H__) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 70b0a49156..f4f692d5ec 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1,7 +1,7 @@
/*
* PowerPC emulation helpers for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
//#define DEBUG_MMU
//#define DEBUG_BATS
+//#define DEBUG_SOFTWARE_TLB
//#define DEBUG_EXCEPTIONS
//#define FLUSH_ALL_TLBS
@@ -55,26 +56,307 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
}
env->exception_index = exception;
env->error_code = error_code;
+
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+
+target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
return addr;
}
#else
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid (target_ulong pte0)
+{
+ return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate (target_ulong *pte0)
+{
+ *pte0 &= ~0x80000000;
+}
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+
+static int pte_check (mmu_ctx_t *ctx,
+ target_ulong pte0, target_ulong pte1, int h, int rw)
+{
+ int access, ret;
+
+ access = 0;
+ ret = -1;
+ /* Check validity and table match */
+ if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) {
+ /* Check vsid & api */
+ if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) {
+ if (ctx->raddr != (target_ulong)-1) {
+ /* all matches should have equal RPN, WIMG & PP */
+ if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) {
+ if (loglevel > 0)
+ fprintf(logfile, "Bad RPN/WIMG/PP\n");
+ return -3;
+ }
+ }
+ /* Compute access rights */
+ if (ctx->key == 0) {
+ access = PAGE_READ;
+ if ((pte1 & 0x00000003) != 0x3)
+ access |= PAGE_WRITE;
+ } else {
+ switch (pte1 & 0x00000003) {
+ case 0x0:
+ access = 0;
+ break;
+ case 0x1:
+ case 0x3:
+ access = PAGE_READ;
+ break;
+ case 0x2:
+ access = PAGE_READ | PAGE_WRITE;
+ break;
+ }
+ }
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ if ((rw == 0 && (access & PAGE_READ)) ||
+ (rw == 1 && (access & PAGE_WRITE))) {
+ /* Access granted */
+#if defined (DEBUG_MMU)
+ if (loglevel > 0)
+ fprintf(logfile, "PTE access granted !\n");
+#endif
+ ret = 0;
+ } else {
+ /* Access right violation */
+#if defined (DEBUG_MMU)
+ if (loglevel > 0)
+ fprintf(logfile, "PTE access rejected\n");
+#endif
+ ret = -2;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
+{
+ int store = 0;
+
+ /* Update page flags */
+ if (!(*pte1p & 0x00000100)) {
+ /* Update accessed flag */
+ *pte1p |= 0x00000100;
+ store = 1;
+ }
+ if (!(*pte1p & 0x00000080)) {
+ if (rw == 1 && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ store = 1;
+ } else {
+ /* Force page fault for first write access */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+ }
+
+ return store;
+}
+
+/* Software driven TLB helpers */
+static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
+ int way, int is_code)
+{
+ int nr;
+
+ /* Select TLB num in a way from address */
+ nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+ /* Select TLB way */
+ nr += env->tlb_per_way * way;
+ /* 6xx have separate TLBs for instructions and data */
+ if (is_code && env->id_tlbs == 1)
+ nr += env->nb_tlb;
+
+ return nr;
+}
+
+void ppc6xx_tlb_invalidate_all (CPUState *env)
+{
+ ppc_tlb_t *tlb;
+ int nr, max;
+
+#if defined (DEBUG_SOFTWARE_TLB) && 0
+ if (loglevel != 0) {
+ fprintf(logfile, "Invalidate all TLBs\n");
+ }
+#endif
+ /* Invalidate all defined software TLB */
+ max = env->nb_tlb;
+ if (env->id_tlbs == 1)
+ max *= 2;
+ for (nr = 0; nr < max; nr++) {
+ tlb = &env->tlb[nr];
+#if !defined(FLUSH_ALL_TLBS)
+ tlb_flush_page(env, tlb->EPN);
+#endif
+ pte_invalidate(&tlb->pte0);
+ }
+#if defined(FLUSH_ALL_TLBS)
+ tlb_flush(env, 1);
+#endif
+}
+
+static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
+ target_ulong eaddr,
+ int is_code, int match_epn)
+{
+ ppc_tlb_t *tlb;
+ int way, nr;
+
+#if !defined(FLUSH_ALL_TLBS)
+ /* Invalidate ITLB + DTLB, all ways */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+ tlb = &env->tlb[nr];
+ if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB invalidate %d/%d %08x\n",
+ nr, env->nb_tlb, eaddr);
+ }
+#endif
+ pte_invalidate(&tlb->pte0);
+ tlb_flush_page(env, tlb->EPN);
+ }
+ }
+#else
+ /* XXX: PowerPC specification say this is valid as well */
+ ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ int is_code)
+{
+ __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1)
+{
+ ppc_tlb_t *tlb;
+ int nr;
+
+ nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+ tlb = &env->tlb[nr];
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "Set TLB %d/%d EPN %08lx PTE0 %08lx PTE1 %08lx\n",
+ nr, env->nb_tlb, (unsigned long)EPN,
+ (unsigned long)pte0, (unsigned long)pte1);
+ }
+#endif
+ /* Invalidate any pending reference in Qemu for this virtual address */
+ __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+ tlb->pte0 = pte0;
+ tlb->pte1 = pte1;
+ tlb->EPN = EPN;
+ tlb->PID = 0;
+ tlb->size = 1;
+ /* Store last way for LRU mechanism */
+ env->last_way = way;
+}
+
+static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type)
+{
+ ppc_tlb_t *tlb;
+ int nr, best, way;
+ int ret;
+
+ best = -1;
+ ret = -1; /* No TLB found */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way,
+ access_type == ACCESS_CODE ? 1 : 0);
+ tlb = &env->tlb[nr];
+ /* This test "emulates" the PTE index match for hardware TLBs */
+ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB %d/%d %s [%08x %08x] <> %08x\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+ }
+#endif
+ continue;
+ }
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB %d/%d %s %08x <> %08x %08x %c %c\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, eaddr, tlb->pte1,
+ rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+ }
+#endif
+ switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
+ case -3:
+ /* TLB inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ best = nr;
+ break;
+ case -1:
+ default:
+ /* No match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all TLBs consistency
+ * but we can speed-up the whole thing as the
+ * result would be undefined if TLBs are not consistent.
+ */
+ ret = 0;
+ best = nr;
+ goto done;
+ }
+ }
+ if (best != -1) {
+ done:
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel > 0) {
+ fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
+ ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ }
+#endif
+ /* Update page flags */
+ pte_update_flags(ctx, &env->tlb[best].pte1, ret, rw);
+ }
+
+ return ret;
+}
+
/* Perform BAT hit & translation */
-static int get_bat (CPUState *env, uint32_t *real, int *prot,
- uint32_t virtual, int rw, int type)
+static int get_bat (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
- uint32_t *BATlt, *BATut, *BATu, *BATl;
- uint32_t base, BEPIl, BEPIu, bl;
+ target_ulong *BATlt, *BATut, *BATu, *BATl;
+ target_ulong base, BEPIl, BEPIu, bl;
int i;
int ret = -1;
#if defined (DEBUG_BATS)
if (loglevel > 0) {
fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
switch (type) {
@@ -90,7 +372,7 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
#if defined (DEBUG_BATS)
if (loglevel > 0) {
fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
base = virtual & 0xFFFC0000;
@@ -113,18 +395,18 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
(msr_pr == 1 && (*BATu & 0x00000001))) {
/* Get physical address */
- *real = (*BATl & 0xF0000000) |
+ ctx->raddr = (*BATl & 0xF0000000) |
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
(virtual & 0x0001F000);
if (*BATl & 0x00000001)
- *prot = PAGE_READ;
+ ctx->prot = PAGE_READ;
if (*BATl & 0x00000002)
- *prot = PAGE_WRITE | PAGE_READ;
+ ctx->prot = PAGE_WRITE | PAGE_READ;
#if defined (DEBUG_BATS)
if (loglevel > 0) {
fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
- i, *real, *prot & PAGE_READ ? 'R' : '-',
- *prot & PAGE_WRITE ? 'W' : '-');
+ i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
}
#endif
ret = 0;
@@ -153,189 +435,154 @@ static int get_bat (CPUState *env, uint32_t *real, int *prot,
}
/* PTE table lookup */
-static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
- int h, int key, int rw)
+static int find_pte (mmu_ctx_t *ctx, int h, int rw)
{
- uint32_t pte0, pte1, keep = 0, access = 0;
- int i, good = -1, store = 0;
- int ret = -1; /* No entry found */
+ target_ulong base, pte0, pte1;
+ int i, good = -1;
+ int ret;
+ ret = -1; /* No entry found */
+ base = ctx->pg_addr[h];
for (i = 0; i < 8; i++) {
pte0 = ldl_phys(base + (i * 8));
pte1 = ldl_phys(base + (i * 8) + 4);
#if defined (DEBUG_MMU)
if (loglevel > 0) {
- fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
- "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
- pte0 >> 31, h, (pte0 >> 6) & 1, va);
- }
-#endif
- /* Check validity and table match */
- if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
- /* Check vsid & api */
- if ((pte0 & 0x7FFFFFBF) == va) {
- if (good == -1) {
- good = i;
- keep = pte1;
- } else {
- /* All matches should have equal RPN, WIMG & PP */
- if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
- if (loglevel > 0)
- fprintf(logfile, "Bad RPN/WIMG/PP\n");
- return -1;
- }
- }
- /* Check access rights */
- if (key == 0) {
- access = PAGE_READ;
- if ((pte1 & 0x00000003) != 0x3)
- access |= PAGE_WRITE;
- } else {
- switch (pte1 & 0x00000003) {
- case 0x0:
- access = 0;
- break;
- case 0x1:
- case 0x3:
- access = PAGE_READ;
- break;
- case 0x2:
- access = PAGE_READ | PAGE_WRITE;
- break;
- }
- }
- if (ret < 0) {
- if ((rw == 0 && (access & PAGE_READ)) ||
- (rw == 1 && (access & PAGE_WRITE))) {
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "PTE access granted !\n");
-#endif
- good = i;
- keep = pte1;
- ret = 0;
- } else {
- /* Access right violation */
- ret = -2;
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "PTE access rejected\n");
+ fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
+ "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
+ pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem);
+ }
#endif
- }
- *prot = access;
- }
- }
+ switch (pte_check(ctx, pte0, pte1, h, rw)) {
+ case -3:
+ /* PTE inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ good = i;
+ break;
+ case -1:
+ default:
+ /* No PTE match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all PTEs consistency
+ * but if we can speed-up the whole thing as the
+ * result would be undefined if PTEs are not consistent.
+ */
+ ret = 0;
+ good = i;
+ goto done;
}
}
if (good != -1) {
- *RPN = keep & 0xFFFFF000;
+ done:
#if defined (DEBUG_MMU)
if (loglevel > 0) {
- fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
- *RPN, *prot, ret);
- }
+ fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
+ ctx->raddr, ctx->prot, ret);
+ }
#endif
/* Update page flags */
- if (!(keep & 0x00000100)) {
- /* Access flag */
- keep |= 0x00000100;
- store = 1;
- }
- if (!(keep & 0x00000080)) {
- if (rw && ret == 0) {
- /* Change flag */
- keep |= 0x00000080;
- store = 1;
- } else {
- /* Force page fault for first write access */
- *prot &= ~PAGE_WRITE;
- }
- }
- if (store) {
- stl_phys_notdirty(base + (good * 8) + 4, keep);
- }
+ pte1 = ctx->raddr;
+ if (pte_update_flags(ctx, &pte1, ret, rw) == 1)
+ stl_phys_notdirty(base + (good * 8) + 4, pte1);
}
return ret;
}
-static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
+static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
+ target_phys_addr_t hash,
+ target_phys_addr_t mask)
{
return (sdr1 & 0xFFFF0000) | (hash & mask);
}
/* Perform segment based translation */
-static int get_segment (CPUState *env, uint32_t *real, int *prot,
- uint32_t virtual, int rw, int type)
+static int get_segment (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
- uint32_t pg_addr, sdr, ptem, vsid, pgidx;
- uint32_t hash, mask;
- uint32_t sr;
- int key;
+ target_phys_addr_t sdr, hash, mask;
+ target_ulong sr, vsid, pgidx;
int ret = -1, ret2;
- sr = env->sr[virtual >> 28];
+ sr = env->sr[eaddr >> 28];
#if defined (DEBUG_MMU)
if (loglevel > 0) {
- fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
- "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
- virtual, virtual >> 28, sr, env->nip,
- env->lr, msr_ir, msr_dr, msr_pr, rw, type);
+ fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
+ "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, eaddr >> 28, sr, env->nip,
+ env->lr, msr_ir, msr_dr, msr_pr, rw, type);
}
#endif
- key = (((sr & 0x20000000) && msr_pr == 1) ||
- ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
+ ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
+ ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
if ((sr & 0x80000000) == 0) {
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
- key, sr & 0x10000000);
+ if (loglevel > 0)
+ fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
+ ctx->key, sr & 0x10000000);
#endif
/* Check if instruction fetch is allowed, if needed */
if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
/* Page address translation */
+ pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF;
vsid = sr & 0x00FFFFFF;
- pgidx = (virtual >> 12) & 0xFFFF;
- sdr = env->sdr1;
hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
+ /* Primary table address */
+ sdr = env->sdr1;
mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
- pg_addr = get_pgaddr(sdr, hash, mask);
- ptem = (vsid << 7) | (pgidx >> 10);
+ ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask);
+ /* Secondary table address */
+ hash = (~hash) & 0x01FFFFC0;
+ ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask);
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (target_ulong)-1;
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ /* Software TLB search */
+ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+ } else {
#if defined (DEBUG_MMU)
- if (loglevel > 0) {
- fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
- "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash,
- pg_addr);
- }
+ if (loglevel > 0) {
+ fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
+ "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx,
+ hash, ctx->pg_addr[0]);
+ }
#endif
- /* Primary table lookup */
- ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
- if (ret < 0) {
- /* Secondary table lookup */
- hash = (~hash) & 0x01FFFFC0;
- pg_addr = get_pgaddr(sdr, hash, mask);
+ /* Primary table lookup */
+ ret = find_pte(ctx, 0, rw);
+ if (ret < 0) {
+ /* Secondary table lookup */
#if defined (DEBUG_MMU)
- if (virtual != 0xEFFFFFFF && loglevel > 0) {
- fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
- "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx,
- hash, pg_addr);
- }
+ if (eaddr != 0xEFFFFFFF && loglevel > 0) {
+ fprintf(logfile,
+ "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
+ "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid,
+ pgidx, hash, ctx->pg_addr[1]);
+ }
#endif
- ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
- if (ret2 != -1)
- ret = ret2;
+ ret2 = find_pte(ctx, 1, rw);
+ if (ret2 != -1)
+ ret = ret2;
+ }
}
} else {
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "No access allowed\n");
+ if (loglevel > 0)
+ fprintf(logfile, "No access allowed\n");
#endif
- ret = -3;
+ ret = -3;
}
} else {
#if defined (DEBUG_MMU)
if (loglevel > 0)
- fprintf(logfile, "direct store...\n");
+ fprintf(logfile, "direct store...\n");
#endif
/* Direct-store segment : absolutely *BUGGY* for now */
switch (type) {
@@ -356,7 +603,7 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
/* Should make the instruction do no-op.
* As it already do no-op, it's quite easy :-)
*/
- *real = virtual;
+ ctx->raddr = eaddr;
return 0;
case ACCESS_EXT:
/* eciwx or ecowx */
@@ -370,8 +617,8 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
"address translation\n");
return -4;
}
- if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
- *real = virtual;
+ if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ ctx->raddr = eaddr;
ret = 2;
} else {
ret = -2;
@@ -381,8 +628,44 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
return ret;
}
-static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
- uint32_t address, int rw, int access_type)
+static int check_physical (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw)
+{
+ int in_plb, ret;
+
+ ctx->raddr = eaddr;
+ ctx->prot = PAGE_READ;
+ ret = 0;
+ if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) {
+ /* 403 family add some particular protections,
+ * using PBL/PBU registers for accesses with no translation.
+ */
+ in_plb =
+ /* Check PLB validity */
+ (env->pb[0] < env->pb[1] &&
+ /* and address in plb area */
+ eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+ (env->pb[2] < env->pb[3] &&
+ eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+ if (in_plb ^ msr_px) {
+ /* Access in protected area */
+ if (rw == 1) {
+ /* Access is not allowed */
+ ret = -2;
+ }
+ } else {
+ /* Read-write access is allowed */
+ ctx->prot |= PAGE_WRITE;
+ }
+ } else {
+ ctx->prot |= PAGE_WRITE;
+ }
+
+ return ret;
+}
+
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+ int rw, int access_type, int check_BATs)
{
int ret;
#if 0
@@ -393,46 +676,46 @@ static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
if ((access_type == ACCESS_CODE && msr_ir == 0) ||
(access_type != ACCESS_CODE && msr_dr == 0)) {
/* No address translation */
- *physical = address & ~0xFFF;
- *prot = PAGE_READ | PAGE_WRITE;
- ret = 0;
+ ret = check_physical(env, ctx, eaddr, rw);
} else {
/* Try to find a BAT */
- ret = get_bat(env, physical, prot, address, rw, access_type);
+ ret = -1;
+ if (check_BATs)
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
if (ret < 0) {
/* We didn't match any BAT entry */
- ret = get_segment(env, physical, prot, address, rw, access_type);
+ ret = get_segment(env, ctx, eaddr, rw, access_type);
}
}
#if 0
if (loglevel > 0) {
- fprintf(logfile, "%s address %08x => %08x\n",
- __func__, address, *physical);
+ fprintf(logfile, "%s address %08x => %08lx\n",
+ __func__, eaddr, ctx->raddr);
}
-#endif
+#endif
+
return ret;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_ulong cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
- uint32_t phys_addr;
- int prot;
+ mmu_ctx_t ctx;
- if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
return -1;
- return phys_addr;
+
+ return ctx.raddr & TARGET_PAGE_MASK;
}
/* Perform address translation */
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
int is_user, int is_softmmu)
{
- uint32_t physical;
- int prot;
+ mmu_ctx_t ctx;
int exception = 0, error_code = 0;
int access_type;
int ret = 0;
-
+
if (rw == 2) {
/* code access */
rw = 0;
@@ -444,35 +727,39 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
access_type = ACCESS_INT;
// access_type = env->access_type;
}
- if (env->user_mode_only) {
- /* user mode only emulation */
- ret = -2;
- goto do_fault;
- }
- ret = get_physical_address(env, &physical, &prot,
- address, rw, access_type);
+ ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
if (ret == 0) {
- ret = tlb_set_page(env, address & ~0xFFF, physical, prot,
- is_user, is_softmmu);
+ ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ is_user, is_softmmu);
} else if (ret < 0) {
- do_fault:
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- cpu_dump_state(env, logfile, fprintf, 0);
+ if (loglevel > 0)
+ cpu_dump_state(env, logfile, fprintf, 0);
#endif
if (access_type == ACCESS_CODE) {
exception = EXCP_ISI;
switch (ret) {
case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
+ /* No matches in page tables or TLB */
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ exception = EXCP_I_TLBMISS;
+ env->spr[SPR_IMISS] = address;
+ env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+ error_code = 1 << 18;
+ goto tlb_miss;
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+ } else {
+ error_code = 0x40000000;
+ }
break;
case -2:
/* Access rights violation */
error_code = 0x08000000;
break;
case -3:
- /* No execute protection violation */
+ /* No execute protection violation */
error_code = 0x10000000;
break;
case -4:
@@ -490,8 +777,28 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
exception = EXCP_DSI;
switch (ret) {
case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
+ /* No matches in page tables or TLB */
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ if (rw == 1) {
+ exception = EXCP_DS_TLBMISS;
+ error_code = 1 << 16;
+ } else {
+ exception = EXCP_DL_TLBMISS;
+ error_code = 0;
+ }
+ env->spr[SPR_DMISS] = address;
+ env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+ tlb_miss:
+ error_code |= ctx.key << 19;
+ env->spr[SPR_HASH1] = ctx.pg_addr[0];
+ env->spr[SPR_HASH2] = ctx.pg_addr[1];
+ /* Do not alter DAR nor DSISR */
+ goto out;
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+ } else {
+ error_code = 0x40000000;
+ }
break;
case -2:
/* Access rights violation */
@@ -514,7 +821,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
error_code = 0x04100000;
break;
default:
- printf("DSI: invalid exception (%d)\n", ret);
+ printf("DSI: invalid exception (%d)\n", ret);
exception = EXCP_PROGRAM;
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
break;
@@ -528,10 +835,11 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
}
if (exception == EXCP_DSI && rw == 1)
error_code |= 0x02000000;
- /* Store fault address */
- env->spr[SPR_DAR] = address;
+ /* Store fault address */
+ env->spr[SPR_DAR] = address;
env->spr[SPR_DSISR] = error_code;
}
+ out:
#if 0
printf("%s: set exception to %d %02x\n",
__func__, exception, error_code);
@@ -540,9 +848,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
env->error_code = error_code;
ret = 1;
}
+
return ret;
}
-#endif
/*****************************************************************************/
/* BATs management */
@@ -551,11 +859,14 @@ static inline void do_invalidate_BAT (CPUPPCState *env,
target_ulong BATu, target_ulong mask)
{
target_ulong base, end, page;
+
base = BATu & ~0x0001FFFF;
end = base + mask + 0x00020000;
#if defined (DEBUG_BATS)
- if (loglevel != 0)
- fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask);
+ if (loglevel != 0) {
+ fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n",
+ base, end, mask);
+ }
#endif
for (page = base; page != end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
@@ -608,8 +919,7 @@ void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
(env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
-#if defined(FLUSH_ALL_TLBS)
+#else
tlb_flush(env, 1);
#endif
}
@@ -663,24 +973,8 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
env->DBAT[1][nr] = value;
}
-static inline void invalidate_all_tlbs (CPUPPCState *env)
-{
- /* XXX: this needs to be completed for sotware driven TLB support */
- tlb_flush(env, 1);
-}
-
/*****************************************************************************/
/* Special registers manipulation */
-target_ulong do_load_nip (CPUPPCState *env)
-{
- return env->nip;
-}
-
-void do_store_nip (CPUPPCState *env, target_ulong value)
-{
- env->nip = value;
-}
-
target_ulong do_load_sdr1 (CPUPPCState *env)
{
return env->sdr1;
@@ -695,7 +989,7 @@ void do_store_sdr1 (CPUPPCState *env, target_ulong value)
#endif
if (env->sdr1 != value) {
env->sdr1 = value;
- invalidate_all_tlbs(env);
+ tlb_flush(env, 1);
}
}
@@ -724,34 +1018,13 @@ void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
tlb_flush_page(env, page);
}
#else
- invalidate_all_tlbs(env);
+ tlb_flush(env, 1);
#endif
}
}
+#endif /* !defined (CONFIG_USER_ONLY) */
-uint32_t do_load_cr (CPUPPCState *env)
-{
- return (env->crf[0] << 28) |
- (env->crf[1] << 24) |
- (env->crf[2] << 20) |
- (env->crf[3] << 16) |
- (env->crf[4] << 12) |
- (env->crf[5] << 8) |
- (env->crf[6] << 4) |
- (env->crf[7] << 0);
-}
-
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask)
-{
- int i, sh;
-
- for (i = 0, sh = 7; i < 8; i++, sh --) {
- if (mask & (1 << sh))
- env->crf[i] = (value >> (sh * 4)) & 0xFUL;
- }
-}
-
-uint32_t do_load_xer (CPUPPCState *env)
+uint32_t ppc_load_xer (CPUPPCState *env)
{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
@@ -760,7 +1033,7 @@ uint32_t do_load_xer (CPUPPCState *env)
(xer_cmp << XER_CMP);
}
-void do_store_xer (CPUPPCState *env, uint32_t value)
+void ppc_store_xer (CPUPPCState *env, uint32_t value)
{
xer_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01;
@@ -769,40 +1042,58 @@ void do_store_xer (CPUPPCState *env, uint32_t value)
xer_bc = (value >> XER_BC) & 0x3F;
}
-target_ulong do_load_msr (CPUPPCState *env)
+/* Swap temporary saved registers with GPRs */
+static inline void swap_gpr_tgpr (CPUPPCState *env)
{
- return (msr_vr << MSR_VR) |
- (msr_ap << MSR_AP) |
- (msr_sa << MSR_SA) |
- (msr_key << MSR_KEY) |
- (msr_pow << MSR_POW) |
- (msr_tlb << MSR_TLB) |
- (msr_ile << MSR_ILE) |
- (msr_ee << MSR_EE) |
- (msr_pr << MSR_PR) |
- (msr_fp << MSR_FP) |
- (msr_me << MSR_ME) |
- (msr_fe0 << MSR_FE0) |
- (msr_se << MSR_SE) |
- (msr_be << MSR_BE) |
- (msr_fe1 << MSR_FE1) |
- (msr_al << MSR_AL) |
- (msr_ip << MSR_IP) |
- (msr_ir << MSR_IR) |
- (msr_dr << MSR_DR) |
- (msr_pe << MSR_PE) |
- (msr_px << MSR_PX) |
- (msr_ri << MSR_RI) |
- (msr_le << MSR_LE);
+ ppc_gpr_t tmp;
+
+ tmp = env->gpr[0];
+ env->gpr[0] = env->tgpr[0];
+ env->tgpr[0] = tmp;
+ tmp = env->gpr[1];
+ env->gpr[1] = env->tgpr[1];
+ env->tgpr[1] = tmp;
+ tmp = env->gpr[2];
+ env->gpr[2] = env->tgpr[2];
+ env->tgpr[2] = tmp;
+ tmp = env->gpr[3];
+ env->gpr[3] = env->tgpr[3];
+ env->tgpr[3] = tmp;
}
-void do_compute_hflags (CPUPPCState *env)
+/* GDBstub can read and write MSR... */
+target_ulong do_load_msr (CPUPPCState *env)
{
- /* Compute current hflags */
- env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
- (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
- (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
- (msr_se << MSR_SE) | (msr_be << MSR_BE);
+ return
+#if defined (TARGET_PPC64)
+ (msr_sf << MSR_SF) |
+ (msr_isf << MSR_ISF) |
+ (msr_hv << MSR_HV) |
+#endif
+ (msr_ucle << MSR_UCLE) |
+ (msr_vr << MSR_VR) | /* VR / SPE */
+ (msr_ap << MSR_AP) |
+ (msr_sa << MSR_SA) |
+ (msr_key << MSR_KEY) |
+ (msr_pow << MSR_POW) | /* POW / WE */
+ (msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */
+ (msr_ile << MSR_ILE) |
+ (msr_ee << MSR_EE) |
+ (msr_pr << MSR_PR) |
+ (msr_fp << MSR_FP) |
+ (msr_me << MSR_ME) |
+ (msr_fe0 << MSR_FE0) |
+ (msr_se << MSR_SE) | /* SE / DWE / UBLE */
+ (msr_be << MSR_BE) | /* BE / DE */
+ (msr_fe1 << MSR_FE1) |
+ (msr_al << MSR_AL) |
+ (msr_ip << MSR_IP) |
+ (msr_ir << MSR_IR) | /* IR / IS */
+ (msr_dr << MSR_DR) | /* DR / DS */
+ (msr_pe << MSR_PE) | /* PE / EP */
+ (msr_px << MSR_PX) | /* PX / PMM */
+ (msr_ri << MSR_RI) |
+ (msr_le << MSR_LE);
}
void do_store_msr (CPUPPCState *env, target_ulong value)
@@ -812,10 +1103,7 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
value &= env->msr_mask;
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
- /* Flush all tlb when changing translation mode
- * When using software driven TLB, we may also need to reload
- * all defined TLBs
- */
+ /* Flush all tlb when changing translation mode */
tlb_flush(env, 1);
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
@@ -824,35 +1112,52 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
}
#endif
- msr_vr = (value >> MSR_VR) & 1;
- msr_ap = (value >> MSR_AP) & 1;
- msr_sa = (value >> MSR_SA) & 1;
- msr_key = (value >> MSR_KEY) & 1;
- msr_pow = (value >> MSR_POW) & 1;
- msr_tlb = (value >> MSR_TLB) & 1;
- msr_ile = (value >> MSR_ILE) & 1;
- msr_ee = (value >> MSR_EE) & 1;
- msr_pr = (value >> MSR_PR) & 1;
- msr_fp = (value >> MSR_FP) & 1;
- msr_me = (value >> MSR_ME) & 1;
- msr_fe0 = (value >> MSR_FE0) & 1;
- msr_se = (value >> MSR_SE) & 1;
- msr_be = (value >> MSR_BE) & 1;
- msr_fe1 = (value >> MSR_FE1) & 1;
- msr_al = (value >> MSR_AL) & 1;
- msr_ip = (value >> MSR_IP) & 1;
- msr_ir = (value >> MSR_IR) & 1;
- msr_dr = (value >> MSR_DR) & 1;
- msr_pe = (value >> MSR_PE) & 1;
- msr_px = (value >> MSR_PX) & 1;
- msr_ri = (value >> MSR_RI) & 1;
- msr_le = (value >> MSR_LE) & 1;
+ switch (PPC_EXCP(env)) {
+ case PPC_FLAGS_EXCP_602:
+ case PPC_FLAGS_EXCP_603:
+ if (((value >> MSR_TGPR) & 1) != msr_tgpr) {
+ /* Swap temporary saved registers with GPRs */
+ swap_gpr_tgpr(env);
+ }
+ break;
+ default:
+ break;
+ }
+#if defined (TARGET_PPC64)
+ msr_sf = (value >> MSR_SF) & 1;
+ msr_isf = (value >> MSR_ISF) & 1;
+ msr_hv = (value >> MSR_HV) & 1;
+#endif
+ msr_ucle = (value >> MSR_UCLE) & 1;
+ msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */
+ msr_ap = (value >> MSR_AP) & 1;
+ msr_sa = (value >> MSR_SA) & 1;
+ msr_key = (value >> MSR_KEY) & 1;
+ msr_pow = (value >> MSR_POW) & 1; /* POW / WE */
+ msr_tlb = (value >> MSR_TLB) & 1; /* TLB / TGPR / CE */
+ msr_ile = (value >> MSR_ILE) & 1;
+ msr_ee = (value >> MSR_EE) & 1;
+ msr_pr = (value >> MSR_PR) & 1;
+ msr_fp = (value >> MSR_FP) & 1;
+ msr_me = (value >> MSR_ME) & 1;
+ msr_fe0 = (value >> MSR_FE0) & 1;
+ msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */
+ msr_be = (value >> MSR_BE) & 1; /* BE / DE */
+ msr_fe1 = (value >> MSR_FE1) & 1;
+ msr_al = (value >> MSR_AL) & 1;
+ msr_ip = (value >> MSR_IP) & 1;
+ msr_ir = (value >> MSR_IR) & 1; /* IR / IS */
+ msr_dr = (value >> MSR_DR) & 1; /* DR / DS */
+ msr_pe = (value >> MSR_PE) & 1; /* PE / EP */
+ msr_px = (value >> MSR_PX) & 1; /* PX / PMM */
+ msr_ri = (value >> MSR_RI) & 1;
+ msr_le = (value >> MSR_LE) & 1;
do_compute_hflags(env);
enter_pm = 0;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_7x0:
- if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
+ if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
enter_pm = 1;
break;
default:
@@ -866,75 +1171,16 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
}
}
-float64 do_load_fpscr (CPUPPCState *env)
+void do_compute_hflags (CPUPPCState *env)
{
- /* The 32 MSB of the target fpr are undefined.
- * They'll be zero...
- */
- union {
- float64 d;
- struct {
- uint32_t u[2];
- } s;
- } u;
- int i;
-
-#ifdef WORDS_BIGENDIAN
-#define WORD0 0
-#define WORD1 1
-#else
-#define WORD0 1
-#define WORD1 0
+ /* Compute current hflags */
+ env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
+ (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
+ (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
+ (msr_se << MSR_SE) | (msr_be << MSR_BE);
+#if defined (TARGET_PPC64)
+ env->hflags |= (msr_sf << MSR_SF) | (msr_hv << MSR_HV);
#endif
- u.s.u[WORD0] = 0;
- u.s.u[WORD1] = 0;
- for (i = 0; i < 8; i++)
- u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
- return u.d;
-}
-
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask)
-{
- /*
- * We use only the 32 LSB of the incoming fpr
- */
- union {
- double d;
- struct {
- uint32_t u[2];
- } s;
- } u;
- int i, rnd_type;
-
- u.d = f;
- if (mask & 0x80)
- env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
- for (i = 1; i < 7; i++) {
- if (mask & (1 << (7 - i)))
- env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
- }
- /* TODO: update FEX & VX */
- /* Set rounding mode */
- switch (env->fpscr[0] & 0x3) {
- case 0:
- /* Best approximation (round to nearest) */
- rnd_type = float_round_nearest_even;
- break;
- case 1:
- /* Smaller magnitude (round toward zero) */
- rnd_type = float_round_to_zero;
- break;
- case 2:
- /* Round toward +infinite */
- rnd_type = float_round_up;
- break;
- default:
- case 3:
- /* Round toward -infinite */
- rnd_type = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_type, &env->fp_status);
}
/*****************************************************************************/
@@ -944,17 +1190,18 @@ void do_interrupt (CPUState *env)
{
env->exception_index = -1;
}
-#else
+#else /* defined (CONFIG_USER_ONLY) */
static void dump_syscall(CPUState *env)
{
- fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n",
+ fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x "
+ "r5=0x%08x r6=0x%08x nip=0x%08x\n",
env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->nip);
}
void do_interrupt (CPUState *env)
{
- target_ulong msr, *srr_0, *srr_1, tmp;
+ target_ulong msr, *srr_0, *srr_1;
int excp;
excp = env->exception_index;
@@ -967,7 +1214,7 @@ void do_interrupt (CPUState *env)
if (loglevel != 0) {
fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
(unsigned long)env->nip, excp, env->error_code);
- cpu_dump_state(env, logfile, fprintf, 0);
+ cpu_dump_state(env, logfile, fprintf, 0);
}
}
#endif
@@ -978,7 +1225,7 @@ void do_interrupt (CPUState *env)
msr_pow = 0;
/* Generate informations in save/restore registers */
switch (excp) {
- /* Generic PowerPC exceptions */
+ /* Generic PowerPC exceptions */
case EXCP_RESET: /* 0x0100 */
if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
if (msr_ip)
@@ -993,7 +1240,7 @@ void do_interrupt (CPUState *env)
if (msr_me == 0) {
cpu_abort(env, "Machine check exception while not allowed\n");
}
- if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
+ if (unlikely(PPC_EXCP(env) == PPC_FLAGS_EXCP_40x)) {
srr_0 = &env->spr[SPR_40x_SRR2];
srr_1 = &env->spr[SPR_40x_SRR3];
}
@@ -1004,26 +1251,26 @@ void do_interrupt (CPUState *env)
/* data location address has been stored
* when the fault has been detected
*/
- msr &= ~0xFFFF0000;
+ msr &= ~0xFFFF0000;
#if defined (DEBUG_EXCEPTIONS)
- if (loglevel) {
- fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
- env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- } else {
- printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
- env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- }
+ if (loglevel) {
+ fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
+ env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ } else {
+ printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
+ env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ }
#endif
goto store_next;
case EXCP_ISI: /* 0x0400 */
/* Store exception cause */
- msr &= ~0xFFFF0000;
+ msr &= ~0xFFFF0000;
msr |= env->error_code;
#if defined (DEBUG_EXCEPTIONS)
- if (loglevel != 0) {
- fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
- msr, env->nip);
- }
+ if (loglevel != 0) {
+ fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
+ msr, env->nip);
+ }
#endif
goto store_next;
case EXCP_EXTERNAL: /* 0x0500 */
@@ -1039,7 +1286,7 @@ void do_interrupt (CPUState *env)
}
goto store_next;
case EXCP_ALIGN: /* 0x0600 */
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
+ if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) {
/* Store exception cause */
/* Get rS/rD and rA from faulting opcode */
env->spr[SPR_DSISR] |=
@@ -1063,7 +1310,7 @@ void do_interrupt (CPUState *env)
printf("Ignore floating point exception\n");
#endif
return;
- }
+ }
msr |= 0x00100000;
/* Set FX */
env->fpscr[7] |= 0x8;
@@ -1071,21 +1318,21 @@ void do_interrupt (CPUState *env)
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
env->fpscr[7] |= 0x4;
- break;
+ break;
case EXCP_INVAL:
- // printf("Invalid instruction at 0x%08x\n", env->nip);
+ // printf("Invalid instruction at 0x%08x\n", env->nip);
msr |= 0x00080000;
- break;
+ break;
case EXCP_PRIV:
msr |= 0x00040000;
- break;
+ break;
case EXCP_TRAP:
msr |= 0x00020000;
break;
default:
/* Should never occur */
- break;
- }
+ break;
+ }
msr |= 0x00010000;
goto store_current;
case EXCP_NO_FP: /* 0x0800 */
@@ -1125,7 +1372,7 @@ void do_interrupt (CPUState *env)
cpu_abort(env, "Floating point assist exception "
"is not implemented yet !\n");
goto store_next;
- /* 64 bits PowerPC exceptions */
+ /* 64 bits PowerPC exceptions */
case EXCP_DSEG: /* 0x0380 */
/* XXX: TODO */
cpu_abort(env, "Data segment exception is not implemented yet !\n");
@@ -1141,14 +1388,16 @@ void do_interrupt (CPUState *env)
/* Requeue it */
env->interrupt_request |= CPU_INTERRUPT_TIMER;
#endif
- return;
+ return;
}
- cpu_abort(env,
- "Hypervisor decrementer exception is not implemented yet !\n");
+ /* XXX: TODO */
+ cpu_abort(env, "Hypervisor decrementer exception is not implemented "
+ "yet !\n");
goto store_next;
/* Implementation specific exceptions */
case 0x0A00:
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
+ if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 ||
+ env->spr[SPR_PVR] == CPU_PPC_G2LE)) {
/* Critical interrupt on G2 */
/* XXX: TODO */
cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
@@ -1186,9 +1435,10 @@ void do_interrupt (CPUState *env)
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* ITLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- msr_tgpr = 1;
goto store_gprs;
+ case PPC_FLAGS_EXCP_7x5:
+ /* ITLBMISS on 745/755 */
+ goto tlb_miss;
default:
cpu_abort(env, "Invalid exception 0x1000 !\n");
break;
@@ -1198,8 +1448,8 @@ void do_interrupt (CPUState *env)
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* FIT on 4xx */
- cpu_abort(env, "40x FIT exception is not implemented yet !\n");
/* XXX: TODO */
+ cpu_abort(env, "40x FIT exception is not implemented yet !\n");
goto store_next;
default:
cpu_abort(env, "Invalid exception 0x1010 !\n");
@@ -1230,9 +1480,10 @@ void do_interrupt (CPUState *env)
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* DLTLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- msr_tgpr = 1;
goto store_gprs;
+ case PPC_FLAGS_EXCP_7x5:
+ /* DLTLBMISS on 745/755 */
+ goto tlb_miss;
default:
cpu_abort(env, "Invalid exception 0x1100 !\n");
break;
@@ -1249,37 +1500,44 @@ void do_interrupt (CPUState *env)
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* DSTLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- msr_tgpr = 1;
store_gprs:
+ /* Swap temporary saved registers with GPRs */
+ swap_gpr_tgpr(env);
+ msr_tgpr = 1;
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
- fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
- "DC %08x H1 %08x H2 %08x %08x\n",
- excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
- env->spr[SPR_IMISS], env->spr[SPR_DMISS],
- env->spr[SPR_ICMP], env->spr[SPR_DCMP],
- env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
+ const unsigned char *es;
+ target_ulong *miss, *cmp;
+ int en;
+ if (excp == 0x1000) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == 0x1100)
+ es = "DL";
+ else
+ es = "DS";
+ en = 'D';
+ miss = &env->spr[SPR_DMISS];
+ cmp = &env->spr[SPR_DCMP];
+ }
+ fprintf(logfile, "6xx %sTLB miss: %cM %08x %cC %08x "
+ "H1 %08x H2 %08x %08x\n", es, en, *miss, en, *cmp,
+ env->spr[SPR_HASH1], env->spr[SPR_HASH2],
env->error_code);
}
#endif
- /* Swap temporary saved registers with GPRs */
- tmp = env->gpr[0];
- env->gpr[0] = env->tgpr[0];
- env->tgpr[0] = tmp;
- tmp = env->gpr[1];
- env->gpr[1] = env->tgpr[1];
- env->tgpr[1] = tmp;
- tmp = env->gpr[2];
- env->gpr[2] = env->tgpr[2];
- env->tgpr[2] = tmp;
- tmp = env->gpr[3];
- env->gpr[3] = env->tgpr[3];
- env->tgpr[3] = tmp;
+ goto tlb_miss;
+ case PPC_FLAGS_EXCP_7x5:
+ /* DSTLBMISS on 745/755 */
+ tlb_miss:
+ msr &= ~0xF83F0000;
msr |= env->crf[0] << 28;
msr |= env->error_code; /* key, D/I, S/L bits */
/* Set way using a LRU mechanism */
- msr |= (env->last_way ^ 1) << 17;
+ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
goto store_next;
default:
cpu_abort(env, "Invalid exception 0x1200 !\n");
@@ -1324,6 +1582,7 @@ void do_interrupt (CPUState *env)
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_602:
/* Watchdog on 602 */
+ /* XXX: TODO */
cpu_abort(env,
"602 watchdog exception is not implemented yet !\n");
goto store_next;
diff --git a/target-ppc/mfrom_table.c b/target-ppc/mfrom_table.c
new file mode 100644
index 0000000000..4c27173187
--- /dev/null
+++ b/target-ppc/mfrom_table.c
@@ -0,0 +1,79 @@
+static const uint8_t mfrom_ROM_table[602] =
+{
+ 77, 77, 76, 76, 75, 75, 74, 74,
+ 73, 73, 72, 72, 71, 71, 70, 70,
+ 69, 69, 68, 68, 68, 67, 67, 66,
+ 66, 65, 65, 64, 64, 64, 63, 63,
+ 62, 62, 61, 61, 61, 60, 60, 59,
+ 59, 58, 58, 58, 57, 57, 56, 56,
+ 56, 55, 55, 54, 54, 54, 53, 53,
+ 53, 52, 52, 51, 51, 51, 50, 50,
+ 50, 49, 49, 49, 48, 48, 47, 47,
+ 47, 46, 46, 46, 45, 45, 45, 44,
+ 44, 44, 43, 43, 43, 42, 42, 42,
+ 42, 41, 41, 41, 40, 40, 40, 39,
+ 39, 39, 39, 38, 38, 38, 37, 37,
+ 37, 37, 36, 36, 36, 35, 35, 35,
+ 35, 34, 34, 34, 34, 33, 33, 33,
+ 33, 32, 32, 32, 32, 31, 31, 31,
+ 31, 30, 30, 30, 30, 29, 29, 29,
+ 29, 28, 28, 28, 28, 28, 27, 27,
+ 27, 27, 26, 26, 26, 26, 26, 25,
+ 25, 25, 25, 25, 24, 24, 24, 24,
+ 24, 23, 23, 23, 23, 23, 23, 22,
+ 22, 22, 22, 22, 21, 21, 21, 21,
+ 21, 21, 20, 20, 20, 20, 20, 20,
+ 19, 19, 19, 19, 19, 19, 19, 18,
+ 18, 18, 18, 18, 18, 17, 17, 17,
+ 17, 17, 17, 17, 16, 16, 16, 16,
+ 16, 16, 16, 16, 15, 15, 15, 15,
+ 15, 15, 15, 15, 14, 14, 14, 14,
+ 14, 14, 14, 14, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0,
+};
diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c
new file mode 100644
index 0000000000..ab4b1cc0bd
--- /dev/null
+++ b/target-ppc/mfrom_table_gen.c
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+
+int main (void)
+{
+ double d;
+ uint8_t n;
+ int i;
+
+ printf("static const uint8_t mfrom_ROM_table[602] =\n{\n ");
+ for (i = 0; i < 602; i++) {
+ /* Extremly decomposed:
+ * -T0 / 256
+ * T0 = 256 * log10(10 + 1.0) + 0.5
+ */
+ d = -i;
+ d /= 256.0;
+ d = exp10(d);
+ d += 1.0;
+ d = log10(d);
+ d *= 256;
+ d += 0.5;
+ n = d;
+ printf("%3d, ", n);
+ if ((i & 7) == 7)
+ printf("\n ");
+ }
+ printf("\n};\n");
+
+ return 0;
+}
diff --git a/target-ppc/op.c b/target-ppc/op.c
index ca1dbc5eb4..1bad768117 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -1,7 +1,7 @@
/*
* PowerPC emulation micro-operations for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,7 +22,9 @@
#include "config.h"
#include "exec.h"
+#include "op_helper.h"
+/* XXX: this is to be suppressed */
#define regs (env)
#define Ts0 (int32_t)T0
#define Ts1 (int32_t)T1
@@ -32,7 +34,8 @@
#define FT1 (env->ft1)
#define FT2 (env->ft2)
-#define PPC_OP(name) void glue(op_, name)(void)
+/* XXX: this is to be suppressed... */
+#define PPC_OP(name) void OPPROTO glue(op_, name)(void)
#define REG 0
#include "op_template.h"
@@ -134,31 +137,7 @@
/* set_Rc0 */
PPC_OP(set_Rc0)
{
- uint32_t tmp;
-
- if (Ts0 < 0) {
- tmp = 0x08;
- } else if (Ts0 > 0) {
- tmp = 0x04;
- } else {
- tmp = 0x02;
- }
- tmp |= xer_ov;
- env->crf[0] = tmp;
- RETURN();
-}
-
-/* reset_Rc0 */
-PPC_OP(reset_Rc0)
-{
- env->crf[0] = 0x02 | xer_ov;
- RETURN();
-}
-
-/* set_Rc0_1 */
-PPC_OP(set_Rc0_1)
-{
- env->crf[0] = 0x04 | xer_ov;
+ env->crf[0] = T0 | xer_ov;
RETURN();
}
@@ -170,6 +149,12 @@ PPC_OP(set_Rc1)
}
/* Constants load */
+void OPPROTO op_reset_T0 (void)
+{
+ T0 = 0;
+ RETURN();
+}
+
PPC_OP(set_T0)
{
T0 = PARAM(1);
@@ -182,26 +167,30 @@ PPC_OP(set_T1)
RETURN();
}
+#if 0 // unused
PPC_OP(set_T2)
{
T2 = PARAM(1);
RETURN();
}
+#endif
-/* Generate exceptions */
-PPC_OP(raise_exception_err)
+void OPPROTO op_move_T1_T0 (void)
{
- do_raise_exception_err(PARAM(1), PARAM(2));
+ T1 = T0;
+ RETURN();
}
-PPC_OP(raise_exception)
+/* Generate exceptions */
+PPC_OP(raise_exception_err)
{
- do_raise_exception(PARAM(1));
+ do_raise_exception_err(PARAM(1), PARAM(2));
}
PPC_OP(update_nip)
{
env->nip = PARAM(1);
+ RETURN();
}
PPC_OP(debug)
@@ -209,46 +198,34 @@ PPC_OP(debug)
do_raise_exception(EXCP_DEBUG);
}
-/* Segment registers load and store with immediate index */
-PPC_OP(load_srin)
-{
- T0 = regs->sr[T1 >> 28];
- RETURN();
-}
-PPC_OP(store_srin)
+PPC_OP(exit_tb)
{
- do_store_sr(env, ((uint32_t)T1 >> 28), T0);
- RETURN();
+ EXIT_TB();
}
-PPC_OP(load_sdr1)
+/* Load/store special registers */
+PPC_OP(load_cr)
{
- T0 = regs->sdr1;
+ do_load_cr();
RETURN();
}
-PPC_OP(store_sdr1)
+PPC_OP(store_cr)
{
- do_store_sdr1(env, T0);
+ do_store_cr(PARAM(1));
RETURN();
}
-PPC_OP(exit_tb)
+void OPPROTO op_load_cro (void)
{
- EXIT_TB();
-}
-
-/* Load/store special registers */
-PPC_OP(load_cr)
-{
- T0 = do_load_cr(env);
+ T0 = env->crf[PARAM1];
RETURN();
}
-PPC_OP(store_cr)
+void OPPROTO op_store_cro (void)
{
- do_store_cr(env, T0, PARAM(1));
+ env->crf[PARAM1] = T0;
RETURN();
}
@@ -272,15 +249,47 @@ PPC_OP(load_xer_bc)
RETURN();
}
+void OPPROTO op_store_xer_bc (void)
+{
+ xer_bc = T0;
+ RETURN();
+}
+
PPC_OP(load_xer)
{
- T0 = do_load_xer(env);
+ do_load_xer();
RETURN();
}
PPC_OP(store_xer)
{
- do_store_xer(env, T0);
+ do_store_xer();
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Segment registers load and store */
+PPC_OP(load_sr)
+{
+ T0 = regs->sr[T1];
+ RETURN();
+}
+
+PPC_OP(store_sr)
+{
+ do_store_sr(env, T1, T0);
+ RETURN();
+}
+
+PPC_OP(load_sdr1)
+{
+ T0 = regs->sdr1;
+ RETURN();
+}
+
+PPC_OP(store_sdr1)
+{
+ do_store_sdr1(env, T0);
RETURN();
}
@@ -295,6 +304,7 @@ PPC_OP(store_msr)
do_store_msr(env, T0);
RETURN();
}
+#endif
/* SPR */
PPC_OP(load_spr)
@@ -345,6 +355,7 @@ PPC_OP(load_tbu)
RETURN();
}
+#if !defined(CONFIG_USER_ONLY)
PPC_OP(store_tbl)
{
cpu_ppc_store_tbl(regs, T0);
@@ -360,7 +371,8 @@ PPC_OP(store_tbu)
PPC_OP(load_decr)
{
T0 = cpu_ppc_load_decr(regs);
- }
+ RETURN();
+}
PPC_OP(store_decr)
{
@@ -371,15 +383,16 @@ PPC_OP(store_decr)
PPC_OP(load_ibat)
{
T0 = regs->IBAT[PARAM(1)][PARAM(2)];
+ RETURN();
}
-void op_store_ibatu (void)
+void OPPROTO op_store_ibatu (void)
{
do_store_ibatu(env, PARAM1, T0);
RETURN();
}
-void op_store_ibatl (void)
+void OPPROTO op_store_ibatl (void)
{
#if 1
env->IBAT[1][PARAM1] = T0;
@@ -392,15 +405,16 @@ void op_store_ibatl (void)
PPC_OP(load_dbat)
{
T0 = regs->DBAT[PARAM(1)][PARAM(2)];
+ RETURN();
}
-void op_store_dbatu (void)
+void OPPROTO op_store_dbatu (void)
{
do_store_dbatu(env, PARAM1, T0);
RETURN();
}
-void op_store_dbatl (void)
+void OPPROTO op_store_dbatl (void)
{
#if 1
env->DBAT[1][PARAM1] = T0;
@@ -409,17 +423,18 @@ void op_store_dbatl (void)
#endif
RETURN();
}
+#endif /* !defined(CONFIG_USER_ONLY) */
/* FPSCR */
PPC_OP(load_fpscr)
{
- FT0 = do_load_fpscr(env);
+ do_load_fpscr();
RETURN();
}
PPC_OP(store_fpscr)
{
- do_store_fpscr(env, FT0, PARAM1);
+ do_store_fpscr(PARAM1);
RETURN();
}
@@ -454,6 +469,7 @@ PPC_OP(setcrfbit)
PPC_OP(setlr)
{
regs->lr = PARAM1;
+ RETURN();
}
PPC_OP(goto_tb0)
@@ -469,6 +485,7 @@ PPC_OP(goto_tb1)
PPC_OP(b_T1)
{
regs->nip = T1 & ~3;
+ RETURN();
}
PPC_OP(jz_T0)
@@ -491,11 +508,13 @@ PPC_OP(btest_T1)
PPC_OP(movl_T1_ctr)
{
T1 = regs->ctr;
+ RETURN();
}
PPC_OP(movl_T1_lr)
{
T1 = regs->lr;
+ RETURN();
}
/* tests with result in T0 */
@@ -503,41 +522,49 @@ PPC_OP(movl_T1_lr)
PPC_OP(test_ctr)
{
T0 = regs->ctr;
+ RETURN();
}
PPC_OP(test_ctr_true)
{
T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
+ RETURN();
}
PPC_OP(test_ctr_false)
{
T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
+ RETURN();
}
PPC_OP(test_ctrz)
{
T0 = (regs->ctr == 0);
+ RETURN();
}
PPC_OP(test_ctrz_true)
{
T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
+ RETURN();
}
PPC_OP(test_ctrz_false)
{
T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
+ RETURN();
}
PPC_OP(test_true)
{
T0 = (T0 & PARAM(1));
+ RETURN();
}
PPC_OP(test_false)
{
T0 = ((T0 & PARAM(1)) == 0);
+ RETURN();
}
/* CTR maintenance */
@@ -555,8 +582,7 @@ PPC_OP(add)
RETURN();
}
-void do_addo (void);
-void op_addo (void)
+void OPPROTO op_addo (void)
{
do_addo();
RETURN();
@@ -575,21 +601,19 @@ PPC_OP(addc)
RETURN();
}
-void do_addco (void);
-void op_addco (void)
+void OPPROTO op_addco (void)
{
do_addco();
RETURN();
}
/* add extended */
-void do_adde (void);
-void op_adde (void)
+void OPPROTO op_adde (void)
{
do_adde();
+ RETURN();
}
-void do_addeo (void);
PPC_OP(addeo)
{
do_addeo();
@@ -626,8 +650,7 @@ PPC_OP(addme)
RETURN();
}
-void do_addmeo (void);
-void op_addmeo (void)
+void OPPROTO op_addmeo (void)
{
do_addmeo();
RETURN();
@@ -646,8 +669,7 @@ PPC_OP(addze)
RETURN();
}
-void do_addzeo (void);
-void op_addzeo (void)
+void OPPROTO op_addzeo (void)
{
do_addzeo();
RETURN();
@@ -664,8 +686,7 @@ PPC_OP(divw)
RETURN();
}
-void do_divwo (void);
-void op_divwo (void)
+void OPPROTO op_divwo (void)
{
do_divwo();
RETURN();
@@ -682,8 +703,7 @@ PPC_OP(divwu)
RETURN();
}
-void do_divwuo (void);
-void op_divwuo (void)
+void OPPROTO op_divwuo (void)
{
do_divwuo();
RETURN();
@@ -717,8 +737,7 @@ PPC_OP(mullw)
RETURN();
}
-void do_mullwo (void);
-void op_mullwo (void)
+void OPPROTO op_mullwo (void)
{
do_mullwo();
RETURN();
@@ -733,8 +752,7 @@ PPC_OP(neg)
RETURN();
}
-void do_nego (void);
-void op_nego (void)
+void OPPROTO op_nego (void)
{
do_nego();
RETURN();
@@ -747,8 +765,7 @@ PPC_OP(subf)
RETURN();
}
-void do_subfo (void);
-void op_subfo (void)
+void OPPROTO op_subfo (void)
{
do_subfo();
RETURN();
@@ -766,22 +783,19 @@ PPC_OP(subfc)
RETURN();
}
-void do_subfco (void);
-void op_subfco (void)
+void OPPROTO op_subfco (void)
{
do_subfco();
RETURN();
}
/* substract from extended */
-void do_subfe (void);
-void op_subfe (void)
+void OPPROTO op_subfe (void)
{
do_subfe();
RETURN();
}
-void do_subfeo (void);
PPC_OP(subfeo)
{
do_subfeo();
@@ -810,8 +824,7 @@ PPC_OP(subfme)
RETURN();
}
-void do_subfmeo (void);
-void op_subfmeo (void)
+void OPPROTO op_subfmeo (void)
{
do_subfmeo();
RETURN();
@@ -830,8 +843,7 @@ PPC_OP(subfze)
RETURN();
}
-void do_subfzeo (void);
-void op_subfzeo (void)
+void OPPROTO op_subfzeo (void)
{
do_subfzeo();
RETURN();
@@ -906,18 +918,48 @@ PPC_OP(andc)
}
/* andi. */
-PPC_OP(andi_)
+void OPPROTO op_andi_T0 (void)
{
T0 &= PARAM(1);
RETURN();
}
+void OPPROTO op_andi_T1 (void)
+{
+ T1 &= PARAM1;
+ RETURN();
+}
+
/* count leading zero */
-PPC_OP(cntlzw)
+void OPPROTO op_cntlzw (void)
{
- T1 = T0;
- for (T0 = 32; T1 > 0; T0--)
- T1 = T1 >> 1;
+ int cnt;
+
+ cnt = 0;
+ if (!(T0 & 0xFFFF0000UL)) {
+ cnt += 16;
+ T0 <<= 16;
+ }
+ if (!(T0 & 0xFF000000UL)) {
+ cnt += 8;
+ T0 <<= 8;
+ }
+ if (!(T0 & 0xF0000000UL)) {
+ cnt += 4;
+ T0 <<= 4;
+ }
+ if (!(T0 & 0xC0000000UL)) {
+ cnt += 2;
+ T0 <<= 2;
+ }
+ if (!(T0 & 0x80000000UL)) {
+ cnt++;
+ T0 <<= 1;
+ }
+ if (!(T0 & 0x80000000UL)) {
+ cnt++;
+ }
+ T0 = cnt;
RETURN();
}
@@ -992,48 +1034,15 @@ PPC_OP(xori)
}
/*** Integer rotate ***/
-/* rotate left word immediate then mask insert */
-PPC_OP(rlwimi)
-{
- T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
- RETURN();
-}
-
-/* rotate left immediate then and with mask insert */
-PPC_OP(rotlwi)
-{
- T0 = rotl(T0, PARAM(1));
- RETURN();
-}
-
-PPC_OP(slwi)
-{
- T0 = T0 << PARAM(1);
- RETURN();
-}
-
-PPC_OP(srwi)
+void OPPROTO op_rotl32_T0_T1 (void)
{
- T0 = T0 >> PARAM(1);
+ T0 = rotl32(T0, T1 & 0x1F);
RETURN();
}
-/* rotate left word then and with mask insert */
-PPC_OP(rlwinm)
+void OPPROTO op_rotli32_T0 (void)
{
- T0 = rotl(T0, PARAM(1)) & PARAM(2);
- RETURN();
-}
-
-PPC_OP(rotl)
-{
- T0 = rotl(T0, T1);
- RETURN();
-}
-
-PPC_OP(rlwnm)
-{
- T0 = rotl(T0, T1) & PARAM(1);
+ T0 = rotl32(T0, PARAM1);
RETURN();
}
@@ -1050,7 +1059,7 @@ PPC_OP(slw)
}
/* shift right algebraic word */
-void op_sraw (void)
+void OPPROTO op_sraw (void)
{
do_sraw();
RETURN();
@@ -1080,25 +1089,55 @@ PPC_OP(srw)
RETURN();
}
+void OPPROTO op_sl_T0_T1 (void)
+{
+ T0 = T0 << T1;
+ RETURN();
+}
+
+void OPPROTO op_sli_T0 (void)
+{
+ T0 = T0 << PARAM1;
+ RETURN();
+}
+
+void OPPROTO op_srl_T0_T1 (void)
+{
+ T0 = T0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_srli_T0 (void)
+{
+ T0 = T0 >> PARAM1;
+ RETURN();
+}
+
+void OPPROTO op_srli_T1 (void)
+{
+ T1 = T1 >> PARAM1;
+ RETURN();
+}
+
/*** Floating-Point arithmetic ***/
/* fadd - fadd. */
PPC_OP(fadd)
{
- FT0 += FT1;
+ FT0 = float64_add(FT0, FT1, &env->fp_status);
RETURN();
}
/* fsub - fsub. */
PPC_OP(fsub)
{
- FT0 -= FT1;
+ FT0 = float64_sub(FT0, FT1, &env->fp_status);
RETURN();
}
/* fmul - fmul. */
PPC_OP(fmul)
{
- FT0 *= FT1;
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
RETURN();
}
@@ -1141,14 +1180,16 @@ PPC_OP(fsel)
/* fmadd - fmadd. */
PPC_OP(fmadd)
{
- FT0 = (FT0 * FT1) + FT2;
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
+ FT0 = float64_add(FT0, FT2, &env->fp_status);
RETURN();
}
/* fmsub - fmsub. */
PPC_OP(fmsub)
{
- FT0 = (FT0 * FT1) - FT2;
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
+ FT0 = float64_sub(FT0, FT2, &env->fp_status);
RETURN();
}
@@ -1170,7 +1211,7 @@ PPC_OP(fnmsub)
/* frsp - frsp. */
PPC_OP(frsp)
{
- FT0 = (float)FT0;
+ FT0 = float64_to_float32(FT0, &env->fp_status);
RETURN();
}
@@ -1188,7 +1229,6 @@ PPC_OP(fctiwz)
RETURN();
}
-
/*** Floating-Point compare ***/
/* fcmpu */
PPC_OP(fcmpu)
@@ -1229,12 +1269,14 @@ PPC_OP(fneg)
/* Load and store */
#define MEMSUFFIX _raw
+#include "op_helper.h"
#include "op_mem.h"
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
+#include "op_helper.h"
#include "op_mem.h"
-
#define MEMSUFFIX _kernel
+#include "op_helper.h"
#include "op_mem.h"
#endif
@@ -1247,24 +1289,18 @@ PPC_OP(check_reservation)
}
/* Return from interrupt */
-void do_rfi (void);
-void op_rfi (void)
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_rfi (void)
{
do_rfi();
RETURN();
}
+#endif
/* Trap word */
-void do_tw (uint32_t cmp, int flags);
-void op_tw (void)
-{
- do_tw(T1, PARAM(1));
- RETURN();
-}
-
-void op_twi (void)
+void OPPROTO op_tw (void)
{
- do_tw(PARAM(1), PARAM(2));
+ do_tw(PARAM1);
RETURN();
}
@@ -1275,6 +1311,7 @@ PPC_OP(icbi)
RETURN();
}
+#if !defined(CONFIG_USER_ONLY)
/* tlbia */
PPC_OP(tlbia)
{
@@ -1288,9 +1325,554 @@ PPC_OP(tlbie)
do_tlbie();
RETURN();
}
+#endif
-void op_store_pir (void)
+/* PowerPC 602/603/755 software TLB load instructions */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_6xx_tlbld (void)
+{
+ do_load_6xx_tlb(0);
+ RETURN();
+}
+
+void OPPROTO op_6xx_tlbli (void)
+{
+ do_load_6xx_tlb(1);
+ RETURN();
+}
+#endif
+
+/* 601 specific */
+uint32_t cpu_ppc601_load_rtcl (CPUState *env);
+void OPPROTO op_load_601_rtcl (void)
+{
+ T0 = cpu_ppc601_load_rtcl(env);
+ RETURN();
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env);
+void OPPROTO op_load_601_rtcu (void)
+{
+ T0 = cpu_ppc601_load_rtcu(env);
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value);
+void OPPROTO op_store_601_rtcl (void)
+{
+ cpu_ppc601_store_rtcl(env, T0);
+ RETURN();
+}
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value);
+void OPPROTO op_store_601_rtcu (void)
+{
+ cpu_ppc601_store_rtcu(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_load_601_bat (void)
+{
+ T0 = env->IBAT[PARAM1][PARAM2];
+ RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* 601 unified BATs store.
+ * To avoid using specific MMU code for 601, we store BATs in
+ * IBAT and DBAT simultaneously, then emulate unified BATs.
+ */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_batl (void)
+{
+ int nr = PARAM1;
+
+ env->IBAT[1][nr] = T0;
+ env->DBAT[1][nr] = T0;
+ RETURN();
+}
+
+void OPPROTO op_store_601_batu (void)
+{
+ do_store_601_batu(PARAM1);
+ RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific instructions (POWER bridge) */
+/* XXX: those micro-ops need tests ! */
+void OPPROTO op_POWER_abs (void)
+{
+ if (T0 == INT32_MIN)
+ T0 = INT32_MAX;
+ else if (T0 < 0)
+ T0 = -T0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_abso (void)
+{
+ do_POWER_abso();
+ RETURN();
+}
+
+void OPPROTO op_POWER_clcs (void)
+{
+ do_POWER_clcs();
+ RETURN();
+}
+
+void OPPROTO op_POWER_div (void)
+{
+ do_POWER_div();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divo (void)
+{
+ do_POWER_divo();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divs (void)
+{
+ do_POWER_divs();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divso (void)
+{
+ do_POWER_divso();
+ RETURN();
+}
+
+void OPPROTO op_POWER_doz (void)
+{
+ if (Ts1 > Ts0)
+ T0 = T1 - T0;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_dozo (void)
+{
+ do_POWER_dozo();
+ RETURN();
+}
+
+void OPPROTO op_load_xer_cmp (void)
+{
+ T2 = xer_cmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_maskg (void)
+{
+ do_POWER_maskg();
+ RETURN();
+}
+
+void OPPROTO op_POWER_maskir (void)
+{
+ T0 = (T0 & ~T2) | (T1 & T2);
+ RETURN();
+}
+
+void OPPROTO op_POWER_mul (void)
+{
+ uint64_t tmp;
+
+ tmp = (uint64_t)T0 * (uint64_t)T1;
+ env->spr[SPR_MQ] = tmp >> 32;
+ T0 = tmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_mulo (void)
+{
+ do_POWER_mulo();
+ RETURN();
+}
+
+void OPPROTO op_POWER_nabs (void)
+{
+ if (T0 > 0)
+ T0 = -T0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_nabso (void)
+{
+ /* nabs never overflows */
+ if (T0 > 0)
+ T0 = -T0;
+ xer_ov = 0;
+ RETURN();
+}
+
+/* XXX: factorise POWER rotates... */
+void OPPROTO op_POWER_rlmi (void)
+{
+ T0 = rotl32(T0, T2) & PARAM1;
+ T0 |= T1 & PARAM2;
+ RETURN();
+}
+
+void OPPROTO op_POWER_rrib (void)
+{
+ T2 &= 0x1FUL;
+ T0 = rotl32(T0 & INT32_MIN, T2);
+ T0 |= T1 & ~rotl32(INT32_MIN, T2);
+ RETURN();
+}
+
+void OPPROTO op_POWER_sle (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, T1);
+ T0 = T0 << T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sleq (void)
+{
+ uint32_t tmp = env->spr[SPR_MQ];
+
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, T1);
+ T0 = T0 << T1;
+ T0 |= tmp >> (32 - T1);
+ RETURN();
+}
+
+void OPPROTO op_POWER_sllq (void)
+{
+ uint32_t msk = -1;
+
+ msk = msk << (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ T0 = (T0 << T1) & msk;
+ T0 |= env->spr[SPR_MQ] & ~msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_slq (void)
+{
+ uint32_t msk = -1, tmp;
+
+ msk = msk << (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ tmp = rotl32(T0, T1);
+ T0 = tmp & msk;
+ env->spr[SPR_MQ] = tmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sraq (void)
+{
+ env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL));
+ if (T1 & 0x20UL)
+ T0 = -1L;
+ else
+ T0 = Ts0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sre (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = Ts0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srea (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = T0 >> T1;
+ T0 = Ts0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sreq (void)
+{
+ uint32_t tmp;
+ int32_t msk;
+
+ T1 &= 0x1FUL;
+ msk = INT32_MIN >> T1;
+ tmp = env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ T0 |= tmp & msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srlq (void)
+{
+ uint32_t tmp;
+ int32_t msk;
+
+ msk = INT32_MIN >> (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ tmp = env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ T0 &= msk;
+ T0 |= tmp & ~msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srq (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ RETURN();
+}
+
+/* POWER instructions not implemented in PowerPC 601 */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_POWER_mfsri (void)
+{
+ T1 = T0 >> 28;
+ T0 = env->sr[T1];
+ RETURN();
+}
+
+void OPPROTO op_POWER_rac (void)
+{
+ do_POWER_rac();
+ RETURN();
+}
+
+void OPPROTO op_POWER_rfsvc (void)
+{
+ do_POWER_rfsvc();
+ RETURN();
+}
+#endif
+
+/* PowerPC 602 specific instruction */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_602_mfrom (void)
+{
+ do_op_602_mfrom();
+ RETURN();
+}
+#endif
+
+/* PowerPC 4xx specific micro-ops */
+void OPPROTO op_405_add_T0_T2 (void)
+{
+ T0 = (int32_t)T0 + (int32_t)T2;
+ RETURN();
+}
+
+void OPPROTO op_405_mulchw (void)
+{
+ T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulchwu (void)
+{
+ T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulhhw (void)
+{
+ T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulhhwu (void)
+{
+ T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mullhw (void)
+{
+ T0 = ((int16_t)T0) * ((int16_t)T1);
+ RETURN();
+}
+
+void OPPROTO op_405_mullhwu (void)
+{
+ T0 = ((uint16_t)T0) * ((uint16_t)T1);
+ RETURN();
+}
+
+void OPPROTO op_405_check_ov (void)
+{
+ do_405_check_ov();
+ RETURN();
+}
+
+void OPPROTO op_405_check_sat (void)
+{
+ do_405_check_sat();
+ RETURN();
+}
+
+void OPPROTO op_405_check_ovu (void)
+{
+ if (likely(T0 >= T2)) {
+ xer_ov = 0;
+ } else {
+ xer_ov = 1;
+ xer_so = 1;
+ }
+ RETURN();
+}
+
+void OPPROTO op_405_check_satu (void)
+{
+ if (unlikely(T0 < T2)) {
+ /* Saturate result */
+ T0 = -1;
+ }
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_4xx_load_dcr (void)
+{
+ do_4xx_load_dcr(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_4xx_store_dcr (void)
+{
+ do_4xx_store_dcr(PARAM1);
+ RETURN();
+}
+
+/* Return from critical interrupt :
+ * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1
+ */
+void OPPROTO op_4xx_rfci (void)
+{
+ do_4xx_rfci();
+ RETURN();
+}
+
+void OPPROTO op_4xx_wrte (void)
+{
+ msr_ee = T0 >> 16;
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_lo (void)
+{
+ do_4xx_tlbre_lo();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_hi (void)
+{
+ do_4xx_tlbre_hi();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx (void)
+{
+ do_4xx_tlbsx();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx_ (void)
+{
+ do_4xx_tlbsx_();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_lo (void)
+{
+ do_4xx_tlbwe_lo();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_hi (void)
+{
+ do_4xx_tlbwe_hi();
+ RETURN();
+}
+#endif
+
+/* SPR micro-ops */
+/* 440 specific */
+void OPPROTO op_440_dlmzb (void)
+{
+ do_440_dlmzb();
+ RETURN();
+}
+
+void OPPROTO op_440_dlmzb_update_Rc (void)
+{
+ if (T0 == 8)
+ T0 = 0x2;
+ else if (T0 < 4)
+ T0 = 0x4;
+ else
+ T0 = 0x8;
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_pir (void)
{
env->spr[SPR_PIR] = T0 & 0x0000000FUL;
RETURN();
}
+
+void OPPROTO op_load_403_pb (void)
+{
+ do_load_403_pb(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_store_403_pb (void)
+{
+ do_store_403_pb(PARAM1);
+ RETURN();
+}
+
+target_ulong load_40x_pit (CPUState *env);
+void OPPROTO op_load_40x_pit (void)
+{
+ T0 = load_40x_pit(env);
+ RETURN();
+}
+
+void store_40x_pit (CPUState *env, target_ulong val);
+void OPPROTO op_store_40x_pit (void)
+{
+ store_40x_pit(env, T0);
+ RETURN();
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val);
+void OPPROTO op_store_booke_tcr (void)
+{
+ store_booke_tcr(env, T0);
+ RETURN();
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val);
+void OPPROTO op_store_booke_tsr (void)
+{
+ store_booke_tsr(env, T0);
+ RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index e949eb42e6..ea3849710d 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1,7 +1,7 @@
/*
* PowerPC emulation helpers for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +30,7 @@
//#define DEBUG_OP
//#define DEBUG_EXCEPTIONS
+//#define DEBUG_SOFTWARE_TLB
//#define FLUSH_ALL_TLBS
#define Ts0 (long)((target_long)T0)
@@ -38,7 +39,7 @@
/*****************************************************************************/
/* Exceptions processing helpers */
-void cpu_loop_exit(void)
+void cpu_loop_exit (void)
{
longjmp(env->jmp_env, 1);
}
@@ -50,16 +51,16 @@ void do_raise_exception_err (uint32_t exception, int error_code)
#endif
switch (exception) {
case EXCP_PROGRAM:
- if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
- return;
- break;
+ if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
+ return;
+ break;
default:
- break;
-}
+ break;
+ }
env->exception_index = exception;
env->error_code = error_code;
- cpu_loop_exit();
- }
+ cpu_loop_exit();
+}
void do_raise_exception (uint32_t exception)
{
@@ -67,6 +68,119 @@ void do_raise_exception (uint32_t exception)
}
/*****************************************************************************/
+/* Registers load and stores */
+void do_load_cr (void)
+{
+ T0 = (env->crf[0] << 28) |
+ (env->crf[1] << 24) |
+ (env->crf[2] << 20) |
+ (env->crf[3] << 16) |
+ (env->crf[4] << 12) |
+ (env->crf[5] << 8) |
+ (env->crf[6] << 4) |
+ (env->crf[7] << 0);
+}
+
+void do_store_cr (uint32_t mask)
+{
+ int i, sh;
+
+ for (i = 0, sh = 7; i < 8; i++, sh --) {
+ if (mask & (1 << sh))
+ env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
+ }
+}
+
+void do_load_xer (void)
+{
+ T0 = (xer_so << XER_SO) |
+ (xer_ov << XER_OV) |
+ (xer_ca << XER_CA) |
+ (xer_bc << XER_BC) |
+ (xer_cmp << XER_CMP);
+}
+
+void do_store_xer (void)
+{
+ xer_so = (T0 >> XER_SO) & 0x01;
+ xer_ov = (T0 >> XER_OV) & 0x01;
+ xer_ca = (T0 >> XER_CA) & 0x01;
+ xer_cmp = (T0 >> XER_CMP) & 0xFF;
+ xer_bc = (T0 >> XER_BC) & 0x3F;
+}
+
+void do_load_fpscr (void)
+{
+ /* The 32 MSB of the target fpr are undefined.
+ * They'll be zero...
+ */
+ union {
+ float64 d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+ int i;
+
+#ifdef WORDS_BIGENDIAN
+#define WORD0 0
+#define WORD1 1
+#else
+#define WORD0 1
+#define WORD1 0
+#endif
+ u.s.u[WORD0] = 0;
+ u.s.u[WORD1] = 0;
+ for (i = 0; i < 8; i++)
+ u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
+ FT0 = u.d;
+}
+
+void do_store_fpscr (uint32_t mask)
+{
+ /*
+ * We use only the 32 LSB of the incoming fpr
+ */
+ union {
+ double d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+ int i, rnd_type;
+
+ u.d = FT0;
+ if (mask & 0x80)
+ env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
+ for (i = 1; i < 7; i++) {
+ if (mask & (1 << (7 - i)))
+ env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
+ }
+ /* TODO: update FEX & VX */
+ /* Set rounding mode */
+ switch (env->fpscr[0] & 0x3) {
+ case 0:
+ /* Best approximation (round to nearest) */
+ rnd_type = float_round_nearest_even;
+ break;
+ case 1:
+ /* Smaller magnitude (round toward zero) */
+ rnd_type = float_round_to_zero;
+ break;
+ case 2:
+ /* Round toward +infinite */
+ rnd_type = float_round_up;
+ break;
+ default:
+ case 3:
+ /* Round toward -infinite */
+ rnd_type = float_round_down;
+ break;
+ }
+ set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+/*****************************************************************************/
/* Fixed point operations helpers */
void do_addo (void)
{
@@ -301,21 +415,21 @@ void do_sraw (void)
if (likely(T1 != 0)) {
ret = (int32_t)T0 >> (T1 & 0x1fUL);
if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
- xer_ca = 0;
+ xer_ca = 0;
} else {
- xer_ca = 1;
+ xer_ca = 1;
}
} else {
- ret = T0;
+ ret = T0;
xer_ca = 0;
}
} else {
ret = (-1) * ((uint32_t)T0 >> 31);
if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
xer_ca = 0;
- } else {
+ } else {
xer_ca = 1;
- }
+ }
}
T0 = ret;
}
@@ -330,7 +444,7 @@ void do_fctiw (void)
} p;
/* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750 (aka G3)
+ * to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
p.i = float64_to_int32(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
@@ -381,7 +495,7 @@ void do_fres (void)
} p;
if (likely(isnormal(FT0))) {
- FT0 = (float)(1.0 / FT0);
+ FT0 = float32_div(1.0, FT0, &env->fp_status);
} else {
p.d = FT0;
if (p.i == 0x8000000000000000ULL) {
@@ -467,8 +581,8 @@ void do_fcmpo (void)
} else {
T0 = 0x01UL;
env->fpscr[4] |= 0x1;
- /* I don't know how to test "quiet" nan... */
- if (0 /* || ! quiet_nan(...) */) {
+ if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
+ /* Quiet NaN case */
env->fpscr[6] |= 0x1;
if (!(env->fpscr[1] & 0x8))
env->fpscr[4] |= 0x8;
@@ -479,6 +593,7 @@ void do_fcmpo (void)
env->fpscr[3] = T0;
}
+#if !defined (CONFIG_USER_ONLY)
void do_rfi (void)
{
env->nip = env->spr[SPR_SRR0] & ~0x00000003;
@@ -489,14 +604,15 @@ void do_rfi (void)
#endif
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
+#endif
-void do_tw (uint32_t cmp, int flags)
+void do_tw (int flags)
{
- if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
- (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
- (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
- (T0 < cmp && (flags & 0x02)) ||
- (T0 > cmp && (flags & 0x01)))))
+ if (!likely(!((Ts0 < Ts1 && (flags & 0x10)) ||
+ (Ts0 > Ts1 && (flags & 0x08)) ||
+ (Ts0 == Ts1 && (flags & 0x04)) ||
+ (T0 < T1 && (flags & 0x02)) ||
+ (T0 > T1 && (flags & 0x01)))))
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
}
@@ -519,20 +635,311 @@ void do_icbi (void)
}
/*****************************************************************************/
-/* MMU related helpers */
-/* TLB invalidation helpers */
-void do_tlbia (void)
+/* PowerPC 601 specific instructions (POWER bridge) */
+void do_POWER_abso (void)
{
- tlb_flush(env, 1);
+ if (T0 == INT32_MIN) {
+ T0 = INT32_MAX;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ T0 = -T0;
+ xer_ov = 0;
+ }
}
-void do_tlbie (void)
+void do_POWER_clcs (void)
{
-#if !defined(FLUSH_ALL_TLBS)
- tlb_flush_page(env, T0);
+ switch (T0) {
+ case 0x0CUL:
+ /* Instruction cache line size */
+ T0 = ICACHE_LINE_SIZE;
+ break;
+ case 0x0DUL:
+ /* Data cache line size */
+ T0 = DCACHE_LINE_SIZE;
+ break;
+ case 0x0EUL:
+ /* Minimum cache line size */
+ T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ?
+ ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+ break;
+ case 0x0FUL:
+ /* Maximum cache line size */
+ T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ?
+ ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+ break;
+ default:
+ /* Undefined */
+ break;
+ }
+}
+
+void do_POWER_div (void)
+{
+ uint64_t tmp;
+
+ if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ } else {
+ tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = tmp % T1;
+ T0 = tmp / Ts1;
+ }
+}
+
+void do_POWER_divo (void)
+{
+ int64_t tmp;
+
+ if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = tmp % T1;
+ tmp /= Ts1;
+ if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ xer_ov = 0;
+ }
+ T0 = tmp;
+ }
+}
+
+void do_POWER_divs (void)
+{
+ if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ } else {
+ env->spr[SPR_MQ] = T0 % T1;
+ T0 = Ts0 / Ts1;
+ }
+}
+
+void do_POWER_divso (void)
+{
+ if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ T0 = Ts0 / Ts1;
+ env->spr[SPR_MQ] = Ts0 % Ts1;
+ xer_ov = 0;
+ }
+}
+
+void do_POWER_dozo (void)
+{
+ if (Ts1 > Ts0) {
+ T2 = T0;
+ T0 = T1 - T0;
+ if (((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)) {
+ xer_so = 1;
+ xer_ov = 1;
+ } else {
+ xer_ov = 0;
+ }
+ } else {
+ T0 = 0;
+ xer_ov = 0;
+ }
+}
+
+void do_POWER_maskg (void)
+{
+ uint32_t ret;
+
+ if (T0 == T1 + 1) {
+ ret = -1;
+ } else {
+ ret = (((uint32_t)(-1)) >> (T0)) ^
+ (((uint32_t)(-1) >> (T1)) >> 1);
+ if (T0 > T1)
+ ret = ~ret;
+ }
+ T0 = ret;
+}
+
+void do_POWER_mulo (void)
+{
+ uint64_t tmp;
+
+ tmp = (uint64_t)T0 * (uint64_t)T1;
+ env->spr[SPR_MQ] = tmp >> 32;
+ T0 = tmp;
+ if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ xer_ov = 0;
+ }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void do_POWER_rac (void)
+{
+#if 0
+ mmu_ctx_t ctx;
+
+ /* We don't have to generate many instances of this instruction,
+ * as rac is supervisor only.
+ */
+ if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0)
+ T0 = ctx.raddr;
+#endif
+}
+
+void do_POWER_rfsvc (void)
+{
+ env->nip = env->lr & ~0x00000003UL;
+ T0 = env->ctr & 0x0000FFFFUL;
+ do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+ dump_rfi();
+#endif
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+/* PowerPC 601 BAT management helper */
+void do_store_601_batu (int nr)
+{
+ do_store_ibatu(env, nr, T0);
+ env->DBAT[0][nr] = env->IBAT[0][nr];
+ env->DBAT[1][nr] = env->IBAT[1][nr];
+}
+#endif
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+#define USE_MFROM_ROM_TABLE
+void do_op_602_mfrom (void)
+{
+ if (likely(T0 < 602)) {
+#ifdef USE_MFROM_ROM_TABLE
+#include "mfrom_table.c"
+ T0 = mfrom_ROM_table[T0];
#else
- do_tlbia();
+ double d;
+ /* Extremly decomposed:
+ * -T0 / 256
+ * T0 = 256 * log10(10 + 1.0) + 0.5
+ */
+ d = T0;
+ d = float64_div(d, 256, &env->fp_status);
+ d = float64_chs(d);
+ d = exp10(d); // XXX: use float emulation function
+ d = float64_add(d, 1.0, &env->fp_status);
+ d = log10(d); // XXX: use float emulation function
+ d = float64_mul(d, 256, &env->fp_status);
+ d = float64_add(d, 0.5, &env->fp_status);
+ T0 = float64_round_to_int(d, &env->fp_status);
#endif
+ } else {
+ T0 = 0;
+ }
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+void do_405_check_ov (void)
+{
+ if (likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) {
+ xer_ov = 0;
+ } else {
+ xer_ov = 1;
+ xer_so = 1;
+ }
+}
+
+void do_405_check_sat (void)
+{
+ if (!likely(((T1 ^ T2) >> 31) || !((T0 ^ T2) >> 31))) {
+ /* Saturate result */
+ if (T2 >> 31) {
+ T0 = INT32_MIN;
+ } else {
+ T0 = INT32_MAX;
+ }
+ }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void do_4xx_rfci (void)
+{
+ env->nip = env->spr[SPR_40x_SRR2];
+ T0 = env->spr[SPR_40x_SRR3] & ~0xFFFF0000;
+ do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+ dump_rfi();
+#endif
+ env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_4xx_load_dcr (int dcrn)
+{
+ target_ulong val;
+
+ if (unlikely(env->dcr_read == NULL))
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+ else if (unlikely((*env->dcr_read)(env->dcr_env, dcrn, &val) != 0))
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+ else
+ T0 = val;
+}
+
+void do_4xx_store_dcr (int dcrn)
+{
+ if (unlikely(env->dcr_write == NULL))
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+ else if (unlikely((*env->dcr_write)(env->dcr_env, dcrn, T0) != 0))
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+}
+
+void do_load_403_pb (int num)
+{
+ T0 = env->pb[num];
+}
+
+void do_store_403_pb (int num)
+{
+ if (likely(env->pb[num] != T0)) {
+ env->pb[num] = T0;
+ /* Should be optimized */
+ tlb_flush(env, 1);
+ }
+}
+#endif
+
+/* 440 specific */
+void do_440_dlmzb (void)
+{
+ target_ulong mask;
+ int i;
+
+ i = 1;
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((T0 & mask) == 0)
+ goto done;
+ i++;
+ }
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((T1 & mask) == 0)
+ break;
+ i++;
+ }
+ done:
+ T0 = i;
}
/*****************************************************************************/
@@ -570,7 +977,7 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
saved_env = env;
env = cpu_single_env;
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (!likely(ret == 0)) {
+ if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
pc = (target_phys_addr_t)retaddr;
@@ -579,11 +986,230 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, NULL);
-}
+ }
}
do_raise_exception_err(env->exception_index, env->error_code);
}
env = saved_env;
}
-#endif /* !CONFIG_USER_ONLY */
+/* TLB invalidation helpers */
+void do_tlbia (void)
+{
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ ppc6xx_tlb_invalidate_all(env);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+#if 0
+ ppcbooke_tlb_invalidate_all(env);
+#endif
+ } else {
+ tlb_flush(env, 1);
+ }
+}
+
+void do_tlbie (void)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
+ if (env->id_tlbs == 1)
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+#if 0
+ ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
+ env->spr[SPR_BOOKE_PID]);
+#endif
+ } else {
+ /* tlbie invalidate TLBs for all segments */
+ T0 &= TARGET_PAGE_MASK;
+ T0 &= ~((target_ulong)-1 << 28);
+ /* XXX: this case should be optimized,
+ * giving a mask to tlb_flush_page
+ */
+ tlb_flush_page(env, T0 | (0x0 << 28));
+ tlb_flush_page(env, T0 | (0x1 << 28));
+ tlb_flush_page(env, T0 | (0x2 << 28));
+ tlb_flush_page(env, T0 | (0x3 << 28));
+ tlb_flush_page(env, T0 | (0x4 << 28));
+ tlb_flush_page(env, T0 | (0x5 << 28));
+ tlb_flush_page(env, T0 | (0x6 << 28));
+ tlb_flush_page(env, T0 | (0x7 << 28));
+ tlb_flush_page(env, T0 | (0x8 << 28));
+ tlb_flush_page(env, T0 | (0x9 << 28));
+ tlb_flush_page(env, T0 | (0xA << 28));
+ tlb_flush_page(env, T0 | (0xB << 28));
+ tlb_flush_page(env, T0 | (0xC << 28));
+ tlb_flush_page(env, T0 | (0xD << 28));
+ tlb_flush_page(env, T0 | (0xE << 28));
+ tlb_flush_page(env, T0 | (0xF << 28));
+ }
+#else
+ do_tlbia();
+#endif
+}
+
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+void do_load_6xx_tlb (int is_code)
+{
+ target_ulong RPN, CMP, EPN;
+ int way;
+
+ RPN = env->spr[SPR_RPA];
+ if (is_code) {
+ CMP = env->spr[SPR_ICMP];
+ EPN = env->spr[SPR_IMISS];
+ } else {
+ CMP = env->spr[SPR_DCMP];
+ EPN = env->spr[SPR_DMISS];
+ }
+ way = (env->spr[SPR_SRR1] >> 17) & 1;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+ __func__, (unsigned long)T0, (unsigned long)EPN,
+ (unsigned long)CMP, (unsigned long)RPN, way);
+ }
+#endif
+ /* Store this TLB */
+ ppc6xx_tlb_store(env, T0 & TARGET_PAGE_MASK, way, is_code, CMP, RPN);
+}
+
+/* Helpers for 4xx TLB management */
+void do_4xx_tlbia (void)
+{
+#if 0
+ ppc_tlb_t *tlb;
+ target_ulong page, end;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ tlb = &env->tlb[i];
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+ tlb->prot &= ~PAGE_VALID;
+ }
+ }
+#endif
+}
+
+void do_4xx_tlbre_lo (void)
+{
+#if 0
+ ppc_tlb_t *tlb;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0];
+ T0 = tlb->stor[0];
+ env->spr[SPR_40x_PID] = tlb->pid;
+#endif
+}
+
+void do_4xx_tlbre_hi (void)
+{
+#if 0
+ ppc_tlb_t *tlb;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0];
+ T0 = tlb->stor[1];
+#endif
+}
+
+static int tlb_4xx_search (target_ulong virtual)
+{
+#if 0
+ ppc_tlb_t *tlb;
+ target_ulong base, mask;
+ int i, ret;
+
+ /* Default return value is no match */
+ ret = -1;
+ for (i = 0; i < 64; i++) {
+ tlb = &env->tlb[i];
+ /* Check TLB validity */
+ if (!(tlb->prot & PAGE_VALID))
+ continue;
+ /* Check TLB PID vs current PID */
+ if (tlb->pid != 0 && tlb->pid != env->spr[SPR_40x_PID])
+ continue;
+ /* Check TLB address vs virtual address */
+ base = tlb->EPN;
+ mask = ~(tlb->size - 1);
+ if ((base & mask) != (virtual & mask))
+ continue;
+ ret = i;
+ break;
+ }
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+
+void do_4xx_tlbsx (void)
+{
+ T0 = tlb_4xx_search(T0);
+}
+
+void do_4xx_tlbsx_ (void)
+{
+ int tmp = xer_ov;
+
+ T0 = tlb_4xx_search(T0);
+ if (T0 != -1)
+ tmp |= 0x02;
+ env->crf[0] = tmp;
+}
+
+void do_4xx_tlbwe_lo (void)
+{
+#if 0
+ ppc_tlb_t *tlb;
+ target_ulong page, end;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0];
+ /* Invalidate previous TLB (if it's valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+ }
+ tlb->size = 1024 << (2 * ((T1 >> 7) & 0x7));
+ tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
+ if (T1 & 0x400)
+ tlb->prot |= PAGE_VALID;
+ else
+ tlb->prot &= ~PAGE_VALID;
+ tlb->pid = env->spr[SPR_BOOKE_PID]; /* PID */
+ /* Invalidate new TLB (if valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+ }
+#endif
+}
+
+void do_4xx_tlbwe_hi (void)
+{
+#if 0
+ ppc_tlb_t *tlb;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0];
+ tlb->RPN = T1 & 0xFFFFFC00;
+ tlb->prot = PAGE_READ;
+ if (T1 & 0x200)
+ tlb->prot |= PAGE_EXEC;
+ if (T1 & 0x100)
+ tlb->prot |= PAGE_WRITE;
+#endif
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
new file mode 100644
index 0000000000..0cba00204a
--- /dev/null
+++ b/target-ppc/op_helper.h
@@ -0,0 +1,132 @@
+/*
+ * PowerPC emulation helpers header for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(MEMSUFFIX)
+
+/* Memory load/store helpers */
+void glue(do_lsw, MEMSUFFIX) (int dst);
+void glue(do_lsw_le, MEMSUFFIX) (int dst);
+void glue(do_stsw, MEMSUFFIX) (int src);
+void glue(do_stsw_le, MEMSUFFIX) (int src);
+void glue(do_lmw, MEMSUFFIX) (int dst);
+void glue(do_lmw_le, MEMSUFFIX) (int dst);
+void glue(do_stmw, MEMSUFFIX) (int src);
+void glue(do_stmw_le, MEMSUFFIX) (int src);
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb);
+void glue(do_POWER2_lfq, MEMSUFFIX) (void);
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void);
+
+#else
+
+/* Registers load and stores */
+void do_load_cr (void);
+void do_store_cr (uint32_t mask);
+void do_load_xer (void);
+void do_store_xer (void);
+void do_load_fpscr (void);
+void do_store_fpscr (uint32_t mask);
+
+/* Integer arithmetic helpers */
+void do_addo (void);
+void do_addco (void);
+void do_adde (void);
+void do_addeo (void);
+void do_addmeo (void);
+void do_addzeo (void);
+void do_divwo (void);
+void do_divwuo (void);
+void do_mullwo (void);
+void do_nego (void);
+void do_subfo (void);
+void do_subfco (void);
+void do_subfe (void);
+void do_subfeo (void);
+void do_subfmeo (void);
+void do_subfzeo (void);
+void do_sraw(void);
+
+/* Floating-point arithmetic helpers */
+void do_fsqrt (void);
+void do_fres (void);
+void do_frsqrte (void);
+void do_fsel (void);
+void do_fnmadd (void);
+void do_fnmsub (void);
+void do_fctiw (void);
+void do_fctiwz (void);
+void do_fcmpu (void);
+void do_fcmpo (void);
+
+void do_tw (int flags);
+void do_icbi (void);
+
+#if !defined(CONFIG_USER_ONLY)
+void do_rfi (void);
+void do_tlbia (void);
+void do_tlbie (void);
+void do_load_6xx_tlb (int is_code);
+#endif
+
+/* POWER / PowerPC 601 specific helpers */
+void do_store_601_batu (int nr);
+void do_POWER_abso (void);
+void do_POWER_clcs (void);
+void do_POWER_div (void);
+void do_POWER_divo (void);
+void do_POWER_divs (void);
+void do_POWER_divso (void);
+void do_POWER_dozo (void);
+void do_POWER_maskg (void);
+void do_POWER_mulo (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_POWER_rac (void);
+void do_POWER_rfsvc (void);
+#endif
+
+/* PowerPC 602 specific helper */
+#if !defined(CONFIG_USER_ONLY)
+void do_op_602_mfrom (void);
+#endif
+
+/* PowerPC 4xx specific helpers */
+void do_405_check_ov (void);
+void do_405_check_sat (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_4xx_load_dcr (int dcrn);
+void do_4xx_store_dcr (int dcrn);
+void do_4xx_rfci (void);
+void do_4xx_tlbre_lo (void);
+void do_4xx_tlbre_hi (void);
+void do_4xx_tlbsx (void);
+void do_4xx_tlbsx_ (void);
+void do_4xx_tlbwe_lo (void);
+void do_4xx_tlbwe_hi (void);
+#endif
+
+void do_440_dlmzb (void);
+
+#if !defined(CONFIG_USER_ONLY)
+void do_load_403_pb (int num);
+void do_store_403_pb (int num);
+#endif
+
+#endif
diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h
index fb90691f2b..45bb90d8a1 100644
--- a/target-ppc/op_helper_mem.h
+++ b/target-ppc/op_helper_mem.h
@@ -1,20 +1,78 @@
+/*
+ * PowerPC emulation micro-operations helpers for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Multiple word / string load and store */
+static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA)
+{
+ uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+ return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) |
+ ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24);
+}
+
+static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data)
+{
+ uint32_t tmp =
+ ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) |
+ ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24);
+ glue(stl, MEMSUFFIX)(EA, tmp);
+}
+
+void glue(do_lmw, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
+ }
+}
+
+void glue(do_stmw, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(stl, MEMSUFFIX)(T0, ugpr(src));
+ }
+}
+
+void glue(do_lmw_le, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
+ }
+}
+
+void glue(do_stmw_le, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(st32r, MEMSUFFIX)(T0, ugpr(src));
+ }
+}
+
void glue(do_lsw, MEMSUFFIX) (int dst)
{
uint32_t tmp;
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, dst);
- }
-#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
- if (dst == 32)
+ if (unlikely(dst == 32))
dst = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
tmp = 0;
for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
@@ -27,18 +85,12 @@ void glue(do_stsw, MEMSUFFIX) (int src)
{
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, src);
- }
-#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
glue(stl, MEMSUFFIX)(T0, ugpr(src++));
- if (src == 32)
+ if (unlikely(src == 32))
src = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
}
@@ -49,20 +101,12 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
uint32_t tmp;
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, dst);
- }
-#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
- tmp = glue(ldl, MEMSUFFIX)(T0);
- ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
- ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
- if (dst == 32)
+ ugpr(dst++) = glue(ld32r, MEMSUFFIX)(T0);
+ if (unlikely(dst == 32))
dst = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
tmp = 0;
for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
@@ -73,28 +117,108 @@ void glue(do_lsw_le, MEMSUFFIX) (int dst)
void glue(do_stsw_le, MEMSUFFIX) (int src)
{
- uint32_t tmp;
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, src);
- }
-#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
- tmp = ((ugpr(src++) & 0xFF000000) >> 24);
- tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);
- tmp |= ((ugpr(src++) & 0x0000FF00) << 8);
- tmp |= ((ugpr(src++) & 0x000000FF) << 24);
- glue(stl, MEMSUFFIX)(T0, tmp);
- if (src == 32)
+ glue(st32r, MEMSUFFIX)(T0, ugpr(src++));
+ if (unlikely(src == 32))
src = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
}
}
+/* PPC 601 specific instructions (POWER bridge) */
+// XXX: to be tested
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb)
+{
+ int i, c, d, reg;
+
+ d = 24;
+ reg = dest;
+ for (i = 0; i < T1; i++) {
+ c = glue(ldub, MEMSUFFIX)(T0++);
+ /* ra (if not 0) and rb are never modified */
+ if (likely(reg != rb && (ra == 0 || reg != ra))) {
+ ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d);
+ }
+ if (unlikely(c == T2))
+ break;
+ if (likely(d != 0)) {
+ d -= 8;
+ } else {
+ d = 24;
+ reg++;
+ reg = reg & 0x1F;
+ }
+ }
+ T0 = i;
+}
+
+/* XXX: TAGs are not managed */
+void glue(do_POWER2_lfq, MEMSUFFIX) (void)
+{
+ FT0 = glue(ldfq, MEMSUFFIX)(T0);
+ FT1 = glue(ldfq, MEMSUFFIX)(T0 + 4);
+}
+
+static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
+{
+ union {
+ double d;
+ uint64_t u;
+ } u;
+
+ u.d = glue(ldfq, MEMSUFFIX)(EA);
+ u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+ ((u.u & 0x00FF000000000000ULL) >> 40) |
+ ((u.u & 0x0000FF0000000000ULL) >> 24) |
+ ((u.u & 0x000000FF00000000ULL) >> 8) |
+ ((u.u & 0x00000000FF000000ULL) << 8) |
+ ((u.u & 0x0000000000FF0000ULL) << 24) |
+ ((u.u & 0x000000000000FF00ULL) << 40) |
+ ((u.u & 0x00000000000000FFULL) << 56);
+
+ return u.d;
+}
+
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+ FT0 = glue(ldfqr, MEMSUFFIX)(T0 + 4);
+ FT1 = glue(ldfqr, MEMSUFFIX)(T0);
+}
+
+void glue(do_POWER2_stfq, MEMSUFFIX) (void)
+{
+ glue(stfq, MEMSUFFIX)(T0, FT0);
+ glue(stfq, MEMSUFFIX)(T0 + 4, FT1);
+}
+
+static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
+{
+ union {
+ double d;
+ uint64_t u;
+ } u;
+
+ u.d = d;
+ u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+ ((u.u & 0x00FF000000000000ULL) >> 40) |
+ ((u.u & 0x0000FF0000000000ULL) >> 24) |
+ ((u.u & 0x000000FF00000000ULL) >> 8) |
+ ((u.u & 0x00000000FF000000ULL) << 8) |
+ ((u.u & 0x0000000000FF0000ULL) << 24) |
+ ((u.u & 0x000000000000FF00ULL) << 40) |
+ ((u.u & 0x00000000000000FFULL) << 56);
+ glue(stfq, MEMSUFFIX)(EA, u.d);
+}
+
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+ glue(stfqr, MEMSUFFIX)(T0 + 4, FT0);
+ glue(stfqr, MEMSUFFIX)(T0, FT1);
+}
+
#undef MEMSUFFIX
diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h
index 9b3f721e5f..a084b31943 100644
--- a/target-ppc/op_mem.h
+++ b/target-ppc/op_mem.h
@@ -1,6 +1,22 @@
-/* External helpers */
-void glue(do_lsw, MEMSUFFIX) (int dst);
-void glue(do_stsw, MEMSUFFIX) (int src);
+/*
+ * PowerPC emulation micro-operations for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
{
@@ -11,7 +27,7 @@ static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
{
int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
- return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
+ return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
}
static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
@@ -80,41 +96,25 @@ PPC_ST_OP(wbr_le, stl);
/*** Integer load and store multiple ***/
PPC_OP(glue(lmw, MEMSUFFIX))
{
- int dst = PARAM(1);
-
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
- }
+ glue(do_lmw, MEMSUFFIX)(PARAM1);
RETURN();
}
-PPC_OP(glue(stmw, MEMSUFFIX))
+PPC_OP(glue(lmw_le, MEMSUFFIX))
{
- int src = PARAM(1);
-
- for (; src < 32; src++, T0 += 4) {
- glue(stl, MEMSUFFIX)(T0, ugpr(src));
- }
+ glue(do_lmw_le, MEMSUFFIX)(PARAM1);
RETURN();
}
-PPC_OP(glue(lmw_le, MEMSUFFIX))
+PPC_OP(glue(stmw, MEMSUFFIX))
{
- int dst = PARAM(1);
-
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
- }
+ glue(do_stmw, MEMSUFFIX)(PARAM1);
RETURN();
}
PPC_OP(glue(stmw_le, MEMSUFFIX))
{
- int src = PARAM(1);
-
- for (; src < 32; src++, T0 += 4) {
- glue(st32r, MEMSUFFIX)(T0, ugpr(src));
- }
+ glue(do_stmw_le, MEMSUFFIX)(PARAM1);
RETURN();
}
@@ -125,7 +125,6 @@ PPC_OP(glue(lswi, MEMSUFFIX))
RETURN();
}
-void glue(do_lsw_le, MEMSUFFIX) (int dst);
PPC_OP(glue(lswi_le, MEMSUFFIX))
{
glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@@ -139,9 +138,9 @@ PPC_OP(glue(lswi_le, MEMSUFFIX))
*/
PPC_OP(glue(lswx, MEMSUFFIX))
{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+ if (unlikely(T1 > 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
glue(do_lsw, MEMSUFFIX)(PARAM(1));
@@ -152,9 +151,9 @@ PPC_OP(glue(lswx, MEMSUFFIX))
PPC_OP(glue(lswx_le, MEMSUFFIX))
{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+ if (unlikely(T1 > 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
@@ -169,7 +168,6 @@ PPC_OP(glue(stsw, MEMSUFFIX))
RETURN();
}
-void glue(do_stsw_le, MEMSUFFIX) (int src);
PPC_OP(glue(stsw_le, MEMSUFFIX))
{
glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
@@ -180,7 +178,7 @@ PPC_OP(glue(stsw_le, MEMSUFFIX))
#define PPC_STF_OP(name, op) \
PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
{ \
- glue(op, MEMSUFFIX)(T0, FT1); \
+ glue(op, MEMSUFFIX)(T0, FT0); \
RETURN(); \
}
@@ -228,7 +226,7 @@ PPC_STF_OP(fs_le, stflr);
#define PPC_LDF_OP(name, op) \
PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
{ \
- FT1 = glue(op, MEMSUFFIX)(T0); \
+ FT0 = glue(op, MEMSUFFIX)(T0); \
RETURN(); \
}
@@ -277,22 +275,22 @@ PPC_LDF_OP(fs_le, ldflr);
/* Load and set reservation */
PPC_OP(glue(lwarx, MEMSUFFIX))
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- T1 = glue(ldl, MEMSUFFIX)(T0);
- regs->reserve = T0;
+ T1 = glue(ldl, MEMSUFFIX)(T0);
+ regs->reserve = T0;
}
RETURN();
}
PPC_OP(glue(lwarx_le, MEMSUFFIX))
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- T1 = glue(ld32r, MEMSUFFIX)(T0);
- regs->reserve = T0;
+ T1 = glue(ld32r, MEMSUFFIX)(T0);
+ regs->reserve = T0;
}
RETURN();
}
@@ -300,33 +298,33 @@ PPC_OP(glue(lwarx_le, MEMSUFFIX))
/* Store with reservation */
PPC_OP(glue(stwcx, MEMSUFFIX))
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- if (regs->reserve != T0) {
+ if (unlikely(regs->reserve != T0)) {
env->crf[0] = xer_ov;
} else {
glue(stl, MEMSUFFIX)(T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
- regs->reserve = 0;
+ regs->reserve = -1;
RETURN();
}
PPC_OP(glue(stwcx_le, MEMSUFFIX))
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- if (regs->reserve != T0) {
+ if (unlikely(regs->reserve != T0)) {
env->crf[0] = xer_ov;
} else {
glue(st32r, MEMSUFFIX)(T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
- regs->reserve = 0;
+ regs->reserve = -1;
RETURN();
}
@@ -340,6 +338,17 @@ PPC_OP(glue(dcbz, MEMSUFFIX))
glue(stl, MEMSUFFIX)(T0 + 0x14, 0);
glue(stl, MEMSUFFIX)(T0 + 0x18, 0);
glue(stl, MEMSUFFIX)(T0 + 0x1C, 0);
+#if DCACHE_LINE_SIZE == 64
+ /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+ glue(stl, MEMSUFFIX)(T0 + 0x20UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x24UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x28UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x2CUL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x30UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x34UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x38UL, 0);
+ glue(stl, MEMSUFFIX)(T0 + 0x3CUL, 0);
+#endif
RETURN();
}
@@ -368,4 +377,41 @@ PPC_OP(glue(ecowx_le, MEMSUFFIX))
RETURN();
}
+/* XXX: those micro-ops need tests ! */
+/* PowerPC 601 specific instructions (POWER bridge) */
+void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void)
+{
+ /* When byte count is 0, do nothing */
+ if (likely(T1 > 0)) {
+ glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3);
+ }
+ RETURN();
+}
+
+/* POWER2 quad load and store */
+/* XXX: TAGs are not managed */
+void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_lfq, MEMSUFFIX)();
+ RETURN();
+}
+
+void glue(op_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_lfq_le, MEMSUFFIX)();
+ RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_stfq, MEMSUFFIX)();
+ RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_stfq_le, MEMSUFFIX)();
+ RETURN();
+}
+
#undef MEMSUFFIX
diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h
index 1be640d6de..511d065f64 100644
--- a/target-ppc/op_template.h
+++ b/target-ppc/op_template.h
@@ -1,7 +1,7 @@
/*
* PowerPC emulation micro-operations for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,107 +19,97 @@
*/
/* General purpose registers moves */
-void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void)
{
T0 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void)
{
T1 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void)
{
T2 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T1;
RETURN();
}
-void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T2;
RETURN();
}
+#endif
#if REG <= 7
/* Condition register moves */
-void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T0_crf, REG) (void)
{
T0 = regs->crf[REG];
RETURN();
}
-void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T1_crf, REG) (void)
{
T1 = regs->crf[REG];
RETURN();
}
-void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T0_crf_crf, REG) (void)
{
regs->crf[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
{
regs->crf[REG] = T1;
RETURN();
}
/* Floating point condition and status register moves */
-void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
+void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
{
T0 = regs->fpscr[REG];
RETURN();
}
#if REG == 0
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
RETURN();
}
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
-{
- regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
- RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
RETURN();
}
#else
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
-{
- regs->fpscr[REG] = PARAM(1);
- RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = 0x0;
RETURN();
@@ -129,55 +119,42 @@ void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
#endif /* REG <= 7 */
/* floating point registers moves */
-void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void)
{
FT0 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT0;
RETURN();
}
-void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void)
{
FT1 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT1;
RETURN();
}
-void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void)
{
FT2 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT2;
RETURN();
}
-
-#if REG <= 15
-/* Segment register moves */
-void OPPROTO glue(op_load_sr, REG)(void)
-{
- T0 = env->sr[REG];
- RETURN();
-}
-
-void OPPROTO glue(op_store_sr, REG)(void)
-{
- do_store_sr(env, REG, T0);
- RETURN();
-}
#endif
#undef REG
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 41737d4a84..1e6c9cb8de 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1,7 +1,7 @@
/*
* PowerPC emulation for qemu: main translation routines.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,7 @@
//#define DO_SINGLE_STEP
//#define PPC_DEBUG_DISAS
+//#define DO_PPC_STATISTICS
#ifdef USE_DIRECT_JUMP
#define TBPARAM(x)
@@ -96,25 +97,12 @@ GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
- &gen_op_store_T0_fpscri_fpscr0,
- &gen_op_store_T0_fpscri_fpscr1,
- &gen_op_store_T0_fpscri_fpscr2,
- &gen_op_store_T0_fpscri_fpscr3,
- &gen_op_store_T0_fpscri_fpscr4,
- &gen_op_store_T0_fpscri_fpscr5,
- &gen_op_store_T0_fpscri_fpscr6,
- &gen_op_store_T0_fpscri_fpscr7,
-};
static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
{
- (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
+ gen_op_set_T0(param);
+ gen_op_store_T0_fpscr(n);
}
-/* Segment register moves */
-GEN16(gen_op_load_sr, gen_op_load_sr);
-GEN16(gen_op_store_sr, gen_op_store_sr);
-
/* General purpose registers moves */
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
@@ -122,7 +110,9 @@ GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
+#if 0 // unused
GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
+#endif
/* floating point registers moves */
GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
@@ -130,9 +120,9 @@ GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
+#if 0 // unused
GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
-
-static uint8_t spr_access[1024 / 2];
+#endif
/* internal defines */
typedef struct DisasContext {
@@ -158,8 +148,18 @@ struct opc_handler_t {
uint32_t type;
/* handler */
void (*handler)(DisasContext *ctx);
+#if defined(DO_PPC_STATISTICS)
+ const unsigned char *oname;
+ uint64_t count;
+#endif
};
+static inline void gen_set_Rc0 (DisasContext *ctx)
+{
+ gen_op_cmpi(0);
+ gen_op_set_Rc0();
+}
+
#define RET_EXCP(ctx, excp, error) \
do { \
if ((ctx)->exception == EXCP_NONE) { \
@@ -209,13 +209,13 @@ typedef struct opcode_t {
/*** Instruction decoding ***/
#define EXTRACT_HELPER(name, shift, nb) \
-static inline uint32_t name (uint32_t opcode) \
+static inline target_ulong name (uint32_t opcode) \
{ \
return (opcode >> (shift)) & ((1 << (nb)) - 1); \
}
#define EXTRACT_SHELPER(name, shift, nb) \
-static inline int32_t name (uint32_t opcode) \
+static inline target_long name (uint32_t opcode) \
{ \
return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
}
@@ -278,7 +278,7 @@ EXTRACT_HELPER(FPIMM, 20, 4);
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
-static inline uint32_t LI (uint32_t opcode)
+static inline target_ulong LI (uint32_t opcode)
{
return (opcode >> 0) & 0x03FFFFFC;
}
@@ -296,13 +296,29 @@ EXTRACT_HELPER(AA, 1, 1);
EXTRACT_HELPER(LK, 0, 1);
/* Create a mask between <start> and <end> bits */
-static inline uint32_t MASK (uint32_t start, uint32_t end)
+static inline target_ulong MASK (uint32_t start, uint32_t end)
{
- uint32_t ret;
+ target_ulong ret;
- ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
- if (start > end)
- return ~ret;
+#if defined(TARGET_PPC64)
+ if (likely(start == 0)) {
+ ret = (uint64_t)(-1ULL) << (63 - end);
+ } else if (likely(end == 63)) {
+ ret = (uint64_t)(-1ULL) >> start;
+ }
+#else
+ if (likely(start == 0)) {
+ ret = (uint32_t)(-1ULL) << (31 - end);
+ } else if (likely(end == 31)) {
+ ret = (uint32_t)(-1ULL) >> start;
+ }
+#endif
+ else {
+ ret = (((target_ulong)(-1ULL)) >> (start)) ^
+ (((target_ulong)(-1ULL) >> (end)) >> 1);
+ if (unlikely(start > end))
+ return ~ret;
+ }
return ret;
}
@@ -320,6 +336,22 @@ static inline uint32_t MASK (uint32_t start, uint32_t end)
__attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
#endif
+#if defined(DO_PPC_STATISTICS)
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
+OPCODES_SECTION opcode_t opc_##name = { \
+ .opc1 = op1, \
+ .opc2 = op2, \
+ .opc3 = op3, \
+ .pad = { 0, }, \
+ .handler = { \
+ .inval = invl, \
+ .type = _typ, \
+ .handler = &gen_##name, \
+ .oname = stringify(name), \
+ }, \
+ .oname = stringify(name), \
+}
+#else
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
OPCODES_SECTION opcode_t opc_##name = { \
.opc1 = op1, \
@@ -333,6 +365,7 @@ OPCODES_SECTION opcode_t opc_##name = { \
}, \
.oname = stringify(name), \
}
+#endif
#define GEN_OPCODE_MARK(name) \
OPCODES_SECTION opcode_t opc_##name = { \
@@ -370,9 +403,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
@@ -381,9 +414,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
@@ -391,18 +424,18 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
/* Two operands arithmetic functions */
@@ -454,41 +487,51 @@ GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
/* addi */
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int32_t simm = SIMM(ctx->opcode);
+ target_long simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
+ /* li case */
gen_op_set_T0(simm);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm);
+ if (likely(simm != 0))
+ gen_op_addi(simm);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic */
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
+ target_long simm = SIMM(ctx->opcode);
+
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
+ if (likely(simm != 0))
+ gen_op_addic(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic. */
GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
+ target_long simm = SIMM(ctx->opcode);
+
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
- gen_op_set_Rc0();
+ if (likely(simm != 0))
+ gen_op_addic(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int32_t simm = SIMM(ctx->opcode);
+ target_long simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
+ /* lis case */
gen_op_set_T0(simm << 16);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm << 16);
+ if (likely(simm != 0))
+ gen_op_addi(simm << 16);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -543,9 +586,9 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
#define GEN_LOGICAL2(name, opc) \
__GEN_LOGICAL2(name, 0x1C, opc)
@@ -555,9 +598,9 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
{ \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
/* and & and. */
@@ -568,17 +611,17 @@ GEN_LOGICAL2(andc, 0x01);
GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode));
- gen_op_set_Rc0();
+ gen_op_andi_T0(UIMM(ctx->opcode));
gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* andis. */
GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode) << 16);
- gen_op_set_Rc0();
+ gen_op_andi_T0(UIMM(ctx->opcode) << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* cntlzw */
@@ -597,15 +640,25 @@ GEN_LOGICAL2(nor, 0x03);
/* or & or. */
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- /* Optimisation for mr case */
- if (rS(ctx->opcode) != rB(ctx->opcode)) {
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_or();
+ int rs, ra, rb;
+
+ rs = rS(ctx->opcode);
+ ra = rA(ctx->opcode);
+ rb = rB(ctx->opcode);
+ /* Optimisation for mr. ri case */
+ if (rs != ra || rs != rb) {
+ gen_op_load_gpr_T0(rs);
+ if (rs != rb) {
+ gen_op_load_gpr_T1(rb);
+ gen_op_or();
+ }
+ gen_op_store_T0_gpr(ra);
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+ } else if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_op_load_gpr_T0(rs);
+ gen_set_Rc0(ctx);
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* orc & orc. */
@@ -619,67 +672,68 @@ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_xor();
} else {
- gen_op_set_T0(0);
+ gen_op_reset_T0();
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* ori */
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
+ /* XXX: should handle special NOPs for POWER series */
return;
- }
- gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (likely(uimm != 0))
gen_op_ori(uimm);
- gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
- }
- gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (likely(uimm != 0))
gen_op_ori(uimm << 16);
- gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
- gen_op_xori(uimm);
+ if (likely(uimm != 0))
+ gen_op_xori(uimm);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
- gen_op_xori(uimm << 16);
+ if (likely(uimm != 0))
+ gen_op_xori(uimm << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
@@ -687,16 +741,42 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t mb, me;
+ target_ulong mask;
+ uint32_t mb, me, sh;
+ int n;
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
+ sh = SH(ctx->opcode);
+ n = me + 1 - mb;
+ if (likely(sh == 0)) {
+ if (likely(mb == 0 && me == 31)) {
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ goto do_store;
+ } else if (likely(mb == 31 && me == 0)) {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ goto do_store;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ goto do_mask;
+ }
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rA(ctx->opcode));
- gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ gen_op_rotli32_T0(SH(ctx->opcode));
+ do_mask:
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ mask = MASK(mb, me);
+ gen_op_andi_T0(mask);
+ gen_op_andi_T1(~mask);
+ gen_op_or();
+ do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -707,35 +787,34 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
-#if 1 // TRY
- if (sh == 0) {
- gen_op_andi_(MASK(mb, me));
- goto store;
- }
-#endif
- if (mb == 0) {
- if (me == 31) {
- gen_op_rotlwi(sh);
- goto store;
-#if 0
- } else if (me == (31 - sh)) {
- gen_op_slwi(sh);
- goto store;
-#endif
+ if (likely(sh == 0)) {
+ goto do_mask;
+ }
+ if (likely(mb == 0)) {
+ if (likely(me == 31)) {
+ gen_op_rotli32_T0(sh);
+ goto do_store;
+ } else if (likely(me == (31 - sh))) {
+ gen_op_sli_T0(sh);
+ goto do_store;
}
- } else if (me == 31) {
-#if 0
- if (sh == (32 - mb)) {
- gen_op_srwi(mb);
- goto store;
+ } else if (likely(me == 31)) {
+ if (likely(sh == (32 - mb))) {
+ gen_op_srli_T0(mb);
+ goto do_store;
}
-#endif
}
- gen_op_rlwinm(sh, MASK(mb, me));
-store:
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ gen_op_rotli32_T0(sh);
+ do_mask:
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ gen_op_andi_T0(MASK(mb, me));
+ do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -746,15 +825,17 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
- if (mb == 0 && me == 31) {
- gen_op_rotl();
- } else
- {
- gen_op_rlwnm(MASK(mb, me));
+ gen_op_rotl32_T0_T1();
+ if (unlikely(mb != 0 || me != 31)) {
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ gen_op_andi_T0(MASK(mb, me));
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/*** Integer shift ***/
@@ -767,10 +848,10 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
if (SH(ctx->opcode) != 0)
- gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* srw & srw. */
__GEN_LOGICAL2(srw, 0x18, 0x10);
@@ -779,7 +860,7 @@ __GEN_LOGICAL2(srw, 0x18, 0x10);
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -792,7 +873,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
@@ -803,7 +884,7 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -815,7 +896,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AB(name, op2, inval) \
@@ -825,7 +906,7 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -837,7 +918,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AC(name, op2, inval) \
@@ -847,7 +928,7 @@ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
#define GEN_FLOAT_B(name, op2, op3) \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -855,14 +936,14 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_BS(name, op1, op2) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -870,7 +951,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
@@ -881,13 +962,13 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0);
/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
-/* fres */
+/* fres */ /* XXX: not in 601 */
GEN_FLOAT_BS(res, 0x3B, 0x18);
-/* frsqrte */
+/* frsqrte */ /* XXX: not in 601 */
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
-/* fsel */
+/* fsel */ /* XXX: not in 601 */
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
@@ -895,7 +976,7 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
/* fsqrt */
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -903,13 +984,13 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_fsqrt();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -918,7 +999,7 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
gen_op_fsqrt();
gen_op_frsp();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -942,9 +1023,9 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00);
/*** Floating-Point compare ***/
/* fcmpo */
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -956,9 +1037,9 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
}
/* fcmpu */
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -976,14 +1057,14 @@ GEN_FLOAT_B(abs, 0x08, 0x08);
/* fmr - fmr. */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -996,7 +1077,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01);
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -1008,13 +1089,13 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_load_fpscr();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -1023,15 +1104,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
{
uint8_t crb;
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
crb = crbD(ctx->opcode) >> 2;
gen_op_load_fpscr_T0(crb);
- gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
+ gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
gen_op_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -1040,7 +1121,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
{
uint8_t crb;
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -1048,35 +1129,70 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
gen_op_load_fpscr_T0(crb);
gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
gen_op_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_fpscr(FM(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
+/*** Addressing modes ***/
+/* Register indirect with immediate index : EA = (rA|0) + SIMM */
+static inline void gen_addr_imm_index (DisasContext *ctx)
+{
+ target_long simm = SIMM(ctx->opcode);
+
+ if (rA(ctx->opcode) == 0) {
+ gen_op_set_T0(simm);
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ if (likely(simm != 0))
+ gen_op_addi(simm);
+ }
+}
+
+static inline void gen_addr_reg_index (DisasContext *ctx)
+{
+ if (rA(ctx->opcode) == 0) {
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_add();
+ }
+}
+
+static inline void gen_addr_register (DisasContext *ctx)
+{
+ if (rA(ctx->opcode) == 0) {
+ gen_op_reset_T0();
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ }
+}
+
/*** Integer load ***/
#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
@@ -1118,14 +1234,7 @@ static GenOpFunc *gen_op_st##width[] = { \
#define GEN_LD(width, opc) \
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
}
@@ -1133,15 +1242,12 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
#define GEN_LDU(width, opc) \
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0 || \
+ rA(ctx->opcode) == rD(ctx->opcode))) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ gen_addr_imm_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
@@ -1150,14 +1256,12 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
#define GEN_LDUX(width, opc) \
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0 || \
+ rA(ctx->opcode) == rD(ctx->opcode))) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
@@ -1166,13 +1270,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
#define GEN_LDX(width, opc2, opc3) \
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
}
@@ -1197,14 +1295,7 @@ GEN_LDS(wz, 0x00);
#define GEN_ST(width, opc) \
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
}
@@ -1212,14 +1303,11 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
#define GEN_STU(width, opc) \
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ gen_addr_imm_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
@@ -1228,13 +1316,11 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
#define GEN_STUX(width, opc) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
@@ -1243,13 +1329,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
#define GEN_STX(width, opc2, opc3) \
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
}
@@ -1311,30 +1391,18 @@ static GenOpFunc1 *gen_op_stmw[] = {
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- if (simm != 0)
- gen_op_addi(simm);
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
op_ldstm(lmw, rD(ctx->opcode));
}
/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- if (simm != 0)
- gen_op_addi(simm);
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
op_ldstm(stmw, rS(ctx->opcode));
}
@@ -1391,19 +1459,16 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
if (nb == 0)
nb = 32;
nr = nb / 4;
- if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) ||
- ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
+ if (unlikely(((start + nr) > 32 &&
+ start <= ra && (start + nr - 32) > ra) ||
+ ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
return;
}
- if (ra == 0) {
- gen_op_set_T0(0);
- } else {
- gen_op_load_gpr_T0(ra);
- }
- gen_op_set_T1(nb);
/* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_register(ctx);
+ gen_op_set_T1(nb);
op_ldsts(lswi, start);
}
@@ -1413,17 +1478,13 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
int ra = rA(ctx->opcode);
int rb = rB(ctx->opcode);
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
if (ra == 0) {
- gen_op_load_gpr_T0(rb);
ra = rb;
- } else {
- gen_op_load_gpr_T0(ra);
- gen_op_load_gpr_T1(rb);
- gen_op_add();
}
gen_op_load_xer_bc();
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
}
@@ -1432,46 +1493,33 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
{
int nb = NB(ctx->opcode);
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(0);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_register(ctx);
if (nb == 0)
nb = 32;
gen_op_set_T1(nb);
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldsts(stsw, rS(ctx->opcode));
}
/* stswx */
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
{
- int ra = rA(ctx->opcode);
-
- if (ra == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- ra = rB(ctx->opcode);
- } else {
- gen_op_load_gpr_T0(ra);
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
- gen_op_load_xer_bc();
/* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ gen_op_load_xer_bc();
op_ldsts(stsw, rS(ctx->opcode));
}
/*** Memory synchronisation ***/
/* eieio */
-GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
{
}
/* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
{
}
@@ -1502,15 +1550,9 @@ static GenOpFunc *gen_op_stwcx[] = {
#endif
/* lwarx */
-GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_lwarx();
gen_op_store_T1_gpr(rD(ctx->opcode));
}
@@ -1518,19 +1560,13 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
/* stwcx. */
GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
gen_op_load_gpr_T1(rS(ctx->opcode));
op_stwcx();
}
/* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
{
}
@@ -1538,79 +1574,59 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
#define GEN_LDF(width, opc) \
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
#define GEN_LDUF(width, opc) \
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ gen_addr_imm_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
#define GEN_LDUXF(width, opc) \
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
#define GEN_LDXF(width, opc2, opc3) \
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
#define GEN_LDFS(width, op) \
@@ -1629,38 +1645,28 @@ GEN_LDFS(fs, 0x10);
#define GEN_STF(width, opc) \
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_imm_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
}
#define GEN_STUF(width, opc) \
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_imm_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
@@ -1668,18 +1674,16 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
#define GEN_STUXF(width, opc) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
@@ -1687,18 +1691,12 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
#define GEN_STXF(width, opc2, opc3) \
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
}
@@ -1718,10 +1716,12 @@ GEN_STFS(fs, 0x14);
/* stfiwx */
GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
+ gen_addr_reg_index(ctx);
+ /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
RET_INVAL(ctx);
}
@@ -1745,9 +1745,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
} else {
gen_op_set_T1(dest);
gen_op_b_T1();
+ gen_op_reset_T0();
if (ctx->singlestep_enabled)
gen_op_debug();
- gen_op_set_T0(0);
gen_op_exit_tb();
}
}
@@ -1755,12 +1755,15 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
- uint32_t li, target;
+ target_ulong li, target;
/* sign extend LI */
- li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
-
- if (AA(ctx->opcode) == 0)
+#if defined(TARGET_PPC64)
+ li = ((target_long)LI(ctx->opcode) << 38) >> 38;
+#else
+ li = ((target_long)LI(ctx->opcode) << 6) >> 6;
+#endif
+ if (likely(AA(ctx->opcode) == 0))
target = ctx->nip + li - 4;
else
target = li;
@@ -1777,18 +1780,18 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
static inline void gen_bcond(DisasContext *ctx, int type)
{
- uint32_t target = 0;
+ target_ulong target = 0;
+ target_ulong li;
uint32_t bo = BO(ctx->opcode);
uint32_t bi = BI(ctx->opcode);
uint32_t mask;
- uint32_t li;
if ((bo & 0x4) == 0)
gen_op_dec_ctr();
switch(type) {
case BCOND_IM:
- li = (int32_t)((int16_t)(BD(ctx->opcode)));
- if (AA(ctx->opcode) == 0) {
+ li = (target_long)((int16_t)(BD(ctx->opcode)));
+ if (likely(AA(ctx->opcode) == 0)) {
target = ctx->nip + li - 4;
} else {
target = li;
@@ -1821,6 +1824,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
gen_goto_tb(ctx, 0, target);
} else {
gen_op_b_T1();
+ gen_op_reset_T0();
}
goto no_test;
}
@@ -1865,8 +1869,12 @@ static inline void gen_bcond(DisasContext *ctx, int type)
gen_goto_tb(ctx, 1, ctx->nip);
} else {
gen_op_btest_T1(ctx->nip);
+ gen_op_reset_T0();
}
no_test:
+ if (ctx->singlestep_enabled)
+ gen_op_debug();
+ gen_op_exit_tb();
ctx->exception = EXCP_BRANCH;
}
@@ -1901,21 +1909,21 @@ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
}
/* crand */
-GEN_CRLOGIC(and, 0x08)
+GEN_CRLOGIC(and, 0x08);
/* crandc */
-GEN_CRLOGIC(andc, 0x04)
+GEN_CRLOGIC(andc, 0x04);
/* creqv */
-GEN_CRLOGIC(eqv, 0x09)
+GEN_CRLOGIC(eqv, 0x09);
/* crnand */
-GEN_CRLOGIC(nand, 0x07)
+GEN_CRLOGIC(nand, 0x07);
/* crnor */
-GEN_CRLOGIC(nor, 0x01)
+GEN_CRLOGIC(nor, 0x01);
/* cror */
-GEN_CRLOGIC(or, 0x0E)
+GEN_CRLOGIC(or, 0x0E);
/* crorc */
-GEN_CRLOGIC(orc, 0x0D)
+GEN_CRLOGIC(orc, 0x0D);
/* crxor */
-GEN_CRLOGIC(xor, 0x06)
+GEN_CRLOGIC(xor, 0x06);
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
@@ -1925,13 +1933,13 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
/*** System linkage ***/
/* rfi (supervisor only) */
-GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
+GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
/* Restore CPU state */
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
@@ -1952,7 +1960,7 @@ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
/*** Trap ***/
/* tw */
-GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
+GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
@@ -1965,39 +1973,11 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
-#if 0
- printf("%s: param=0x%04x T0=0x%04x\n", __func__,
- SIMM(ctx->opcode), TO(ctx->opcode));
-#endif
- gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
+ gen_op_set_T1(SIMM(ctx->opcode));
+ gen_op_tw(TO(ctx->opcode));
}
/*** Processor control ***/
-static inline int check_spr_access (int spr, int rw, int supervisor)
-{
- uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
-
-#if 0
- if (spr != LR && spr != CTR) {
- if (loglevel > 0) {
- fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
- SPR_ENCODE(spr), supervisor, rw, rights,
- (rights >> ((2 * supervisor) + rw)) & 1);
- } else {
- printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
- SPR_ENCODE(spr), supervisor, rw, rights,
- (rights >> ((2 * supervisor) + rw)) & 1);
- }
- }
-#endif
- if (rights == 0)
- return -1;
- rights = rights >> (2 * supervisor);
- rights = rights >> rw;
-
- return rights & 1;
-}
-
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
@@ -2007,9 +1987,22 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
}
/* mfcr */
-GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
{
- gen_op_load_cr();
+#if 0 // XXX: to be tested
+ uint32_t crm, crn;
+
+ if (likely(ctx->opcode & 0x00100000)) {
+ crm = CRM(ctx->opcode);
+ if (likely((crm ^ (crm - 1)) == 0)) {
+ crn = ffs(crm);
+ gen_op_load_cro(7 - crn);
+ }
+ } else
+#endif
+ {
+ gen_op_load_cr();
+ }
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -2019,7 +2012,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
@@ -2051,8 +2044,8 @@ static inline void gen_op_mfspr (DisasContext *ctx)
else
#endif
read_cb = ctx->spr_cb[sprn].uea_read;
- if (read_cb != NULL) {
- if (read_cb != SPR_NOACCESS) {
+ if (likely(read_cb != NULL)) {
+ if (likely(read_cb != SPR_NOACCESS)) {
(*read_cb)(ctx, sprn);
gen_op_store_T0_gpr(rD(ctx->opcode));
} else {
@@ -2062,7 +2055,7 @@ static inline void gen_op_mfspr (DisasContext *ctx)
sprn, sprn);
}
printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
+ RET_PRIVREG(ctx);
}
} else {
/* Not defined */
@@ -2078,7 +2071,7 @@ static inline void gen_op_mfspr (DisasContext *ctx)
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
{
gen_op_mfspr(ctx);
- }
+}
/* mftb */
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
@@ -2087,11 +2080,20 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
}
/* mtcrf */
-/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
{
+ uint32_t crm, crn;
+
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_cr(CRM(ctx->opcode));
+ crm = CRM(ctx->opcode);
+ if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
+ crn = ffs(crm);
+ gen_op_srli_T0(crn * 4);
+ gen_op_andi_T0(0xF);
+ gen_op_store_cro(7 - crn);
+ } else {
+ gen_op_store_cr(crm);
+ }
}
/* mtmsr */
@@ -2100,7 +2102,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
@@ -2124,8 +2126,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
else
#endif
write_cb = ctx->spr_cb[sprn].uea_write;
- if (write_cb != NULL) {
- if (write_cb != SPR_NOACCESS) {
+ if (likely(write_cb != NULL)) {
+ if (likely(write_cb != SPR_NOACCESS)) {
gen_op_load_gpr_T0(rS(ctx->opcode));
(*write_cb)(ctx, sprn);
} else {
@@ -2135,8 +2137,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
sprn, sprn);
}
printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
- }
+ RET_PRIVREG(ctx);
+ }
} else {
/* Not defined */
if (loglevel) {
@@ -2156,13 +2158,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
/* dcbf */
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_ldst(lbz);
}
@@ -2172,18 +2168,13 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
- op_ldst(lbz);
+ gen_addr_reg_index(ctx);
+ /* XXX: specification says this should be treated as a store by the MMU */
+ //op_ldst(lbz);
op_ldst(stb);
#endif
}
@@ -2191,31 +2182,35 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
/* dcdst */
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ /* XXX: specification say this is treated as a load by the MMU */
+ gen_addr_reg_index(ctx);
op_ldst(lbz);
}
/* dcbt */
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
{
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
}
/* dcbtst */
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
{
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
}
/* dcbz */
+#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
-#define op_dcbz() gen_op_dcbz_raw()
+static GenOpFunc *gen_op_dcbz[] = {
+ &gen_op_dcbz_raw,
+ &gen_op_dcbz_raw,
+};
#else
-#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
static GenOpFunc *gen_op_dcbz[] = {
&gen_op_dcbz_user,
&gen_op_dcbz_user,
@@ -2226,13 +2221,7 @@ static GenOpFunc *gen_op_dcbz[] = {
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_dcbz();
gen_op_check_reservation();
}
@@ -2240,14 +2229,11 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
/* icbi */
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
gen_op_icbi();
+ RET_STOP(ctx);
}
/* Optional: */
@@ -2264,11 +2250,12 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
- gen_op_load_sr(SR(ctx->opcode));
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_load_sr();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
@@ -2279,12 +2266,13 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_load_srin();
+ gen_op_srli_T1(28);
+ gen_op_load_sr();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
@@ -2295,12 +2283,13 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_sr(SR(ctx->opcode));
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_store_sr();
RET_STOP(ctx);
#endif
}
@@ -2311,13 +2300,14 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_store_srin();
+ gen_op_srli_T1(28);
+ gen_op_store_sr();
RET_STOP(ctx);
#endif
}
@@ -2330,7 +2320,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
if (loglevel)
fprintf(logfile, "%s: ! supervisor\n", __func__);
RET_PRIVOPC(ctx);
@@ -2342,12 +2332,12 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
}
/* tlbie */
-GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
@@ -2358,12 +2348,12 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
}
/* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
@@ -2406,13 +2396,7 @@ static GenOpFunc *gen_op_ecowx[] = {
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
/* Should check EAR[E] & alignment ! */
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_eciwx();
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -2421,15 +2405,1140 @@ GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
/* Should check EAR[E] & alignment ! */
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
+ gen_addr_reg_index(ctx);
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ op_ecowx();
+}
+
+/* PowerPC 601 specific instructions */
+/* abs - abs. */
+GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_abs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* abso - abso. */
+GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_abso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* clcs */
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_clcs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* div - div. */
+GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_div();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divo - divo. */
+GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divs - divs. */
+GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divso - divso. */
+GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* doz - doz. */
+GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_doz();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* dozo - dozo. */
+GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_dozo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* dozi */
+GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_set_T1(SIMM(ctx->opcode));
+ gen_op_POWER_doz();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* As lscbx load from memory byte after byte, it's always endian safe */
+#define op_POWER_lscbx(start, ra, rb) \
+(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+ &gen_op_POWER_lscbx_raw,
+ &gen_op_POWER_lscbx_raw,
+};
+#else
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+ &gen_op_POWER_lscbx_user,
+ &gen_op_POWER_lscbx_user,
+ &gen_op_POWER_lscbx_kernel,
+ &gen_op_POWER_lscbx_kernel,
+};
+#endif
+
+/* lscbx - lscbx. */
+GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
+{
+ int ra = rA(ctx->opcode);
+ int rb = rB(ctx->opcode);
+
+ gen_addr_reg_index(ctx);
+ if (ra == 0) {
+ ra = rb;
+ }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_op_load_xer_bc();
+ gen_op_load_xer_cmp();
+ op_POWER_lscbx(rD(ctx->opcode), ra, rb);
+ gen_op_store_xer_bc();
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* maskg - maskg. */
+GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_maskg();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* maskir - maskir. */
+GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_maskir();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* mul - mul. */
+GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_mul();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* mulo - mulo. */
+GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_mulo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* nabs - nabs. */
+GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_nabs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* nabso - nabso. */
+GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_nabso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* rlmi - rlmi. */
+GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+ uint32_t mb, me;
+
+ mb = MB(ctx->opcode);
+ me = ME(ctx->opcode);
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* rrib - rrib. */
+GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_rrib();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sle - sle. */
+GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sle();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sleq - sleq. */
+GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sleq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sliq - sliq. */
+GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sle();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* slliq - slliq. */
+GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sleq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sllq - sllq. */
+GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sllq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* slq - slq. */
+GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_slq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sraiq -sraiq. */
+GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sraq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sraq - sraq. */
+GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sraq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sre - sre. */
+GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sre();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srea - srea. */
+GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srea();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sreq */
+GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sreq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sriq */
+GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_srq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srliq */
+GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_srlq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srlq */
+GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srlq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srq */
+GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* PowerPC 602 specific instructions */
+/* dsa */
+GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+/* esa */
+GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+/* mfrom */
+GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_602_mfrom();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* 602 - 603 - G2 TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_6xx_tlbld();
+ RET_STOP(ctx);
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_6xx_tlbli();
+ RET_STOP(ctx);
+#endif
+}
+
+/* POWER instructions not in PowerPC 601 */
+/* clf */
+GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
+{
+ /* Cache line flush: implemented as no-op */
+}
+
+/* cli */
+GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
+{
+ /* Cache line invalidate: priviledged and treated as no-op */
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+#endif
+}
+
+/* dclst */
+GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
+{
+ /* Data cache line store: treated as no-op */
+}
+
+GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ int ra = rA(ctx->opcode);
+ int rd = rD(ctx->opcode);
+
+ gen_addr_reg_index(ctx);
+ gen_op_POWER_mfsri();
+ gen_op_store_T0_gpr(rd);
+ if (ra != 0 && ra != rd)
+ gen_op_store_T1_gpr(ra);
+#endif
+}
+
+GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ gen_op_POWER_rac();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_POWER_rfsvc();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* svc is not implemented for now */
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
+#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+ &gen_op_POWER2_lfq_le_raw,
+ &gen_op_POWER2_lfq_raw,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+ &gen_op_POWER2_stfq_le_raw,
+ &gen_op_POWER2_stfq_raw,
+};
+#else
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+ &gen_op_POWER2_lfq_le_user,
+ &gen_op_POWER2_lfq_user,
+ &gen_op_POWER2_lfq_le_kernel,
+ &gen_op_POWER2_lfq_kernel,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+ &gen_op_POWER2_stfq_le_user,
+ &gen_op_POWER2_stfq_user,
+ &gen_op_POWER2_stfq_le_kernel,
+ &gen_op_POWER2_stfq_kernel,
+};
+#endif
+
+/* lfq */
+GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* lfqu */
+GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* lfqux */
+GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* lfqx */
+GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* stfq */
+GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+}
+
+/* stfqu */
+GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_imm_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* stfqux */
+GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* stfqx */
+GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_op_update_nip(ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+}
+
+/* BookE specific instructions */
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ /* Use the same micro-ops as for tlbie */
+ gen_op_tlbie();
+ RET_STOP(ctx);
+#endif
+}
+
+/* All 405 MAC instructions are translated here */
+static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
+ int ra, int rb, int rt, int Rc)
+{
+ gen_op_load_gpr_T0(ra);
+ gen_op_load_gpr_T1(rb);
+ switch (opc3 & 0x0D) {
+ case 0x05:
+ /* macchw - macchw. - macchwo - macchwo. */
+ /* macchws - macchws. - macchwso - macchwso. */
+ /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */
+ /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */
+ /* mulchw - mulchw. */
+ gen_op_405_mulchw();
+ break;
+ case 0x04:
+ /* macchwu - macchwu. - macchwuo - macchwuo. */
+ /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */
+ /* mulchwu - mulchwu. */
+ gen_op_405_mulchwu();
+ break;
+ case 0x01:
+ /* machhw - machhw. - machhwo - machhwo. */
+ /* machhws - machhws. - machhwso - machhwso. */
+ /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */
+ /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */
+ /* mulhhw - mulhhw. */
+ gen_op_405_mulhhw();
+ break;
+ case 0x00:
+ /* machhwu - machhwu. - machhwuo - machhwuo. */
+ /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */
+ /* mulhhwu - mulhhwu. */
+ gen_op_405_mulhhwu();
+ break;
+ case 0x0D:
+ /* maclhw - maclhw. - maclhwo - maclhwo. */
+ /* maclhws - maclhws. - maclhwso - maclhwso. */
+ /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */
+ /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */
+ /* mullhw - mullhw. */
+ gen_op_405_mullhw();
+ break;
+ case 0x0C:
+ /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */
+ /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */
+ /* mullhwu - mullhwu. */
+ gen_op_405_mullhwu();
+ break;
+ }
+ if (opc2 & 0x02) {
+ /* nmultiply-and-accumulate (0x0E) */
+ gen_op_neg();
+ }
+ if (opc2 & 0x04) {
+ /* (n)multiply-and-accumulate (0x0C - 0x0E) */
+ gen_op_load_gpr_T2(rt);
+ gen_op_move_T1_T0();
+ gen_op_405_add_T0_T2();
+ }
+ if (opc3 & 0x10) {
+ /* Check overflow */
+ if (opc3 & 0x01)
+ gen_op_405_check_ov();
+ else
+ gen_op_405_check_ovu();
+ }
+ if (opc3 & 0x02) {
+ /* Saturate */
+ if (opc3 & 0x01)
+ gen_op_405_check_sat();
+ else
+ gen_op_405_check_satu();
+ }
+ gen_op_store_T0_gpr(rt);
+ if (unlikely(Rc) != 0) {
+ /* Update Rc0 */
+ gen_set_Rc0(ctx);
+ }
+}
+
+#define GEN_MAC_HANDLER(name, opc2, opc3) \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \
+{ \
+ gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \
+ rD(ctx->opcode), Rc(ctx->opcode)); \
+}
+
+/* macchw - macchw. */
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
+/* macchwo - macchwo. */
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
+/* macchws - macchws. */
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
+/* macchwso - macchwso. */
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
+/* macchwsu - macchwsu. */
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
+/* macchwsuo - macchwsuo. */
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
+/* macchwu - macchwu. */
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
+/* macchwuo - macchwuo. */
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
+/* machhw - machhw. */
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
+/* machhwo - machhwo. */
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
+/* machhws - machhws. */
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
+/* machhwso - machhwso. */
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
+/* machhwsu - machhwsu. */
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
+/* machhwsuo - machhwsuo. */
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
+/* machhwu - machhwu. */
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
+/* machhwuo - machhwuo. */
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
+/* maclhw - maclhw. */
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
+/* maclhwo - maclhwo. */
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
+/* maclhws - maclhws. */
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
+/* maclhwso - maclhwso. */
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
+/* maclhwu - maclhwu. */
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
+/* maclhwuo - maclhwuo. */
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
+/* maclhwsu - maclhwsu. */
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
+/* maclhwsuo - maclhwsuo. */
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
+/* nmacchw - nmacchw. */
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
+/* nmacchwo - nmacchwo. */
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
+/* nmacchws - nmacchws. */
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
+/* nmacchwso - nmacchwso. */
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
+/* nmachhw - nmachhw. */
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
+/* nmachhwo - nmachhwo. */
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
+/* nmachhws - nmachhws. */
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
+/* nmachhwso - nmachhwso. */
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
+/* nmaclhw - nmaclhw. */
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
+/* nmaclhwo - nmaclhwo. */
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
+/* nmaclhws - nmaclhws. */
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
+/* nmaclhwso - nmaclhwso. */
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
+
+/* mulchw - mulchw. */
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
+/* mulchwu - mulchwu. */
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
+/* mulhhw - mulhhw. */
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
+/* mulhhwu - mulhhwu. */
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
+/* mullhw - mullhw. */
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
+/* mullhwu - mullhwu. */
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
+
+/* mfdcr */
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ uint32_t dcrn = SPR(ctx->opcode);
+
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_4xx_load_dcr(dcrn);
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtdcr */
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ uint32_t dcrn = SPR(ctx->opcode);
+
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_4xx_store_dcr(dcrn);
+#endif
+}
+
+/* dccci */
+GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* dcread */
+GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ op_ldst(lwz);
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* icbt */
+GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
+{
+ /* interpreted as no-op */
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
+}
+
+/* iccci */
+GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* icread */
+GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* rfci (supervisor only) */
+GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* Restore CPU state */
+ gen_op_4xx_rfci();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* tlbre */
+GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
+ gen_op_4xx_tlbre_hi();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ break;
+ case 1:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_4xx_tlbre_lo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ break;
+ default:
+ RET_INVAL(ctx);
+ break;
}
- gen_op_load_gpr_T2(rS(ctx->opcode));
- op_ecowx();
+#endif
+}
+
+/* tlbsx - tlbsx. */ /* Named tlbs in BookE */
+GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ if (Rc(ctx->opcode))
+ gen_op_4xx_tlbsx_();
+ else
+ gen_op_4xx_tlbsx();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_4xx_tlbwe_hi();
+ break;
+ case 1:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_4xx_tlbwe_lo();
+ break;
+ default:
+ RET_INVAL(ctx);
+ break;
+ }
+#endif
+}
+
+/* wrtee */
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rD(ctx->opcode));
+ gen_op_4xx_wrte();
+ RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* wrteei */
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_set_T0(ctx->opcode & 0x00010000);
+ gen_op_4xx_wrte();
+ RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* PPC 440 specific instructions */
+/* dlmzb */
+GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_440_dlmzb();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_xer_bc();
+ if (Rc(ctx->opcode)) {
+ gen_op_440_dlmzb_update_Rc();
+ gen_op_store_T0_crf(0);
+ }
+}
+
+/* mbar replaces eieio on 440 */
+GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+}
+
+/* msync replaces sync on 440 */
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+}
+
+/* icbt */
+GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
}
/* End opcode list */
@@ -2439,18 +3548,25 @@ GEN_OPCODE_MARK(end);
/*****************************************************************************/
/* Misc PowerPC helpers */
+static inline uint32_t load_xer (CPUState *env)
+{
+ return (xer_so << XER_SO) |
+ (xer_ov << XER_OV) |
+ (xer_ca << XER_CA) |
+ (xer_bc << XER_BC) |
+ (xer_cmp << XER_CMP);
+}
+
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
{
#if defined(TARGET_PPC64) || 1
#define FILL ""
-#define REGX "%016" PRIx64
#define RGPL 4
#define RFPL 4
#else
#define FILL " "
-#define REGX "%08" PRIx64
#define RGPL 8
#define RFPL 4
#endif
@@ -2459,30 +3575,38 @@ void cpu_dump_state(CPUState *env, FILE *f,
cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
env->nip, env->lr, env->ctr);
- cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n",
- do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
- cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
- for (i = 0; i < 32; i++) {
+ cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x "
+#if !defined(CONFIG_USER_ONLY)
+ "DECR %08x"
+#endif
+ "\n",
+ do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env),
+ cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+ , cpu_ppc_load_decr(env)
+#endif
+ );
+ for (i = 0; i < 32; i++) {
if ((i & (RGPL - 1)) == 0)
cpu_fprintf(f, "GPR%02d", i);
cpu_fprintf(f, " " REGX, env->gpr[i]);
if ((i & (RGPL - 1)) == (RGPL - 1))
cpu_fprintf(f, "\n");
- }
+ }
cpu_fprintf(f, "CR ");
- for (i = 0; i < 8; i++)
+ for (i = 0; i < 8; i++)
cpu_fprintf(f, "%01x", env->crf[i]);
cpu_fprintf(f, " [");
- for (i = 0; i < 8; i++) {
- char a = '-';
- if (env->crf[i] & 0x08)
- a = 'L';
- else if (env->crf[i] & 0x04)
- a = 'G';
- else if (env->crf[i] & 0x02)
- a = 'E';
+ for (i = 0; i < 8; i++) {
+ char a = '-';
+ if (env->crf[i] & 0x08)
+ a = 'L';
+ else if (env->crf[i] & 0x04)
+ a = 'G';
+ else if (env->crf[i] & 0x02)
+ a = 'E';
cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
- }
+ }
cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
for (i = 0; i < 32; i++) {
if ((i & (RFPL - 1)) == 0)
@@ -2501,6 +3625,53 @@ void cpu_dump_state(CPUState *env, FILE *f,
#undef FILL
}
+void cpu_dump_statistics (CPUState *env, FILE*f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+#if defined(DO_PPC_STATISTICS)
+ opc_handler_t **t1, **t2, **t3, *handler;
+ int op1, op2, op3;
+
+ t1 = env->opcodes;
+ for (op1 = 0; op1 < 64; op1++) {
+ handler = t1[op1];
+ if (is_indirect_opcode(handler)) {
+ t2 = ind_table(handler);
+ for (op2 = 0; op2 < 32; op2++) {
+ handler = t2[op2];
+ if (is_indirect_opcode(handler)) {
+ t3 = ind_table(handler);
+ for (op3 = 0; op3 < 32; op3++) {
+ handler = t3[op3];
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
+ "%016llx %lld\n",
+ op1, op2, op3, op1, (op3 << 5) | op2,
+ handler->oname,
+ handler->count, handler->count);
+ }
+ } else {
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: "
+ "%016llx %lld\n",
+ op1, op2, op1, op2, handler->oname,
+ handler->count, handler->count);
+ }
+ }
+ } else {
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n",
+ op1, op1, handler->oname,
+ handler->count, handler->count);
+ }
+ }
+#endif
+}
+
/*****************************************************************************/
int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int search_pc)
@@ -2534,8 +3705,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
#endif
/* Set env in case of segfault during code fetch */
while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
- if (env->nb_breakpoints > 0) {
- for(j = 0; j < env->nb_breakpoints; j++) {
+ if (unlikely(env->nb_breakpoints > 0)) {
+ for (j = 0; j < env->nb_breakpoints; j++) {
if (env->breakpoints[j] == ctx.nip) {
gen_op_update_nip(ctx.nip);
gen_op_debug();
@@ -2543,7 +3714,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
}
}
}
- if (search_pc) {
+ if (unlikely(search_pc)) {
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
@@ -2586,11 +3757,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
}
}
/* Is opcode *REALLY* valid ? */
- if (handler->handler == &gen_invalid) {
+ if (unlikely(handler->handler == &gen_invalid)) {
if (loglevel > 0) {
- fprintf(logfile, "invalid/unsupported opcode: "
+ fprintf(logfile, "invalid/unsupported opcode: "
"%02x - %02x - %02x (%08x) 0x%08x %d\n",
- opc1(ctx.opcode), opc2(ctx.opcode),
+ opc1(ctx.opcode), opc2(ctx.opcode),
opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
} else {
printf("invalid/unsupported opcode: "
@@ -2598,8 +3769,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
opc1(ctx.opcode), opc2(ctx.opcode),
opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
}
- } else {
- if ((ctx.opcode & handler->inval) != 0) {
+ } else {
+ if (unlikely((ctx.opcode & handler->inval) != 0)) {
if (loglevel > 0) {
fprintf(logfile, "invalid bits: %08x for opcode: "
"%02x -%02x - %02x (0x%08x) (0x%08x)\n",
@@ -2609,38 +3780,40 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
} else {
printf("invalid bits: %08x for opcode: "
"%02x -%02x - %02x (0x%08x) (0x%08x)\n",
- ctx.opcode & handler->inval, opc1(ctx.opcode),
- opc2(ctx.opcode), opc3(ctx.opcode),
+ ctx.opcode & handler->inval, opc1(ctx.opcode),
+ opc2(ctx.opcode), opc3(ctx.opcode),
ctx.opcode, ctx.nip - 4);
- }
+ }
RET_INVAL(ctxp);
break;
}
}
(*(handler->handler))(&ctx);
+#if defined(DO_PPC_STATISTICS)
+ handler->count++;
+#endif
/* Check trace mode exceptions */
- if ((msr_be && ctx.exception == EXCP_BRANCH) ||
- /* Check in single step trace mode
- * we need to stop except if:
- * - rfi, trap or syscall
- * - first instruction of an exception handler
- */
- (msr_se && (ctx.nip < 0x100 ||
- ctx.nip > 0xF00 ||
- (ctx.nip & 0xFC) != 0x04) &&
- ctx.exception != EXCP_SYSCALL &&
- ctx.exception != EXCP_SYSCALL_USER &&
- ctx.exception != EXCP_TRAP)) {
+ if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
+ /* Check in single step trace mode
+ * we need to stop except if:
+ * - rfi, trap or syscall
+ * - first instruction of an exception handler
+ */
+ (msr_se && (ctx.nip < 0x100 ||
+ ctx.nip > 0xF00 ||
+ (ctx.nip & 0xFC) != 0x04) &&
+ ctx.exception != EXCP_SYSCALL &&
+ ctx.exception != EXCP_SYSCALL_USER &&
+ ctx.exception != EXCP_TRAP))) {
RET_EXCP(ctxp, EXCP_TRACE, 0);
}
-
/* if we reach a page boundary or are single stepping, stop
* generation
*/
- if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled)) {
+ if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+ (env->singlestep_enabled))) {
break;
- }
+ }
#if defined (DO_SINGLE_STEP)
break;
#endif
@@ -2648,28 +3821,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
if (ctx.exception == EXCP_NONE) {
gen_goto_tb(&ctx, 0, ctx.nip);
} else if (ctx.exception != EXCP_BRANCH) {
- gen_op_set_T0(0);
+ gen_op_reset_T0();
+ /* Generate the return instruction */
+ gen_op_exit_tb();
}
-#if 1
- /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
- * do bad business and then qemu crashes !
- */
- gen_op_set_T0(0);
-#endif
- /* Generate the return instruction */
- gen_op_exit_tb();
*gen_opc_ptr = INDEX_op_end;
- if (search_pc) {
+ if (unlikely(search_pc)) {
j = gen_opc_ptr - gen_opc_buf;
lj++;
while (lj <= j)
gen_opc_instr_start[lj++] = 0;
tb->size = 0;
-#if 0
- if (loglevel > 0) {
- page_dump(logfile);
- }
-#endif
} else {
tb->size = ctx.nip - pc_start;
}
@@ -2679,8 +3841,10 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
cpu_dump_state(env, logfile, fprintf, 0);
}
if (loglevel & CPU_LOG_TB_IN_ASM) {
+ int flags;
+ flags = msr_le;
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
+ target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
fprintf(logfile, "\n");
}
if (loglevel & CPU_LOG_TB_OP) {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index ddf0c9126d..d4159fab45 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1,7 +1,7 @@
/*
* PowerPC CPU initialization for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -48,7 +48,7 @@ static void spr_write_generic (void *opaque, int sprn)
gen_op_store_spr(sprn);
}
-/* SPR common to all PPC */
+/* SPR common to all PowerPC */
/* XER */
static void spr_read_xer (void *opaque, int sprn)
{
@@ -93,8 +93,9 @@ static void spr_read_ureg (void *opaque, int sprn)
gen_op_load_spr(sprn + 0x10);
}
-/* SPR common to all non-embedded PPC (ie not 4xx) */
+/* SPR common to all non-embedded PowerPC */
/* DECR */
+#if !defined(CONFIG_USER_ONLY)
static void spr_read_decr (void *opaque, int sprn)
{
gen_op_load_decr();
@@ -104,29 +105,33 @@ static void spr_write_decr (void *opaque, int sprn)
{
gen_op_store_decr();
}
+#endif
-/* SPR common to all non-embedded PPC, except 601 */
+/* SPR common to all non-embedded PowerPC, except 601 */
/* Time base */
static void spr_read_tbl (void *opaque, int sprn)
{
gen_op_load_tbl();
}
-static void spr_write_tbl (void *opaque, int sprn)
+static void spr_read_tbu (void *opaque, int sprn)
{
- gen_op_store_tbl();
+ gen_op_load_tbu();
}
-static void spr_read_tbu (void *opaque, int sprn)
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_tbl (void *opaque, int sprn)
{
- gen_op_load_tbu();
+ gen_op_store_tbl();
}
static void spr_write_tbu (void *opaque, int sprn)
{
gen_op_store_tbu();
}
+#endif
+#if !defined(CONFIG_USER_ONLY)
/* IBAT0U...IBAT0U */
/* IBAT0L...IBAT7L */
static void spr_read_ibat (void *opaque, int sprn)
@@ -229,11 +234,129 @@ static void spr_write_sdr1 (void *opaque, int sprn)
RET_STOP(ctx);
}
+/* 64 bits PowerPC specific SPRs */
+/* ASR */
+#if defined(TARGET_PPC64)
+static void spr_read_asr (void *opaque, int sprn)
+{
+ gen_op_load_asr();
+}
+
+static void spr_write_asr (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_asr();
+ RET_STOP(ctx);
+}
+#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific registers */
+/* RTC */
+static void spr_read_601_rtcl (void *opaque, int sprn)
+{
+ gen_op_load_601_rtcl();
+}
+
+static void spr_read_601_rtcu (void *opaque, int sprn)
+{
+ gen_op_load_601_rtcu();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_601_rtcu (void *opaque, int sprn)
+{
+ gen_op_store_601_rtcu();
+}
+
+static void spr_write_601_rtcl (void *opaque, int sprn)
+{
+ gen_op_store_601_rtcl();
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_601_ubat (void *opaque, int sprn)
+{
+ gen_op_load_601_bat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_write_601_ubatu (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2);
+ RET_STOP(ctx);
+}
+
+static void spr_write_601_ubatl (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2);
+ RET_STOP(ctx);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_40x_pit (void *opaque, int sprn)
+{
+ gen_op_load_40x_pit();
+}
+
+static void spr_write_40x_pit (void *opaque, int sprn)
+{
+ gen_op_store_40x_pit();
+}
+
+static void spr_write_booke_tcr (void *opaque, int sprn)
+{
+ gen_op_store_booke_tcr();
+}
+
+static void spr_write_booke_tsr (void *opaque, int sprn)
+{
+ gen_op_store_booke_tsr();
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_403_pbr (void *opaque, int sprn)
+{
+ gen_op_load_403_pb(sprn - SPR_403_PBL1);
+}
+
+static void spr_write_403_pbr (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_403_pb(sprn - SPR_403_PBL1);
+ RET_STOP(ctx);
+}
+
static void spr_write_pir (void *opaque, int sprn)
{
gen_op_store_pir();
}
+#endif
+#if defined(CONFIG_USER_ONLY)
+#define spr_register(env, num, name, uea_read, uea_write, \
+ oea_read, oea_write, initial_value) \
+do { \
+ _spr_register(env, num, name, uea_read, uea_write, initial_value); \
+} while (0)
+static inline void _spr_register (CPUPPCState *env, int num,
+ const unsigned char *name,
+ void (*uea_read)(void *opaque, int sprn),
+ void (*uea_write)(void *opaque, int sprn),
+ target_ulong initial_value)
+#else
static inline void spr_register (CPUPPCState *env, int num,
const unsigned char *name,
void (*uea_read)(void *opaque, int sprn),
@@ -241,25 +364,30 @@ static inline void spr_register (CPUPPCState *env, int num,
void (*oea_read)(void *opaque, int sprn),
void (*oea_write)(void *opaque, int sprn),
target_ulong initial_value)
+#endif
{
ppc_spr_t *spr;
spr = &env->spr_cb[num];
if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
- spr->uea_read != NULL || spr->uea_write != NULL ||
- spr->oea_read != NULL || spr->oea_write != NULL) {
+#if !defined(CONFIG_USER_ONLY)
+ spr->oea_read != NULL || spr->oea_write != NULL ||
+#endif
+ spr->uea_read != NULL || spr->uea_write != NULL) {
printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
exit(1);
}
#if defined(PPC_DEBUG_SPR)
- printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name,
- (unsigned long long)initial_value);
+ printf("*** register spr %d (%03x) %s val " REGX "\n", num, num, name,
+ initial_value);
#endif
spr->name = name;
spr->uea_read = uea_read;
spr->uea_write = uea_write;
+#if !defined(CONFIG_USER_ONLY)
spr->oea_read = oea_read;
spr->oea_write = oea_write;
+#endif
env->spr[num] = initial_value;
}
@@ -493,6 +621,70 @@ static void gen_tbl (CPUPPCState *env)
0x00000000);
}
+/* Softare table search registers */
+static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+ env->nb_tlb = nb_tlbs;
+ env->nb_ways = nb_ways;
+ env->id_tlbs = 1;
+ spr_register(env, SPR_DMISS, "DMISS",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_DCMP, "DCMP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_HASH1, "HASH1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_HASH2, "HASH2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_IMISS, "IMISS",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_ICMP, "ICMP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_RPA, "RPA",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR common to MPC755 and G2 */
+static void gen_spr_G2_755 (CPUPPCState *env)
+{
+ /* SGPRs */
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* External access control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_EAR, "EAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
/* SPR common to all 7xx PowerPC implementations */
static void gen_spr_7xx (CPUPPCState *env)
{
@@ -513,6 +705,11 @@ static void gen_spr_7xx (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_L2CR, "L2CR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
/* Performance monitors */
/* XXX : not implemented */
spr_register(env, SPR_MMCR0, "MMCR0",
@@ -669,7 +866,817 @@ static void gen_spr_604 (CPUPPCState *env)
0x00000000);
}
-// XXX: TODO (64 bits PPC sprs)
+/* SPR specific to PowerPC 603 implementation */
+static void gen_spr_603 (CPUPPCState *env)
+{
+ /* 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 G2 implementation */
+static void gen_spr_G2 (CPUPPCState *env)
+{
+ /* Memory base address */
+ /* MBAR */
+ spr_register(env, SPR_MBAR, "MBAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* System version register */
+ /* SVR */
+ spr_register(env, SPR_SVR, "SVR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Exception processing */
+ spr_register(env, SPR_CSRR0, "CSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_CSRR1, "CSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Breakpoints */
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR, "DABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR2, "DABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR, "IABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR2, "IABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IBCR, "IBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DBCR, "DBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 602 implementation */
+static void gen_spr_602 (CPUPPCState *env)
+{
+ /* ESA registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_SER, "SER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_SEBR, "SEBR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_ESASR, "ESASR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Floating point status */
+ /* XXX : not implemented */
+ spr_register(env, SPR_SP, "SP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_LT, "LT",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Watchdog timer */
+ /* XXX : not implemented */
+ spr_register(env, SPR_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Interrupt base */
+ spr_register(env, SPR_IBR, "IBR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 601 implementation */
+static void gen_spr_601 (CPUPPCState *env)
+{
+ /* Multiplication/division register */
+ /* MQ */
+ spr_register(env, SPR_MQ, "MQ",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* RTC registers */
+ spr_register(env, SPR_601_RTCU, "RTCU",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_601_rtcu,
+ 0x00000000);
+ spr_register(env, SPR_601_VRTCU, "RTCU",
+ &spr_read_601_rtcu, SPR_NOACCESS,
+ &spr_read_601_rtcu, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_601_RTCL, "RTCL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_601_rtcl,
+ 0x00000000);
+ spr_register(env, SPR_601_VRTCL, "RTCL",
+ &spr_read_601_rtcl, SPR_NOACCESS,
+ &spr_read_601_rtcl, SPR_NOACCESS,
+ 0x00000000);
+ /* Timer */
+#if 0 /* ? */
+ spr_register(env, SPR_601_UDECR, "UDECR",
+ &spr_read_decr, SPR_NOACCESS,
+ &spr_read_decr, SPR_NOACCESS,
+ 0x00000000);
+#endif
+ /* External access control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_EAR, "EAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Memory management */
+ spr_register(env, SPR_IBAT0U, "IBAT0U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT0L, "IBAT0L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT1U, "IBAT1U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT1L, "IBAT1L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT2U, "IBAT2U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT2L, "IBAT2L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT3U, "IBAT3U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT3L, "IBAT3L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+}
+
+/* PowerPC BookE SPR */
+static void gen_spr_BookE (CPUPPCState *env)
+{
+ /* Processor identification */
+ spr_register(env, SPR_BOOKE_PIR, "PIR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_pir,
+ 0x00000000);
+ /* Interrupt processing */
+ spr_register(env, SPR_CSRR0, "CSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_CSRR1, "CSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC1, "IAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DAC1, "DAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR0, "DBCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR1, "DBCR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR2, "DBCR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBSR, "DBSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DEAR, "DEAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_ESR, "ESR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_EVPR, "EVPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR0, "IVOR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR1, "IVOR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR2, "IVOR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR3, "IVOR3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR4, "IVOR4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR5, "IVOR5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR6, "IVOR6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR7, "IVOR7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR8, "IVOR8",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR9, "IVOR9",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR10, "IVOR10",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR11, "IVOR11",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR12, "IVOR12",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR13, "IVOR13",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR14, "IVOR14",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR15, "IVOR15",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_PID, "PID",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tcr,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_TSR, "TSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tsr,
+ 0x00000000);
+ /* Timer */
+ spr_register(env, SPR_DECR, "DECR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_decr, &spr_write_decr,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DECAR, "DECAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ /* SPRGs */
+ spr_register(env, SPR_USPRG0, "USPRG0",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG4, "USPRG4",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG5, "USPRG5",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG6, "USPRG6",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG7, "USPRG7",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 440 implementation */
+static void gen_spr_440 (CPUPPCState *env)
+{
+ /* Cache control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV0, "DNV0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV1, "DNV1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV2, "DNV2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV3, "DNV3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT0, "DVT0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT1, "DVT1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT2, "DVT2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT3, "DVT3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVLIM, "DVLIM",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV0, "INV0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV1, "INV1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV2, "INV2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV3, "INV3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT0, "IVT0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT1, "IVT1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT2, "IVT2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT3, "IVT3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVLIM, "IVLIM",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Cache debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DCBTRH, "DCBTRH",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DCBTRL, "DCBTRL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_4xx_ICDBDR, "ICDBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_ICBTRH, "ICBTRH",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_ICBTRL, "ICBTRL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DBDR, "DBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Processor control */
+ spr_register(env, SPR_4xx_CCR0, "CCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_440_RSTCFG, "RSTCFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Storage control */
+ spr_register(env, SPR_440_MMUCR, "MMUCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR shared between PowerPC 40x implementations */
+static void gen_spr_40x (CPUPPCState *env)
+{
+ /* Cache */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DCCR, "DCCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DCWR, "DCWR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_ICCR, "ICCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_4xx_ICDBDR, "ICDBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Bus access control */
+ spr_register(env, SPR_40x_SGR, "SGR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0xFFFFFFFF);
+ spr_register(env, SPR_40x_ZPR, "ZPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* MMU */
+ spr_register(env, SPR_40x_PID, "PID",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Exception */
+ spr_register(env, SPR_40x_DEAR, "DEAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_ESR, "ESR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_EVPR, "EVPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_SRR2, "SRR2",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_SRR3, "SRR3",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Timers */
+ spr_register(env, SPR_40x_PIT, "PIT",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_40x_pit, &spr_write_40x_pit,
+ 0x00000000);
+ spr_register(env, SPR_40x_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tcr,
+ 0x00000000);
+ spr_register(env, SPR_40x_TSR, "TSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tsr,
+ 0x00000000);
+ /* Debug interface */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DAC1, "DAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DBCR0, "DBCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DBSR, "DBSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ /* Last reset was system reset (system boot */
+ 0x00000300);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_IAC1, "IAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 405 implementation */
+static void gen_spr_405 (CPUPPCState *env)
+{
+ spr_register(env, SPR_4xx_CCR0, "CCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00700000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DBCR1, "DBCR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DVC1, "DVC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DVC2, "DVC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_IAC3, "IAC3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_IAC4, "IAC4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Storage control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_SLER, "SLER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_SU0R, "SU0R",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* SPRG */
+ spr_register(env, SPR_USPRG0, "USPRG0",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG4, "USPRG4",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG5, "USPRG5",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG6, "USPRG6",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG7, "USPRG7",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR shared between PowerPC 401 & 403 implementations */
+static void gen_spr_401_403 (CPUPPCState *env)
+{
+ /* Time base */
+ spr_register(env, SPR_403_VTBL, "TBL",
+ &spr_read_tbl, SPR_NOACCESS,
+ &spr_read_tbl, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_403_TBL, "TBL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_tbl,
+ 0x00000000);
+ spr_register(env, SPR_403_VTBU, "TBU",
+ &spr_read_tbu, SPR_NOACCESS,
+ &spr_read_tbu, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_403_TBU, "TBU",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_tbu,
+ 0x00000000);
+ /* Debug */
+ /* XXX: not implemented */
+ spr_register(env, SPR_403_CDBCR, "CDBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 403 implementation */
+static void gen_spr_403 (CPUPPCState *env)
+{
+ /* MMU */
+ spr_register(env, SPR_403_PBL1, "PBL1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBU1, "PBU1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBL2, "PBL2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBU2, "PBU2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC compression coprocessor extension */
+#if defined (TODO)
+static void gen_spr_compress (CPUPPCState *env)
+{
+ spr_register(env, SPR_401_SKR, "SKR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+#endif
+
+// XXX: TODO (64 bits PowerPC SPRs)
/*
* ASR => SPR 280 (64 bits)
* FPECR => SPR 1022 (?)
@@ -691,32 +1698,229 @@ static void gen_spr_604 (CPUPPCState *env)
static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
{
+ env->reserve = -1;
/* Default MMU definitions */
env->nb_BATs = -1;
env->nb_tlb = 0;
env->nb_ways = 0;
/* XXX: missing:
- * 32 bits PPC:
+ * 32 bits PowerPC:
* - MPC5xx(x)
* - MPC8xx(x)
- * - RCPU (MPC5xx)
+ * - RCPU (same as MPC5xx ?)
*/
spr_register(env, SPR_PVR, "PVR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
def->pvr);
+ printf("%s: PVR %08x mask %08x => %08x\n", __func__,
+ def->pvr, def->pvr_mask, def->pvr & def->pvr_mask);
switch (def->pvr & def->pvr_mask) {
- case CPU_PPC_604: /* PPC 604 */
- case CPU_PPC_604E: /* PPC 604e */
- case CPU_PPC_604R: /* PPC 604r */
+ /* Embedded PowerPC from IBM */
+ case CPU_PPC_401A1: /* 401 A1 family */
+ case CPU_PPC_401B2: /* 401 B2 family */
+ case CPU_PPC_401C2: /* 401 C2 family */
+ case CPU_PPC_401D2: /* 401 D2 family */
+ case CPU_PPC_401E2: /* 401 E2 family */
+ case CPU_PPC_401F2: /* 401 F2 family */
+ case CPU_PPC_401G2: /* 401 G2 family */
+ case CPU_PPC_IOP480: /* IOP 480 family */
+ case CPU_PPC_COBRA: /* IBM Processor for Network Resources */
+ gen_spr_generic(env);
+ gen_spr_40x(env);
+ gen_spr_401_403(env);
+#if defined (TODO)
+ /* XXX: optional ? */
+ gen_spr_compress(env);
+#endif
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+ case CPU_PPC_403GA: /* 403 GA family */
+ case CPU_PPC_403GB: /* 403 GB family */
+ case CPU_PPC_403GC: /* 403 GC family */
+ case CPU_PPC_403GCX: /* 403 GCX family */
+ gen_spr_generic(env);
+ gen_spr_40x(env);
+ gen_spr_401_403(env);
+ gen_spr_403(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+ case CPU_PPC_405CR: /* 405 GP/CR family */
+ case CPU_PPC_405EP: /* 405 EP family */
+ case CPU_PPC_405GPR: /* 405 GPR family */
+ case CPU_PPC_405D2: /* 405 D2 family */
+ case CPU_PPC_405D4: /* 405 D4 family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+ case CPU_PPC_NPE405H: /* NPe405 H family */
+ case CPU_PPC_NPE405H2:
+ case CPU_PPC_NPE405L: /* Npe405 L family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+#if defined (TODO)
+ case CPU_PPC_STB01000:
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB01010:
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB0210:
+#endif
+ case CPU_PPC_STB03: /* STB03 family */
+#if defined (TODO)
+ case CPU_PPC_STB043: /* STB043 family */
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB045: /* STB045 family */
+#endif
+ case CPU_PPC_STB25: /* STB25 family */
+#if defined (TODO)
+ case CPU_PPC_STB130: /* STB130 family */
+#endif
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+ case CPU_PPC_440EP: /* 440 EP family */
+ case CPU_PPC_440GP: /* 440 GP family */
+ case CPU_PPC_440GX: /* 440 GX family */
+ case CPU_PPC_440GXc: /* 440 GXc family */
+ case CPU_PPC_440GXf: /* 440 GXf family */
+ case CPU_PPC_440SP: /* 440 SP family */
+ case CPU_PPC_440SP2:
+ case CPU_PPC_440SPE: /* 440 SPE family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_BookE(env);
+ gen_spr_440(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+ /* Embedded PowerPC from Freescale */
+#if defined (TODO)
+ case CPU_PPC_5xx:
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_8xx: /* MPC821 / 823 / 850 / 860 */
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_82xx_HIP3: /* MPC8240 / 8260 */
+ case CPU_PPC_82xx_HIP4: /* MPC8240 / 8260 */
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_827x: /* MPC 827x / 828x */
+ break;
+#endif
+
+ /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */
+ case CPU_PPC_e500v110:
+ case CPU_PPC_e500v120:
+ case CPU_PPC_e500v210:
+ case CPU_PPC_e500v220:
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_BookE(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ break;
+
+#if defined (TODO)
+ case CPU_PPC_e600:
+ break;
+#endif
+
+ /* 32 bits PowerPC */
+ case CPU_PPC_601: /* PowerPC 601 */
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ gen_spr_601(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_601_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_601_HID5, "HID5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+#if 0 /* ? */
+ spr_register(env, SPR_601_HID15, "HID15",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+#endif
+ env->nb_tlb = 64;
+ env->nb_ways = 2;
+ env->id_tlbs = 0;
+ env->id_tlbs = 0;
+ break;
+
+ case CPU_PPC_602: /* PowerPC 602 */
gen_spr_generic(env);
gen_spr_ne_601(env);
/* Memory management */
gen_low_BATs(env);
/* Time base */
gen_tbl(env);
- gen_spr_604(env);
- /* Hardware implementation registers */
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_602(env);
+ /* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -729,21 +1933,79 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
0x00000000);
break;
- case CPU_PPC_74x: /* PPC 740 / 750 */
- case CPU_PPC_74xP: /* PPC 740P / 750P */
- case CPU_PPC_750CXE: /* IBM PPC 750cxe */
+ case CPU_PPC_603: /* PowerPC 603 */
+ case CPU_PPC_603E: /* PowerPC 603e */
+ case CPU_PPC_603E7v:
+ case CPU_PPC_603E7v2:
+ case CPU_PPC_603P: /* PowerPC 603p */
+ case CPU_PPC_603R: /* PowerPC 603r */
gen_spr_generic(env);
gen_spr_ne_601(env);
/* Memory management */
gen_low_BATs(env);
/* Time base */
gen_tbl(env);
- gen_spr_7xx(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_603(env);
+ /* hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
+ spr_register(env, SPR_HID1, "HID1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ break;
+
+ case CPU_PPC_G2: /* PowerPC G2 family */
+ case CPU_PPC_G2H4:
+ case CPU_PPC_G2gp:
+ case CPU_PPC_G2ls:
+ case CPU_PPC_G2LE: /* PowerPC G2LE family */
+ case CPU_PPC_G2LEgp:
+ case CPU_PPC_G2LEls:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ /* Memory management */
+ gen_high_BATs(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_G2_755(env);
+ gen_spr_G2(env);
+ /* Hardware implementation register */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ break;
+
+ case CPU_PPC_604: /* PowerPC 604 */
+ case CPU_PPC_604E: /* PowerPC 604e */
+ case CPU_PPC_604R: /* PowerPC 604r */
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_604(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -757,8 +2019,46 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
0x00000000);
break;
- case CPU_PPC_750FX: /* IBM PPC 750 FX */
- case CPU_PPC_750GX: /* IBM PPC 750 GX */
+ case CPU_PPC_74x: /* PowerPC 740 / 750 */
+ case CPU_PPC_740E:
+ case CPU_PPC_750E:
+ case CPU_PPC_74xP: /* PowerPC 740P / 750P */
+ case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe */
+ case CPU_PPC_750CXE22:
+ case CPU_PPC_750CXE23:
+ case CPU_PPC_750CXE24:
+ case CPU_PPC_750CXE24b:
+ case CPU_PPC_750CXE31:
+ case CPU_PPC_750CXE31b:
+ case CPU_PPC_750CXR:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_7xx(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ break;
+
+ case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */
+ case CPU_PPC_750FX20:
+ case CPU_PPC_750FX21:
+ case CPU_PPC_750FX22:
+ case CPU_PPC_750FX23:
+ case CPU_PPC_750GX10: /* IBM PowerPC 750 GX */
+ case CPU_PPC_750GX11:
+ case CPU_PPC_750GX12:
gen_spr_generic(env);
gen_spr_ne_601(env);
/* Memory management */
@@ -768,8 +2068,47 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
/* Time base */
gen_tbl(env);
gen_spr_7xx(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_750_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ break;
+
+ case CPU_PPC_755_10: /* PowerPC 755 */
+ case CPU_PPC_755_11:
+ case CPU_PPC_755_20:
+ case CPU_PPC_755D:
+ case CPU_PPC_755E:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ /* Memory management */
+ gen_high_BATs(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_G2_755(env);
+ /* L2 cache control */
/* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
+ spr_register(env, SPR_ICTC, "ICTC",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_L2PM, "L2PM",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
@@ -781,22 +2120,90 @@ static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_HID1, "HID1",
- SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_750_HID2, "HID2",
+ spr_register(env, SPR_HID2, "HID2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
break;
+#if defined (TODO)
+ /* G4 family */
+ case CPU_PPC_7400: /* PowerPC 7400 */
+ case CPU_PPC_7410C: /* PowerPC 7410 */
+ case CPU_PPC_7410D:
+ case CPU_PPC_7410E:
+ case CPU_PPC_7441: /* PowerPC 7441 */
+ case CPU_PPC_7445: /* PowerPC 7445 */
+ case CPU_PPC_7447: /* PowerPC 7447 */
+ case CPU_PPC_7447A: /* PowerPC 7447A */
+ case CPU_PPC_7448: /* PowerPC 7448 */
+ case CPU_PPC_7450: /* PowerPC 7450 */
+ case CPU_PPC_7450b:
+ case CPU_PPC_7451: /* PowerPC 7451 */
+ case CPU_PPC_7451G:
+ case CPU_PPC_7455: /* PowerPC 7455 */
+ case CPU_PPC_7455F:
+ case CPU_PPC_7455G:
+ case CPU_PPC_7457: /* PowerPC 7457 */
+ case CPU_PPC_7457C:
+ case CPU_PPC_7457A: /* PowerPC 7457A */
+ break;
+#endif
+
+#if defined (TODO)
+ /* 64 bits PowerPC */
+ case CPU_PPC_620: /* PowerPC 620 */
+ case CPU_PPC_630: /* PowerPC 630 (Power 3) */
+ case CPU_PPC_631: /* PowerPC 631 (Power 3+) */
+ case CPU_PPC_POWER4: /* Power 4 */
+ case CPU_PPC_POWER4P: /* Power 4+ */
+ case CPU_PPC_POWER5: /* Power 5 */
+ case CPU_PPC_POWER5P: /* Power 5+ */
+ case CPU_PPC_970: /* PowerPC 970 */
+ case CPU_PPC_970FX10: /* PowerPC 970 FX */
+ case CPU_PPC_970FX20:
+ case CPU_PPC_970FX21:
+ case CPU_PPC_970FX30:
+ case CPU_PPC_970FX31:
+ case CPU_PPC_970MP10: /* PowerPC 970 MP */
+ case CPU_PPC_970MP11:
+ case CPU_PPC_CELL10: /* Cell family */
+ case CPU_PPC_CELL20:
+ case CPU_PPC_CELL30:
+ case CPU_PPC_CELL31:
+ case CPU_PPC_RS64: /* Apache (RS64/A35) */
+ case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */
+ case CPU_PPC_RS64III: /* Pulsar (RS64-III) */
+ case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */
+ break;
+#endif
+
+#if defined (TODO)
+ /* POWER */
+ case CPU_POWER: /* POWER */
+ case CPU_POWER2: /* POWER2 */
+ break;
+#endif
+
default:
gen_spr_generic(env);
break;
}
if (env->nb_BATs == -1)
env->nb_BATs = 4;
+ /* Allocate TLBs buffer when needed */
+ if (env->nb_tlb != 0) {
+ int nb_tlb = env->nb_tlb;
+ if (env->id_tlbs != 0)
+ nb_tlb *= 2;
+ env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+ /* Pre-compute some useful values */
+ env->tlb_per_way = env->nb_tlb / env->nb_ways;
+ }
}
#if defined(PPC_DUMP_CPU)
@@ -812,8 +2219,13 @@ static void dump_sprs (CPUPPCState *env)
for (j = 0; j < 32; j++) {
n = (i << 5) | j;
spr = &env->spr_cb[n];
+#if !defined(CONFIG_USER_ONLY)
sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
+#else
+ sw = 0;
+ sr = 0;
+#endif
uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS;
ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS;
if (sw || sr || uw || ur) {
@@ -889,7 +2301,7 @@ static int register_direct_insn (opc_handler_t **ppc_opcodes,
{
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in main "
- "opcode table\n", idx);
+ "opcode table\n", idx);
return -1;
}
@@ -903,20 +2315,20 @@ static int register_ind_in_table (opc_handler_t **table,
if (table[idx1] == &invalid_handler) {
if (create_new_table(table, idx1) < 0) {
printf("*** ERROR: unable to create indirect table "
- "idx=%02x\n", idx1);
+ "idx=%02x\n", idx1);
return -1;
}
} else {
if (!is_indirect_opcode(table[idx1])) {
printf("*** ERROR: idx %02x already assigned to a direct "
- "opcode\n", idx1);
+ "opcode\n", idx1);
return -1;
}
}
if (handler != NULL &&
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in "
- "opcode table %02x\n", idx2, idx1);
+ "opcode table %02x\n", idx2, idx1);
return -1;
}
@@ -925,7 +2337,7 @@ static int register_ind_in_table (opc_handler_t **table,
static int register_ind_insn (opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
+ opc_handler_t *handler)
{
int ret;
@@ -936,17 +2348,17 @@ static int register_ind_insn (opc_handler_t **ppc_opcodes,
static int register_dblind_insn (opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
- unsigned char idx3, opc_handler_t *handler)
+ unsigned char idx3, opc_handler_t *handler)
{
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
- "[%02x-%02x]\n", idx1, idx2);
+ "[%02x-%02x]\n", idx1, idx2);
return -1;
}
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
handler) < 0) {
printf("*** ERROR: unable to insert opcode "
- "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+ "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
@@ -1012,21 +2424,22 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
fill_new_table(env->opcodes, 0x40);
#if defined(PPC_DUMP_CPU)
- printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
+ printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n",
+ def->pvr, def->name, def->insns_flags, def->flags);
#endif
if (&opc_start < &opc_end) {
- start = &opc_start;
- end = &opc_end;
+ start = &opc_start;
+ end = &opc_end;
} else {
- start = &opc_end;
- end = &opc_start;
+ start = &opc_end;
+ end = &opc_start;
}
for (opc = start + 1; opc != end; opc++) {
if ((opc->handler.type & def->insns_flags) != 0) {
if (register_insn(env->opcodes, opc) < 0) {
- printf("*** ERROR initializing PPC instruction "
- "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
- opc->opc3);
+ printf("*** ERROR initializing PowerPC instruction "
+ "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+ opc->opc3);
return -1;
}
#if defined(PPC_DUMP_CPU)
@@ -1038,7 +2451,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
} else {
printf(" %02x %02x -- (%2d %4d) : %s\n",
opc->opc1, opc->opc2, opc->opc1, opc->opc2,
- opc->oname);
+ opc->oname);
}
} else {
printf(" %02x %02x %02x (%2d %4d) : %s\n",
@@ -1061,23 +2474,22 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def)
{
env->msr_mask = def->msr_mask;
env->flags = def->flags;
- if (create_ppc_opcodes(env, def) < 0) {
- printf("Error creating opcodes table\n");
- fflush(stdout);
- fflush(stderr);
+ if (create_ppc_opcodes(env, def) < 0)
return -1;
- }
init_ppc_proc(env, def);
#if defined(PPC_DUMP_CPU)
dump_sprs(env);
+ if (env->tlb != NULL) {
+ printf("%d %s TLB in %d ways\n", env->nb_tlb,
+ env->id_tlbs ? "splitted" : "merged", env->nb_ways);
+ }
#endif
- fflush(stdout);
- fflush(stderr);
return 0;
}
-CPUPPCState *cpu_ppc_init(void)
+void do_compute_hflags (CPUPPCState *env);
+CPUPPCState *cpu_ppc_init (void)
{
CPUPPCState *env;
@@ -1112,911 +2524,1171 @@ void cpu_ppc_close(CPUPPCState *env)
/*****************************************************************************/
/* PowerPC CPU definitions */
static ppc_def_t ppc_defs[] =
-{
- /* Embedded PPC */
-#if defined (TODO)
- /* PPC 401 */
{
- .name = "401",
- .pvr = CPU_PPC_401,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_401,
- .flags = PPC_FLAGS_401,
- .msr_mask = xxx,
- },
+ /* Embedded PowerPC */
+#if defined (TODO)
+ /* PowerPC 401 */
+ {
+ .name = "401",
+ .pvr = CPU_PPC_401,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_401,
+ .flags = PPC_FLAGS_401,
+ .msr_mask = xxx,
+ },
#endif
#if defined (TODO)
- /* IOP480 (401 microcontroler) */
- {
- .name = "iop480",
- .pvr = CPU_PPC_IOP480,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_401,
- .flags = PPC_FLAGS_401,
- .msr_mask = xxx,
- },
+ /* IOP480 (401 microcontroler) */
+ {
+ .name = "iop480",
+ .pvr = CPU_PPC_IOP480,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_401,
+ .flags = PPC_FLAGS_401,
+ .msr_mask = xxx,
+ },
#endif
#if defined (TODO)
- /* PPC 403 GA */
- {
- .name = "403ga",
- .pvr = CPU_PPC_403GA,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
+ /* IBM Processor for Network Resources */
+ {
+ .name = "Cobra",
+ .pvr = CPU_PPC_COBRA,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_401,
+ .flags = PPC_FLAGS_401,
+ .msr_mask = xxx,
+ },
#endif
#if defined (TODO)
- /* PPC 403 GB */
- {
- .name = "403gb",
- .pvr = CPU_PPC_403GB,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
+ /* Generic PowerPC 403 */
+ {
+ .name = "403",
+ .pvr = CPU_PPC_403,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23D,
+ },
#endif
#if defined (TODO)
- /* PPC 403 GC */
- {
- .name = "403gc",
- .pvr = CPU_PPC_403GC,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
+ /* PowerPC 403 GA */
+ {
+ .name = "403ga",
+ .pvr = CPU_PPC_403GA,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23D,
+ },
#endif
#if defined (TODO)
- /* PPC 403 GCX */
- {
- .name = "403gcx",
- .pvr = CPU_PPC_403GCX,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
+ /* PowerPC 403 GB */
+ {
+ .name = "403gb",
+ .pvr = CPU_PPC_403GB,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23D,
+ },
#endif
#if defined (TODO)
- /* PPC 405 CR */
- {
- .name = "405cr",
- .pvr = CPU_PPC_405,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 403 GC */
+ {
+ .name = "403gc",
+ .pvr = CPU_PPC_403GC,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23D,
+ },
#endif
#if defined (TODO)
- /* PPC 405 GP */
- {
- .name = "405gp",
- .pvr = CPU_PPC_405,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 403 GCX */
+ {
+ .name = "403gcx",
+ .pvr = CPU_PPC_403GCX,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23D,
+ },
#endif
#if defined (TODO)
- /* PPC 405 EP */
- {
- .name = "405ep",
- .pvr = CPU_PPC_405EP,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* Generic PowerPC 405 */
+ {
+ .name = "405",
+ .pvr = CPU_PPC_405,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 405 GPR */
- {
- .name = "405gpr",
- .pvr = CPU_PPC_405GPR,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 CR */
+ {
+ .name = "405cr",
+ .pvr = CPU_PPC_405,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 405 D2 */
- {
- .name = "405d2",
- .pvr = CPU_PPC_405D2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 GP */
+ {
+ .name = "405gp",
+ .pvr = CPU_PPC_405,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 405 D4 */
- {
- .name = "405d4",
- .pvr = CPU_PPC_405D4,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 EP */
+ {
+ .name = "405ep",
+ .pvr = CPU_PPC_405EP,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* Npe405 H */
- {
- .name = "Npe405H",
- .pvr = CPU_PPC_NPE405H,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 GPR */
+ {
+ .name = "405gpr",
+ .pvr = CPU_PPC_405GPR,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* Npe405 L */
- {
- .name = "Npe405L",
- .pvr = CPU_PPC_NPE405L,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 D2 */
+ {
+ .name = "405d2",
+ .pvr = CPU_PPC_405D2,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* STB03xx */
- {
- .name = "STB03",
- .pvr = CPU_PPC_STB03,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* PowerPC 405 D4 */
+ {
+ .name = "405d4",
+ .pvr = CPU_PPC_405D4,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* STB04xx */
- {
- .name = "STB04",
- .pvr = CPU_PPC_STB04,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* Npe405 H */
+ {
+ .name = "Npe405H",
+ .pvr = CPU_PPC_NPE405H,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* STB25xx */
- {
- .name = "STB25",
- .pvr = CPU_PPC_STB25,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
+ /* Npe405 L */
+ {
+ .name = "Npe405L",
+ .pvr = CPU_PPC_NPE405L,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 440 EP */
- {
- .name = "440ep",
- .pvr = CPU_PPC_440EP,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_440,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
+ /* STB010000 */
+ {
+ .name = "STB01000",
+ .pvr = CPU_PPC_STB01000,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 440 GP */
- {
- .name = "440gp",
- .pvr = CPU_PPC_440GP,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_440,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
+ /* STB01010 */
+ {
+ .name = "STB01010",
+ .pvr = CPU_PPC_STB01010,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 440 GX */
- {
- .name = "440gx",
- .pvr = CPU_PPC_440GX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
+ /* STB0210 */
+ {
+ .name = "STB0210",
+ .pvr = CPU_PPC_STB0210,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
-
- /* 32 bits "classic" powerpc */
#if defined (TODO)
- /* PPC 601 */
- {
- .name = "601",
- .pvr = CPU_PPC_601,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_601,
- .flags = PPC_FLAGS_601,
- .msr_mask = 0x000000000000FD70,
- },
+ /* STB03xx */
+ {
+ .name = "STB03",
+ .pvr = CPU_PPC_STB03,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 602 */
- {
- .name = "602",
- .pvr = CPU_PPC_602,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_602,
- .flags = PPC_FLAGS_602,
- .msr_mask = 0x0000000000C7FF73,
- },
+ /* STB043x */
+ {
+ .name = "STB043",
+ .pvr = CPU_PPC_STB043,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 603 */
- {
- .name = "603",
- .pvr = CPU_PPC_603,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
+ /* STB045x */
+ {
+ .name = "STB045",
+ .pvr = CPU_PPC_STB045,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 603e */
- {
- .name = "603e",
- .pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
- {
- .name = "Stretch",
- .pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
+ /* STB25xx */
+ {
+ .name = "STB25",
+ .pvr = CPU_PPC_STB25,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* PPC 603ev */
- {
- .name = "603ev",
- .pvr = CPU_PPC_603EV,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
+ /* STB130 */
+ {
+ .name = "STB130",
+ .pvr = CPU_PPC_STB130,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
+ /* Xilinx PowerPC 405 cores */
#if defined (TODO)
- /* PPC 603r */
- {
- .name = "603r",
- .pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
- {
- .name = "Goldeneye",
- .pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
+ {
+ .name = "x2vp4",
+ .pvr = CPU_PPC_X2VP4,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
+ {
+ .name = "x2vp7",
+ .pvr = CPU_PPC_X2VP7,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
+ {
+ .name = "x2vp20",
+ .pvr = CPU_PPC_X2VP20,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
+ {
+ .name = "x2vp50",
+ .pvr = CPU_PPC_X2VP50,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30,
+ },
#endif
#if defined (TODO)
- /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
- {
- .name = "G2",
- .pvr = CPU_PPC_G2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_G2,
- .flags = PPC_FLAGS_G2,
- .msr_mask = 0x000000000006FFF2,
- },
- { /* Same as G2, with LE mode support */
- .name = "G2le",
- .pvr = CPU_PPC_G2LE,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_G2,
- .flags = PPC_FLAGS_G2,
- .msr_mask = 0x000000000007FFF3,
- },
-#endif
- /* PPC 604 */
- {
- .name = "604",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* PPC 604e */
- {
- .name = "604e",
- .pvr = CPU_PPC_604E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* PPC 604r */
- {
- .name = "604r",
- .pvr = CPU_PPC_604R,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* generic G3 */
- {
- .name = "G3",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC740 (G3) */
- {
- .name = "740",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Arthur",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
+ /* PowerPC 440 EP */
+ {
+ .name = "440ep",
+ .pvr = CPU_PPC_440EP,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_440,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* MPC745 (G3) */
- {
- .name = "745",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Goldfinger",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* MPC750 (G3) */
- {
- .name = "750",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC755 (G3) */
- {
- .name = "755",
- .pvr = CPU_PPC_755,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
+ /* PowerPC 440 GR */
+ {
+ .name = "440gr",
+ .pvr = CPU_PPC_440GR,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_440,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* MPC740P (G3) */
- {
- .name = "740p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Conan/Doyle",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
+ /* PowerPC 440 GP */
+ {
+ .name = "440gp",
+ .pvr = CPU_PPC_440GP,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_440,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* MPC745P (G3) */
- {
- .name = "745p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* MPC750P (G3) */
- {
- .name = "750p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC755P (G3) */
- {
- .name = "755p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* IBM 750CXe (G3 embedded) */
- {
- .name = "750cxe",
- .pvr = CPU_PPC_750CXE,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- /* IBM 750FX (G3 embedded) */
- {
- .name = "750fx",
- .pvr = CPU_PPC_750FX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- /* IBM 750GX (G3 embedded) */
- {
- .name = "750gx",
- .pvr = CPU_PPC_750GX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* generic G4 */
- {
- .name = "G4",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 GX */
+ {
+ .name = "440gx",
+ .pvr = CPU_PPC_440GX,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* PPC 7400 (G4) */
- {
- .name = "7400",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Max",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 GXc */
+ {
+ .name = "440gxc",
+ .pvr = CPU_PPC_440GXC,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* PPC 7410 (G4) */
- {
- .name = "7410",
- .pvr = CPU_PPC_7410,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Nitro",
- .pvr = CPU_PPC_7410,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
- /* XXX: 7441 */
- /* XXX: 7445 */
- /* XXX: 7447 */
- /* XXX: 7447A */
-#if defined (TODO)
- /* PPC 7450 (G4) */
- {
- .name = "7450",
- .pvr = CPU_PPC_7450,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Vger",
- .pvr = CPU_PPC_7450,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 GXf */
+ {
+ .name = "440gxf",
+ .pvr = CPU_PPC_440GXF,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
- /* XXX: 7451 */
#if defined (TODO)
- /* PPC 7455 (G4) */
- {
- .name = "7455",
- .pvr = CPU_PPC_7455,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 6",
- .pvr = CPU_PPC_7455,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 SP */
+ {
+ .name = "440sp",
+ .pvr = CPU_PPC_440SP,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* PPC 7457 (G4) */
- {
- .name = "7457",
- .pvr = CPU_PPC_7457,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 7",
- .pvr = CPU_PPC_7457,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 SP2 */
+ {
+ .name = "440sp2",
+ .pvr = CPU_PPC_440SP2,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
#if defined (TODO)
- /* PPC 7457A (G4) */
- {
- .name = "7457A",
- .pvr = CPU_PPC_7457A,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 7 PM",
- .pvr = CPU_PPC_7457A,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
+ /* PowerPC 440 SPE */
+ {
+ .name = "440spe",
+ .pvr = CPU_PPC_440SPE,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630,
+ },
#endif
- /* 64 bits PPC */
+ /* Fake generic BookE PowerPC */
+ {
+ .name = "BookE",
+ .pvr = CPU_PPC_e500,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_BOOKE,
+ .flags = PPC_FLAGS_BOOKE,
+ .msr_mask = 0x000000000006D630,
+ },
+ /* PowerPC 460 cores - TODO */
+ /* PowerPC MPC 5xx cores - TODO */
+ /* PowerPC MPC 8xx cores - TODO */
+ /* PowerPC MPC 8xxx cores - TODO */
+ /* e200 cores - TODO */
+ /* e500 cores - TODO */
+ /* e600 cores - TODO */
+
+ /* 32 bits "classic" PowerPC */
#if defined (TODO)
- /* PPC 620 */
- {
- .name = "620",
- .pvr = CPU_PPC_620,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_620,
- .flags = PPC_FLAGS_620,
- .msr_mask = 0x800000000005FF73,
- },
+ /* PowerPC 601 */
+ {
+ .name = "601",
+ .pvr = CPU_PPC_601,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_601,
+ .flags = PPC_FLAGS_601,
+ .msr_mask = 0x000000000000FD70,
+ },
#endif
#if defined (TODO)
- /* PPC 630 (POWER3) */
- {
- .name = "630",
- .pvr = CPU_PPC_630,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_630,
- .flags = PPC_FLAGS_630,
- .msr_mask = xxx,
- }
- {
- .name = "POWER3",
- .pvr = CPU_PPC_630,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_630,
- .flags = PPC_FLAGS_630,
- .msr_mask = xxx,
- }
+ /* PowerPC 602 */
+ {
+ .name = "602",
+ .pvr = CPU_PPC_602,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_602,
+ .flags = PPC_FLAGS_602,
+ .msr_mask = 0x0000000000C7FF73,
+ },
#endif
+ /* PowerPC 603 */
+ {
+ .name = "603",
+ .pvr = CPU_PPC_603,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603e */
+ {
+ .name = "603e",
+ .pvr = CPU_PPC_603E,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ {
+ .name = "Stretch",
+ .pvr = CPU_PPC_603E,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603p */
+ {
+ .name = "603p",
+ .pvr = CPU_PPC_603P,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603e7 */
+ {
+ .name = "603e7",
+ .pvr = CPU_PPC_603E7,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603e7v */
+ {
+ .name = "603e7v",
+ .pvr = CPU_PPC_603E7v,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603e7v2 */
+ {
+ .name = "603e7v2",
+ .pvr = CPU_PPC_603E7v2,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ /* PowerPC 603r */
+ {
+ .name = "603r",
+ .pvr = CPU_PPC_603R,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
+ {
+ .name = "Goldeneye",
+ .pvr = CPU_PPC_603R,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73,
+ },
#if defined (TODO)
- /* PPC 631 (Power 3+)*/
- {
- .name = "631",
- .pvr = CPU_PPC_631,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_631,
- .flags = PPC_FLAGS_631,
- .msr_mask = xxx,
- },
- {
- .name = "POWER3+",
- .pvr = CPU_PPC_631,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_631,
- .flags = PPC_FLAGS_631,
- .msr_mask = xxx,
- },
+ /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
+ {
+ .name = "G2",
+ .pvr = CPU_PPC_G2,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2,
+ },
+ {
+ .name = "G2h4",
+ .pvr = CPU_PPC_G2H4,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2,
+ },
+ {
+ .name = "G2gp",
+ .pvr = CPU_PPC_G2gp,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2,
+ },
+ {
+ .name = "G2ls",
+ .pvr = CPU_PPC_G2ls,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2,
+ },
+ { /* Same as G2, with LE mode support */
+ .name = "G2le",
+ .pvr = CPU_PPC_G2LE,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000007FFF3,
+ },
+ {
+ .name = "G2legp",
+ .pvr = CPU_PPC_G2LEgp,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000007FFF3,
+ },
+ {
+ .name = "G2lels",
+ .pvr = CPU_PPC_G2LEls,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000007FFF3,
+ },
#endif
+ /* PowerPC 604 */
+ {
+ .name = "604",
+ .pvr = CPU_PPC_604,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_604,
+ .flags = PPC_FLAGS_604,
+ .msr_mask = 0x000000000005FF77,
+ },
+ /* PowerPC 604e */
+ {
+ .name = "604e",
+ .pvr = CPU_PPC_604E,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_604,
+ .flags = PPC_FLAGS_604,
+ .msr_mask = 0x000000000005FF77,
+ },
+ /* PowerPC 604r */
+ {
+ .name = "604r",
+ .pvr = CPU_PPC_604R,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_604,
+ .flags = PPC_FLAGS_604,
+ .msr_mask = 0x000000000005FF77,
+ },
+ /* generic G3 */
+ {
+ .name = "G3",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
+ /* MPC740 (G3) */
+ {
+ .name = "740",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
+ {
+ .name = "Arthur",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
#if defined (TODO)
- /* POWER4 */
- {
- .name = "POWER4",
- .pvr = CPU_PPC_POWER4,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER4,
- .flags = PPC_FLAGS_POWER4,
- .msr_mask = xxx,
- },
+ /* MPC745 (G3) */
+ {
+ .name = "745",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFF000,
+ .insns_flags = PPC_INSNS_7x5,
+ .flags = PPC_FLAGS_7x5,
+ .msr_mask = 0x000000000007FF77,
+ },
+ {
+ .name = "Goldfinger",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFF000,
+ .insns_flags = PPC_INSNS_7x5,
+ .flags = PPC_FLAGS_7x5,
+ .msr_mask = 0x000000000007FF77,
+ },
#endif
+ /* MPC750 (G3) */
+ {
+ .name = "750",
+ .pvr = CPU_PPC_74x,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
#if defined (TODO)
- /* POWER4p */
- {
- .name = "POWER4+",
- .pvr = CPU_PPC_POWER4P,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER4,
- .flags = PPC_FLAGS_POWER4,
- .msr_mask = xxx,
- },
+ /* MPC755 (G3) */
+ {
+ .name = "755",
+ .pvr = CPU_PPC_755,
+ .pvr_mask = 0xFFFFF000,
+ .insns_flags = PPC_INSNS_7x5,
+ .flags = PPC_FLAGS_7x5,
+ .msr_mask = 0x000000000007FF77,
+ },
#endif
+ /* MPC740P (G3) */
+ {
+ .name = "740p",
+ .pvr = CPU_PPC_74xP,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
+ {
+ .name = "Conan/Doyle",
+ .pvr = CPU_PPC_74xP,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
#if defined (TODO)
- /* POWER5 */
- {
- .name = "POWER5",
- .pvr = CPU_PPC_POWER5,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER5,
- .flags = PPC_FLAGS_POWER5,
- .msr_mask = xxx,
- },
+ /* MPC745P (G3) */
+ {
+ .name = "745p",
+ .pvr = CPU_PPC_74xP,
+ .pvr_mask = 0xFFFFF000,
+ .insns_flags = PPC_INSNS_7x5,
+ .flags = PPC_FLAGS_7x5,
+ .msr_mask = 0x000000000007FF77,
+ },
#endif
+ /* MPC750P (G3) */
+ {
+ .name = "750p",
+ .pvr = CPU_PPC_74xP,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
#if defined (TODO)
- /* POWER5+ */
- {
- .name = "POWER5+",
- .pvr = CPU_PPC_POWER5P,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER5,
- .flags = PPC_FLAGS_POWER5,
- .msr_mask = xxx,
- },
+ /* MPC755P (G3) */
+ {
+ .name = "755p",
+ .pvr = CPU_PPC_74xP,
+ .pvr_mask = 0xFFFFF000,
+ .insns_flags = PPC_INSNS_7x5,
+ .flags = PPC_FLAGS_7x5,
+ .msr_mask = 0x000000000007FF77,
+ },
#endif
+ /* IBM 750CXe (G3 embedded) */
+ {
+ .name = "750cxe",
+ .pvr = CPU_PPC_750CXE,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
+ /* IBM 750FX (G3 embedded) */
+ {
+ .name = "750fx",
+ .pvr = CPU_PPC_750FX,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
+ /* IBM 750GX (G3 embedded) */
+ {
+ .name = "750gx",
+ .pvr = CPU_PPC_750GX,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_7x0,
+ .flags = PPC_FLAGS_7x0,
+ .msr_mask = 0x000000000007FF77,
+ },
#if defined (TODO)
- /* PPC 970 */
- {
- .name = "970",
- .pvr = CPU_PPC_970,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_970,
- .flags = PPC_FLAGS_970,
- .msr_mask = 0x900000000204FF36,
- },
+ /* generic G4 */
+ {
+ .name = "G4",
+ .pvr = CPU_PPC_7400,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
#if defined (TODO)
- /* PPC 970FX (G5) */
- {
- .name = "970fx",
- .pvr = CPU_PPC_970FX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_970FX,
- .flags = PPC_FLAGS_970FX,
- .msr_mask = 0x800000000204FF36,
- },
-#endif
-#if defined (TODO)
- /* RS64 (Apache/A35) */
- /* This one seems to support the whole POWER2 instruction set
- * and the PowerPC 64 one.
- */
- {
- .name = "RS64",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "Apache",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "A35",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
+ /* PowerPC 7400 (G4) */
+ {
+ .name = "7400",
+ .pvr = CPU_PPC_7400,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Max",
+ .pvr = CPU_PPC_7400,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
#if defined (TODO)
- /* RS64-II (NorthStar/A50) */
- {
- .name = "RS64-II",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "NortStar",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "A50",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
+ /* PowerPC 7410 (G4) */
+ {
+ .name = "7410",
+ .pvr = CPU_PPC_7410,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Nitro",
+ .pvr = CPU_PPC_7410,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
+ /* XXX: 7441 */
+ /* XXX: 7445 */
+ /* XXX: 7447 */
+ /* XXX: 7447A */
#if defined (TODO)
- /* RS64-III (Pulsar) */
- {
- .name = "RS64-III",
- .pvr = CPU_PPC_RS64III,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "Pulsar",
- .pvr = CPU_PPC_RS64III,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
+ /* PowerPC 7450 (G4) */
+ {
+ .name = "7450",
+ .pvr = CPU_PPC_7450,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Vger",
+ .pvr = CPU_PPC_7450,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
+ /* XXX: 7451 */
#if defined (TODO)
- /* RS64-IV (IceStar/IStar/SStar) */
- {
- .name = "RS64-IV",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "IceStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "IStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "SStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
+ /* PowerPC 7455 (G4) */
+ {
+ .name = "7455",
+ .pvr = CPU_PPC_7455,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Apollo 6",
+ .pvr = CPU_PPC_7455,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
- /* POWER */
#if defined (TODO)
- /* Original POWER */
- {
- .name = "POWER",
- .pvr = CPU_POWER,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER,
- .flags = PPC_FLAGS_POWER,
- .msr_mask = xxx,
- },
+ /* PowerPC 7457 (G4) */
+ {
+ .name = "7457",
+ .pvr = CPU_PPC_7457,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Apollo 7",
+ .pvr = CPU_PPC_7457,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
#if defined (TODO)
- /* POWER2 */
- {
- .name = "POWER2",
- .pvr = CPU_POWER2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER,
- .flags = PPC_FLAGS_POWER,
- .msr_mask = xxx,
- },
+ /* PowerPC 7457A (G4) */
+ {
+ .name = "7457A",
+ .pvr = CPU_PPC_7457A,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
+ {
+ .name = "Apollo 7 PM",
+ .pvr = CPU_PPC_7457A,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_74xx,
+ .flags = PPC_FLAGS_74xx,
+ .msr_mask = 0x000000000205FF77,
+ },
#endif
- /* Generic PowerPCs */
+ /* 64 bits PowerPC */
#if defined (TODO)
- {
- .name = "ppc64",
- .pvr = CPU_PPC_970,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC64,
- .flags = PPC_FLAGS_PPC64,
- .msr_mask = 0xA00000000204FF36,
- },
+ /* PowerPC 620 */
+ {
+ .name = "620",
+ .pvr = CPU_PPC_620,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_620,
+ .flags = PPC_FLAGS_620,
+ .msr_mask = 0x800000000005FF73,
+ },
#endif
- {
- .name = "ppc32",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC32,
- .flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
- },
- /* Fallback */
- {
- .name = "ppc",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC32,
- .flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
- },
-};
+#if defined (TODO)
+ /* PowerPC 630 (POWER3) */
+ {
+ .name = "630",
+ .pvr = CPU_PPC_630,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_630,
+ .flags = PPC_FLAGS_630,
+ .msr_mask = xxx,
+ }
+ {
+ .name = "POWER3",
+ .pvr = CPU_PPC_630,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_630,
+ .flags = PPC_FLAGS_630,
+ .msr_mask = xxx,
+ }
+#endif
+#if defined (TODO)
+ /* PowerPC 631 (Power 3+)*/
+ {
+ .name = "631",
+ .pvr = CPU_PPC_631,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_631,
+ .flags = PPC_FLAGS_631,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "POWER3+",
+ .pvr = CPU_PPC_631,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_631,
+ .flags = PPC_FLAGS_631,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* POWER4 */
+ {
+ .name = "POWER4",
+ .pvr = CPU_PPC_POWER4,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER4,
+ .flags = PPC_FLAGS_POWER4,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* POWER4p */
+ {
+ .name = "POWER4+",
+ .pvr = CPU_PPC_POWER4P,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER4,
+ .flags = PPC_FLAGS_POWER4,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* POWER5 */
+ {
+ .name = "POWER5",
+ .pvr = CPU_PPC_POWER5,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER5,
+ .flags = PPC_FLAGS_POWER5,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* POWER5+ */
+ {
+ .name = "POWER5+",
+ .pvr = CPU_PPC_POWER5P,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER5,
+ .flags = PPC_FLAGS_POWER5,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 970 */
+ {
+ .name = "970",
+ .pvr = CPU_PPC_970,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_970,
+ .flags = PPC_FLAGS_970,
+ .msr_mask = 0x900000000204FF36,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 970FX (G5) */
+ {
+ .name = "970fx",
+ .pvr = CPU_PPC_970FX,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_970FX,
+ .flags = PPC_FLAGS_970FX,
+ .msr_mask = 0x800000000204FF36,
+ },
+#endif
+#if defined (TODO)
+ /* RS64 (Apache/A35) */
+ /* This one seems to support the whole POWER2 instruction set
+ * and the PowerPC 64 one.
+ */
+ {
+ .name = "RS64",
+ .pvr = CPU_PPC_RS64,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "Apache",
+ .pvr = CPU_PPC_RS64,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "A35",
+ .pvr = CPU_PPC_RS64,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* RS64-II (NorthStar/A50) */
+ {
+ .name = "RS64-II",
+ .pvr = CPU_PPC_RS64II,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "NortStar",
+ .pvr = CPU_PPC_RS64II,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "A50",
+ .pvr = CPU_PPC_RS64II,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* RS64-III (Pulsar) */
+ {
+ .name = "RS64-III",
+ .pvr = CPU_PPC_RS64III,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "Pulsar",
+ .pvr = CPU_PPC_RS64III,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* RS64-IV (IceStar/IStar/SStar) */
+ {
+ .name = "RS64-IV",
+ .pvr = CPU_PPC_RS64IV,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "IceStar",
+ .pvr = CPU_PPC_RS64IV,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "IStar",
+ .pvr = CPU_PPC_RS64IV,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+ {
+ .name = "SStar",
+ .pvr = CPU_PPC_RS64IV,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_RS64,
+ .flags = PPC_FLAGS_RS64,
+ .msr_mask = xxx,
+ },
+#endif
+ /* POWER */
+#if defined (TODO)
+ /* Original POWER */
+ {
+ .name = "POWER",
+ .pvr = CPU_POWER,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER,
+ .flags = PPC_FLAGS_POWER,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* POWER2 */
+ {
+ .name = "POWER2",
+ .pvr = CPU_POWER2,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_POWER,
+ .flags = PPC_FLAGS_POWER,
+ .msr_mask = xxx,
+ },
+#endif
+ /* Generic PowerPCs */
+#if defined (TODO)
+ {
+ .name = "ppc64",
+ .pvr = CPU_PPC_970,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_PPC64,
+ .flags = PPC_FLAGS_PPC64,
+ .msr_mask = 0xA00000000204FF36,
+ },
+#endif
+ {
+ .name = "ppc32",
+ .pvr = CPU_PPC_604,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_PPC32,
+ .flags = PPC_FLAGS_PPC32,
+ .msr_mask = 0x000000000005FF77,
+ },
+ /* Fallback */
+ {
+ .name = "ppc",
+ .pvr = CPU_PPC_604,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_PPC32,
+ .flags = PPC_FLAGS_PPC32,
+ .msr_mask = 0x000000000005FF77,
+ },
+ };
int ppc_find_by_name (const unsigned char *name, ppc_def_t **def)
{
@@ -2058,7 +3730,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
int i;
for (i = 0; ; i++) {
- (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n",
+ (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n",
ppc_defs[i].name,
ppc_defs[i].pvr, ppc_defs[i].pvr_mask);
if (strcmp(ppc_defs[i].name, "ppc") == 0)