From 76a66253e5e48f1744f689041c1c21cedcaff630 Mon Sep 17 00:00:00 2001 From: j_mayer Date: Wed, 7 Mar 2007 08:32:30 +0000 Subject: 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 --- target-ppc/STATUS | 91 ++ target-ppc/cpu.h | 926 ++++++----- target-ppc/exec.h | 76 +- target-ppc/helper.c | 1089 ++++++++----- target-ppc/mfrom_table.c | 79 + target-ppc/mfrom_table_gen.c | 33 + target-ppc/op.c | 896 +++++++++-- target-ppc/op_helper.c | 696 +++++++- target-ppc/op_helper.h | 132 ++ target-ppc/op_helper_mem.h | 206 ++- target-ppc/op_mem.h | 142 +- target-ppc/op_template.h | 73 +- target-ppc/translate.c | 2224 ++++++++++++++++++++------ target-ppc/translate_init.c | 3634 ++++++++++++++++++++++++++++++------------ 14 files changed, 7651 insertions(+), 2646 deletions(-) create mode 100644 target-ppc/STATUS create mode 100644 target-ppc/mfrom_table.c create mode 100644 target-ppc/mfrom_table_gen.c create mode 100644 target-ppc/op_helper.h (limited to 'target-ppc') 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 +#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 +#include +#include + +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,22 +51,135 @@ 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) { do_raise_exception_err(exception, 0); } +/*****************************************************************************/ +/* 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 and bits */ -static inline uint32_t MASK (uint32_t start, uint32_t end) +static inline target_ulong MASK (uint32_t start, uint32_t end) { - uint32_t ret; + target_ulong ret; - ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1); - if (start > end) - return ~ret; +#if defined(TARGET_PPC64) + if (likely(start == 0)) { + ret = (uint64_t)(-1ULL) << (63 - end); + } else if (likely(end == 63)) { + ret = (uint64_t)(-1ULL) >> start; + } +#else + if (likely(start == 0)) { + ret = (uint32_t)(-1ULL) << (31 - end); + } else if (likely(end == 31)) { + ret = (uint32_t)(-1ULL) >> start; + } +#endif + else { + ret = (((target_ulong)(-1ULL)) >> (start)) ^ + (((target_ulong)(-1ULL) >> (end)) >> 1); + if (unlikely(start > end)) + return ~ret; + } return ret; } @@ -320,6 +336,7 @@ static inline uint32_t MASK (uint32_t start, uint32_t end) __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) )) #endif +#if defined(DO_PPC_STATISTICS) #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ OPCODES_SECTION opcode_t opc_##name = { \ .opc1 = op1, \ @@ -330,9 +347,25 @@ OPCODES_SECTION opcode_t opc_##name = { \ .inval = invl, \ .type = _typ, \ .handler = &gen_##name, \ + .oname = stringify(name), \ }, \ .oname = stringify(name), \ } +#else +#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \ +OPCODES_SECTION opcode_t opc_##name = { \ + .opc1 = op1, \ + .opc2 = op2, \ + .opc3 = op3, \ + .pad = { 0, }, \ + .handler = { \ + .inval = invl, \ + .type = _typ, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} +#endif #define GEN_OPCODE_MARK(name) \ OPCODES_SECTION opcode_t opc_##name = { \ @@ -370,9 +403,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \ @@ -381,9 +414,9 @@ GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \ @@ -391,18 +424,18 @@ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \ GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rA(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rD(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } /* Two operands arithmetic functions */ @@ -454,41 +487,51 @@ GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06); /* addi */ GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int32_t simm = SIMM(ctx->opcode); + target_long simm = SIMM(ctx->opcode); if (rA(ctx->opcode) == 0) { + /* li case */ gen_op_set_T0(simm); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addi(simm); + if (likely(simm != 0)) + gen_op_addi(simm); } gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic */ GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + target_long simm = SIMM(ctx->opcode); + gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addic(SIMM(ctx->opcode)); + if (likely(simm != 0)) + gen_op_addic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); } /* addic. */ GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { + target_long simm = SIMM(ctx->opcode); + gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addic(SIMM(ctx->opcode)); - gen_op_set_Rc0(); + if (likely(simm != 0)) + gen_op_addic(SIMM(ctx->opcode)); gen_op_store_T0_gpr(rD(ctx->opcode)); + gen_set_Rc0(ctx); } /* addis */ GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int32_t simm = SIMM(ctx->opcode); + target_long simm = SIMM(ctx->opcode); if (rA(ctx->opcode) == 0) { + /* lis case */ gen_op_set_T0(simm << 16); } else { gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_addi(simm << 16); + if (likely(simm != 0)) + gen_op_addi(simm << 16); } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -543,9 +586,9 @@ GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_load_gpr_T1(rB(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } #define GEN_LOGICAL2(name, opc) \ __GEN_LOGICAL2(name, 0x1C, opc) @@ -555,9 +598,9 @@ GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \ { \ gen_op_load_gpr_T0(rS(ctx->opcode)); \ gen_op_##name(); \ - if (Rc(ctx->opcode) != 0) \ - gen_op_set_Rc0(); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ + if (unlikely(Rc(ctx->opcode) != 0)) \ + gen_set_Rc0(ctx); \ } /* and & and. */ @@ -568,17 +611,17 @@ GEN_LOGICAL2(andc, 0x01); GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_(UIMM(ctx->opcode)); - gen_op_set_Rc0(); + gen_op_andi_T0(UIMM(ctx->opcode)); gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_set_Rc0(ctx); } /* andis. */ GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_andi_(UIMM(ctx->opcode) << 16); - gen_op_set_Rc0(); + gen_op_andi_T0(UIMM(ctx->opcode) << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_set_Rc0(ctx); } /* cntlzw */ @@ -597,15 +640,25 @@ GEN_LOGICAL2(nor, 0x03); /* or & or. */ GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER) { - gen_op_load_gpr_T0(rS(ctx->opcode)); - /* Optimisation for mr case */ - if (rS(ctx->opcode) != rB(ctx->opcode)) { - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_or(); + int rs, ra, rb; + + rs = rS(ctx->opcode); + ra = rA(ctx->opcode); + rb = rB(ctx->opcode); + /* Optimisation for mr. ri case */ + if (rs != ra || rs != rb) { + gen_op_load_gpr_T0(rs); + if (rs != rb) { + gen_op_load_gpr_T1(rb); + gen_op_or(); + } + gen_op_store_T0_gpr(ra); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); + } else if (unlikely(Rc(ctx->opcode) != 0)) { + gen_op_load_gpr_T0(rs); + gen_set_Rc0(ctx); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); - gen_op_store_T0_gpr(rA(ctx->opcode)); } /* orc & orc. */ @@ -619,67 +672,68 @@ GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER) gen_op_load_gpr_T1(rB(ctx->opcode)); gen_op_xor(); } else { - gen_op_set_T0(0); + gen_op_reset_T0(); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* ori */ GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ + /* XXX: should handle special NOPs for POWER series */ return; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (likely(uimm != 0)) gen_op_ori(uimm); - gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); } /* oris */ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; - } - gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + if (likely(uimm != 0)) gen_op_ori(uimm << 16); - gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_T0_gpr(rA(ctx->opcode)); } /* xori */ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) - gen_op_xori(uimm); + if (likely(uimm != 0)) + gen_op_xori(uimm); gen_op_store_T0_gpr(rA(ctx->opcode)); } /* xoris */ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t uimm = UIMM(ctx->opcode); + target_ulong uimm = UIMM(ctx->opcode); if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) { /* NOP */ return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - if (uimm != 0) - gen_op_xori(uimm << 16); + if (likely(uimm != 0)) + gen_op_xori(uimm << 16); gen_op_store_T0_gpr(rA(ctx->opcode)); } @@ -687,16 +741,42 @@ GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) /* rlwimi & rlwimi. */ GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - uint32_t mb, me; + target_ulong mask; + uint32_t mb, me, sh; + int n; mb = MB(ctx->opcode); me = ME(ctx->opcode); + sh = SH(ctx->opcode); + n = me + 1 - mb; + if (likely(sh == 0)) { + if (likely(mb == 0 && me == 31)) { + gen_op_load_gpr_T0(rS(ctx->opcode)); + goto do_store; + } else if (likely(mb == 31 && me == 0)) { + gen_op_load_gpr_T0(rA(ctx->opcode)); + goto do_store; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + goto do_mask; + } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rA(ctx->opcode)); - gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me)); - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_rotli32_T0(SH(ctx->opcode)); + do_mask: +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + mask = MASK(mb, me); + gen_op_andi_T0(mask); + gen_op_andi_T1(~mask); + gen_op_or(); + do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* rlwinm & rlwinm. */ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -707,35 +787,34 @@ GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) mb = MB(ctx->opcode); me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); -#if 1 // TRY - if (sh == 0) { - gen_op_andi_(MASK(mb, me)); - goto store; - } -#endif - if (mb == 0) { - if (me == 31) { - gen_op_rotlwi(sh); - goto store; -#if 0 - } else if (me == (31 - sh)) { - gen_op_slwi(sh); - goto store; -#endif + if (likely(sh == 0)) { + goto do_mask; + } + if (likely(mb == 0)) { + if (likely(me == 31)) { + gen_op_rotli32_T0(sh); + goto do_store; + } else if (likely(me == (31 - sh))) { + gen_op_sli_T0(sh); + goto do_store; } - } else if (me == 31) { -#if 0 - if (sh == (32 - mb)) { - gen_op_srwi(mb); - goto store; + } else if (likely(me == 31)) { + if (likely(sh == (32 - mb))) { + gen_op_srli_T0(mb); + goto do_store; } -#endif } - gen_op_rlwinm(sh, MASK(mb, me)); -store: - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_rotli32_T0(sh); + do_mask: +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + gen_op_andi_T0(MASK(mb, me)); + do_store: gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* rlwnm & rlwnm. */ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) @@ -746,15 +825,17 @@ GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) me = ME(ctx->opcode); gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - if (mb == 0 && me == 31) { - gen_op_rotl(); - } else - { - gen_op_rlwnm(MASK(mb, me)); + gen_op_rotl32_T0_T1(); + if (unlikely(mb != 0 || me != 31)) { +#if defined(TARGET_PPC64) + mb += 32; + me += 32; +#endif + gen_op_andi_T0(MASK(mb, me)); } - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /*** Integer shift ***/ @@ -767,10 +848,10 @@ GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER) { gen_op_load_gpr_T0(rS(ctx->opcode)); if (SH(ctx->opcode) != 0) - gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); - if (Rc(ctx->opcode) != 0) - gen_op_set_Rc0(); + gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31)); gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); } /* srw & srw. */ __GEN_LOGICAL2(srw, 0x18, 0x10); @@ -779,7 +860,7 @@ __GEN_LOGICAL2(srw, 0x18, 0x10); #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -792,7 +873,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } @@ -803,7 +884,7 @@ _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1); #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -815,7 +896,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AB(name, op2, inval) \ @@ -825,7 +906,7 @@ _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1); #define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -837,7 +918,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \ gen_op_frsp(); \ } \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_AC(name, op2, inval) \ @@ -847,7 +928,7 @@ _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1); #define GEN_FLOAT_B(name, op2, op3) \ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -855,14 +936,14 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } #define GEN_FLOAT_BS(name, op1, op2) \ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ @@ -870,7 +951,7 @@ GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \ gen_op_load_fpr_FT0(rB(ctx->opcode)); \ gen_op_f##name(); \ gen_op_store_FT0_fpr(rD(ctx->opcode)); \ - if (Rc(ctx->opcode)) \ + if (unlikely(Rc(ctx->opcode) != 0)) \ gen_op_set_Rc1(); \ } @@ -881,13 +962,13 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0); /* fmul - fmuls */ GEN_FLOAT_AC(mul, 0x19, 0x0000F800); -/* fres */ +/* fres */ /* XXX: not in 601 */ GEN_FLOAT_BS(res, 0x3B, 0x18); -/* frsqrte */ +/* frsqrte */ /* XXX: not in 601 */ GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A); -/* fsel */ +/* fsel */ /* XXX: not in 601 */ _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0); /* fsub - fsubs */ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); @@ -895,7 +976,7 @@ GEN_FLOAT_AB(sub, 0x14, 0x000007C0); /* fsqrt */ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -903,13 +984,13 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_fsqrt(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -918,7 +999,7 @@ GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT) gen_op_fsqrt(); gen_op_frsp(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -942,9 +1023,9 @@ GEN_FLOAT_B(rsp, 0x0C, 0x00); /*** Floating-Point compare ***/ /* fcmpo */ -GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) +GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -956,9 +1037,9 @@ GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) } /* fcmpu */ -GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT) +GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -976,14 +1057,14 @@ GEN_FLOAT_B(abs, 0x08, 0x08); /* fmr - fmr. */ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_reset_scrfx(); gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -996,7 +1077,7 @@ GEN_FLOAT_B(neg, 0x08, 0x01); /* mcrfs */ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -1008,13 +1089,13 @@ GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT) /* mffs */ GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_load_fpscr(); gen_op_store_FT0_fpr(rD(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -1023,15 +1104,15 @@ GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT) { uint8_t crb; - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } crb = crbD(ctx->opcode) >> 2; gen_op_load_fpscr_T0(crb); - gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03))); + gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03))); gen_op_store_T0_fpscr(crb); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } @@ -1040,7 +1121,7 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) { uint8_t crb; - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } @@ -1048,35 +1129,70 @@ GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT) gen_op_load_fpscr_T0(crb); gen_op_ori(1 << (crbD(ctx->opcode) & 0x03)); gen_op_store_T0_fpscr(crb); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } /* mtfsf */ GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_load_fpr_FT0(rB(ctx->opcode)); gen_op_store_fpscr(FM(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } /* mtfsfi */ GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode)); - if (Rc(ctx->opcode)) + if (unlikely(Rc(ctx->opcode) != 0)) gen_op_set_Rc1(); } +/*** Addressing modes ***/ +/* Register indirect with immediate index : EA = (rA|0) + SIMM */ +static inline void gen_addr_imm_index (DisasContext *ctx) +{ + target_long simm = SIMM(ctx->opcode); + + if (rA(ctx->opcode) == 0) { + gen_op_set_T0(simm); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + if (likely(simm != 0)) + gen_op_addi(simm); + } +} + +static inline void gen_addr_reg_index (DisasContext *ctx) +{ + if (rA(ctx->opcode) == 0) { + gen_op_load_gpr_T0(rB(ctx->opcode)); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_add(); + } +} + +static inline void gen_addr_register (DisasContext *ctx) +{ + if (rA(ctx->opcode) == 0) { + gen_op_reset_T0(); + } else { + gen_op_load_gpr_T0(rA(ctx->opcode)); + } +} + /*** Integer load ***/ #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) @@ -1118,14 +1234,7 @@ static GenOpFunc *gen_op_st##width[] = { \ #define GEN_LD(width, opc) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } @@ -1133,15 +1242,12 @@ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_LDU(width, opc) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode))) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1150,14 +1256,12 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_LDUX(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0 || \ + rA(ctx->opcode) == rD(ctx->opcode))) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1166,13 +1270,7 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_LDX(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ gen_op_store_T1_gpr(rD(ctx->opcode)); \ } @@ -1197,14 +1295,7 @@ GEN_LDS(wz, 0x00); #define GEN_ST(width, opc) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1212,14 +1303,11 @@ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_STU(width, opc) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1228,13 +1316,11 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ #define GEN_STUX(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ @@ -1243,13 +1329,7 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ #define GEN_STX(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \ { \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ gen_op_load_gpr_T1(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1311,30 +1391,18 @@ static GenOpFunc1 *gen_op_stmw[] = { /* lmw */ GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(simm); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (simm != 0) - gen_op_addi(simm); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); op_ldstm(lmw, rD(ctx->opcode)); } /* stmw */ GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) { - int simm = SIMM(ctx->opcode); - - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(simm); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - if (simm != 0) - gen_op_addi(simm); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); op_ldstm(stmw, rS(ctx->opcode)); } @@ -1391,19 +1459,16 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) if (nb == 0) nb = 32; nr = nb / 4; - if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || - ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { + if (unlikely(((start + nr) > 32 && + start <= ra && (start + nr - 32) > ra) || + ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) { RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); return; } - if (ra == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(ra); - } - gen_op_set_T1(nb); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); + gen_op_update_nip(ctx->nip - 4); + gen_addr_register(ctx); + gen_op_set_T1(nb); op_ldsts(lswi, start); } @@ -1413,17 +1478,13 @@ GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER) int ra = rA(ctx->opcode); int rb = rB(ctx->opcode); + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); if (ra == 0) { - gen_op_load_gpr_T0(rb); ra = rb; - } else { - gen_op_load_gpr_T0(ra); - gen_op_load_gpr_T1(rb); - gen_op_add(); } gen_op_load_xer_bc(); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); op_ldstsx(lswx, rD(ctx->opcode), ra, rb); } @@ -1432,46 +1493,33 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER) { int nb = NB(ctx->opcode); - if (rA(ctx->opcode) == 0) { - gen_op_set_T0(0); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_register(ctx); if (nb == 0) nb = 32; gen_op_set_T1(nb); - /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); op_ldsts(stsw, rS(ctx->opcode)); } /* stswx */ GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER) { - int ra = rA(ctx->opcode); - - if (ra == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - ra = rB(ctx->opcode); - } else { - gen_op_load_gpr_T0(ra); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } - gen_op_load_xer_bc(); /* NIP cannot be restored if the memory exception comes from an helper */ - gen_op_update_nip((ctx)->nip - 4); + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_xer_bc(); op_ldsts(stsw, rS(ctx->opcode)); } /*** Memory synchronisation ***/ /* eieio */ -GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM) +GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO) { } /* isync */ -GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM) +GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM) { } @@ -1502,15 +1550,9 @@ static GenOpFunc *gen_op_stwcx[] = { #endif /* lwarx */ -GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) +GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_lwarx(); gen_op_store_T1_gpr(rD(ctx->opcode)); } @@ -1518,19 +1560,13 @@ GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES) /* stwcx. */ GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); gen_op_load_gpr_T1(rS(ctx->opcode)); op_stwcx(); } /* sync */ -GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) +GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC) { } @@ -1538,79 +1574,59 @@ GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM) #define GEN_LDF(width, opc) \ GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } #define GEN_LDUF(width, opc) \ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ + gen_addr_imm_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } #define GEN_LDUXF(width, opc) \ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0 || \ - rA(ctx->opcode) == rD(ctx->opcode)) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } #define GEN_LDXF(width, opc2, opc3) \ GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ + gen_addr_reg_index(ctx); \ op_ldst(l##width); \ - gen_op_store_FT1_fpr(rD(ctx->opcode)); \ + gen_op_store_FT0_fpr(rD(ctx->opcode)); \ } #define GEN_LDFS(width, op) \ @@ -1629,38 +1645,28 @@ GEN_LDFS(fs, 0x10); #define GEN_STF(width, opc) \ GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_set_T0(simm); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - } \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_imm_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ } #define GEN_STUF(width, opc) \ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ { \ - uint32_t simm = SIMM(ctx->opcode); \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - if (simm != 0) \ - gen_op_addi(simm); \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_imm_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } @@ -1668,18 +1674,16 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \ #define GEN_STUXF(width, opc) \ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ + if (unlikely(rA(ctx->opcode) == 0)) { \ RET_INVAL(ctx); \ return; \ } \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_reg_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ gen_op_store_T0_gpr(rA(ctx->opcode)); \ } @@ -1687,18 +1691,12 @@ GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \ #define GEN_STXF(width, opc2, opc3) \ GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \ { \ - if (!ctx->fpu_enabled) { \ + if (unlikely(!ctx->fpu_enabled)) { \ RET_EXCP(ctx, EXCP_NO_FP, 0); \ return; \ } \ - if (rA(ctx->opcode) == 0) { \ - gen_op_load_gpr_T0(rB(ctx->opcode)); \ - } else { \ - gen_op_load_gpr_T0(rA(ctx->opcode)); \ - gen_op_load_gpr_T1(rB(ctx->opcode)); \ - gen_op_add(); \ - } \ - gen_op_load_fpr_FT1(rS(ctx->opcode)); \ + gen_addr_reg_index(ctx); \ + gen_op_load_fpr_FT0(rS(ctx->opcode)); \ op_ldst(st##width); \ } @@ -1718,10 +1716,12 @@ GEN_STFS(fs, 0x14); /* stfiwx */ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) { - if (!ctx->fpu_enabled) { + if (unlikely(!ctx->fpu_enabled)) { RET_EXCP(ctx, EXCP_NO_FP, 0); return; } + gen_addr_reg_index(ctx); + /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */ RET_INVAL(ctx); } @@ -1745,9 +1745,9 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) } else { gen_op_set_T1(dest); gen_op_b_T1(); + gen_op_reset_T0(); if (ctx->singlestep_enabled) gen_op_debug(); - gen_op_set_T0(0); gen_op_exit_tb(); } } @@ -1755,12 +1755,15 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) /* b ba bl bla */ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { - uint32_t li, target; + target_ulong li, target; /* sign extend LI */ - li = ((int32_t)LI(ctx->opcode) << 6) >> 6; - - if (AA(ctx->opcode) == 0) +#if defined(TARGET_PPC64) + li = ((target_long)LI(ctx->opcode) << 38) >> 38; +#else + li = ((target_long)LI(ctx->opcode) << 6) >> 6; +#endif + if (likely(AA(ctx->opcode) == 0)) target = ctx->nip + li - 4; else target = li; @@ -1777,18 +1780,18 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) static inline void gen_bcond(DisasContext *ctx, int type) { - uint32_t target = 0; + target_ulong target = 0; + target_ulong li; uint32_t bo = BO(ctx->opcode); uint32_t bi = BI(ctx->opcode); uint32_t mask; - uint32_t li; if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { case BCOND_IM: - li = (int32_t)((int16_t)(BD(ctx->opcode))); - if (AA(ctx->opcode) == 0) { + li = (target_long)((int16_t)(BD(ctx->opcode))); + if (likely(AA(ctx->opcode) == 0)) { target = ctx->nip + li - 4; } else { target = li; @@ -1821,6 +1824,7 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_goto_tb(ctx, 0, target); } else { gen_op_b_T1(); + gen_op_reset_T0(); } goto no_test; } @@ -1865,8 +1869,12 @@ static inline void gen_bcond(DisasContext *ctx, int type) gen_goto_tb(ctx, 1, ctx->nip); } else { gen_op_btest_T1(ctx->nip); + gen_op_reset_T0(); } no_test: + if (ctx->singlestep_enabled) + gen_op_debug(); + gen_op_exit_tb(); ctx->exception = EXCP_BRANCH; } @@ -1901,21 +1909,21 @@ GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \ } /* crand */ -GEN_CRLOGIC(and, 0x08) +GEN_CRLOGIC(and, 0x08); /* crandc */ -GEN_CRLOGIC(andc, 0x04) +GEN_CRLOGIC(andc, 0x04); /* creqv */ -GEN_CRLOGIC(eqv, 0x09) +GEN_CRLOGIC(eqv, 0x09); /* crnand */ -GEN_CRLOGIC(nand, 0x07) +GEN_CRLOGIC(nand, 0x07); /* crnor */ -GEN_CRLOGIC(nor, 0x01) +GEN_CRLOGIC(nor, 0x01); /* cror */ -GEN_CRLOGIC(or, 0x0E) +GEN_CRLOGIC(or, 0x0E); /* crorc */ -GEN_CRLOGIC(orc, 0x0D) +GEN_CRLOGIC(orc, 0x0D); /* crxor */ -GEN_CRLOGIC(xor, 0x06) +GEN_CRLOGIC(xor, 0x06); /* mcrf */ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) { @@ -1925,13 +1933,13 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) /*** System linkage ***/ /* rfi (supervisor only) */ -GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) +GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else /* Restore CPU state */ - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -1952,7 +1960,7 @@ GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) /*** Trap ***/ /* tw */ -GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) +GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); @@ -1965,39 +1973,11 @@ GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW) GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW) { gen_op_load_gpr_T0(rA(ctx->opcode)); -#if 0 - printf("%s: param=0x%04x T0=0x%04x\n", __func__, - SIMM(ctx->opcode), TO(ctx->opcode)); -#endif - gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode)); + gen_op_set_T1(SIMM(ctx->opcode)); + gen_op_tw(TO(ctx->opcode)); } /*** Processor control ***/ -static inline int check_spr_access (int spr, int rw, int supervisor) -{ - uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1)); - -#if 0 - if (spr != LR && spr != CTR) { - if (loglevel > 0) { - fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, - SPR_ENCODE(spr), supervisor, rw, rights, - (rights >> ((2 * supervisor) + rw)) & 1); - } else { - printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__, - SPR_ENCODE(spr), supervisor, rw, rights, - (rights >> ((2 * supervisor) + rw)) & 1); - } - } -#endif - if (rights == 0) - return -1; - rights = rights >> (2 * supervisor); - rights = rights >> rw; - - return rights & 1; -} - /* mcrxr */ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) { @@ -2007,9 +1987,22 @@ GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC) } /* mfcr */ -GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) +GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC) { - gen_op_load_cr(); +#if 0 // XXX: to be tested + uint32_t crm, crn; + + if (likely(ctx->opcode & 0x00100000)) { + crm = CRM(ctx->opcode); + if (likely((crm ^ (crm - 1)) == 0)) { + crn = ffs(crm); + gen_op_load_cro(7 - crn); + } + } else +#endif + { + gen_op_load_cr(); + } gen_op_store_T0_gpr(rD(ctx->opcode)); } @@ -2019,7 +2012,7 @@ GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } @@ -2051,8 +2044,8 @@ static inline void gen_op_mfspr (DisasContext *ctx) else #endif read_cb = ctx->spr_cb[sprn].uea_read; - if (read_cb != NULL) { - if (read_cb != SPR_NOACCESS) { + if (likely(read_cb != NULL)) { + if (likely(read_cb != SPR_NOACCESS)) { (*read_cb)(ctx, sprn); gen_op_store_T0_gpr(rD(ctx->opcode)); } else { @@ -2062,7 +2055,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) sprn, sprn); } printf("Trying to read priviledged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); + RET_PRIVREG(ctx); } } else { /* Not defined */ @@ -2078,7 +2071,7 @@ static inline void gen_op_mfspr (DisasContext *ctx) GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) { gen_op_mfspr(ctx); - } +} /* mftb */ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) @@ -2087,11 +2080,20 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB) } /* mtcrf */ -/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC) { + uint32_t crm, crn; + gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_cr(CRM(ctx->opcode)); + crm = CRM(ctx->opcode); + if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) { + crn = ffs(crm); + gen_op_srli_T0(crn * 4); + gen_op_andi_T0(0xF); + gen_op_store_cro(7 - crn); + } else { + gen_op_store_cr(crm); + } } /* mtmsr */ @@ -2100,7 +2102,7 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } @@ -2124,8 +2126,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) else #endif write_cb = ctx->spr_cb[sprn].uea_write; - if (write_cb != NULL) { - if (write_cb != SPR_NOACCESS) { + if (likely(write_cb != NULL)) { + if (likely(write_cb != SPR_NOACCESS)) { gen_op_load_gpr_T0(rS(ctx->opcode)); (*write_cb)(ctx, sprn); } else { @@ -2135,8 +2137,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) sprn, sprn); } printf("Trying to write priviledged spr %d %03x\n", sprn, sprn); - RET_PRIVREG(ctx); - } + RET_PRIVREG(ctx); + } } else { /* Not defined */ if (loglevel) { @@ -2156,13 +2158,7 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) /* dcbf */ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_ldst(lbz); } @@ -2172,18 +2168,13 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } - op_ldst(lbz); + gen_addr_reg_index(ctx); + /* XXX: specification says this should be treated as a store by the MMU */ + //op_ldst(lbz); op_ldst(stb); #endif } @@ -2191,31 +2182,35 @@ GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) /* dcdst */ GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + /* XXX: specification say this is treated as a load by the MMU */ + gen_addr_reg_index(ctx); op_ldst(lbz); } /* dcbt */ GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE) { + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* dcbtst */ GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE) { + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* dcbz */ +#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() #if defined(CONFIG_USER_ONLY) -#define op_dcbz() gen_op_dcbz_raw() +static GenOpFunc *gen_op_dcbz[] = { + &gen_op_dcbz_raw, + &gen_op_dcbz_raw, +}; #else -#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])() static GenOpFunc *gen_op_dcbz[] = { &gen_op_dcbz_user, &gen_op_dcbz_user, @@ -2226,13 +2221,7 @@ static GenOpFunc *gen_op_dcbz[] = { GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + gen_addr_reg_index(ctx); op_dcbz(); gen_op_check_reservation(); } @@ -2240,14 +2229,11 @@ GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE) /* icbi */ GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE) { - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { - gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); - } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); gen_op_icbi(); + RET_STOP(ctx); } /* Optional: */ @@ -2264,11 +2250,12 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } - gen_op_load_sr(SR(ctx->opcode)); + gen_op_set_T1(SR(ctx->opcode)); + gen_op_load_sr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -2279,12 +2266,13 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_load_srin(); + gen_op_srli_T1(28); + gen_op_load_sr(); gen_op_store_T0_gpr(rD(ctx->opcode)); #endif } @@ -2295,12 +2283,13 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); - gen_op_store_sr(SR(ctx->opcode)); + gen_op_set_T1(SR(ctx->opcode)); + gen_op_store_sr(); RET_STOP(ctx); #endif } @@ -2311,13 +2300,14 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) #if defined(CONFIG_USER_ONLY) RET_PRIVREG(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVREG(ctx); return; } gen_op_load_gpr_T0(rS(ctx->opcode)); gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_store_srin(); + gen_op_srli_T1(28); + gen_op_store_sr(); RET_STOP(ctx); #endif } @@ -2330,7 +2320,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { if (loglevel) fprintf(logfile, "%s: ! supervisor\n", __func__); RET_PRIVOPC(ctx); @@ -2342,12 +2332,12 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA) } /* tlbie */ -GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) +GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -2358,12 +2348,12 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) } /* tlbsync */ -GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) +GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC) { #if defined(CONFIG_USER_ONLY) RET_PRIVOPC(ctx); #else - if (!ctx->supervisor) { + if (unlikely(!ctx->supervisor)) { RET_PRIVOPC(ctx); return; } @@ -2406,30 +2396,1149 @@ static GenOpFunc *gen_op_ecowx[] = { GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN) { /* Should check EAR[E] & alignment ! */ - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { + gen_addr_reg_index(ctx); + op_eciwx(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* ecowx */ +GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) +{ + /* Should check EAR[E] & alignment ! */ + gen_addr_reg_index(ctx); + gen_op_load_gpr_T1(rS(ctx->opcode)); + op_ecowx(); +} + +/* PowerPC 601 specific instructions */ +/* abs - abs. */ +GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_abs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* abso - abso. */ +GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_abso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* clcs */ +GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */ +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_clcs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* div - div. */ +GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_div(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divo - divo. */ +GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divs - divs. */ +GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* divso - divso. */ +GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_divso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* doz - doz. */ +GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_doz(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* dozo - dozo. */ +GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_dozo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* dozi */ +GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_set_T1(SIMM(ctx->opcode)); + gen_op_POWER_doz(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +} + +/* As lscbx load from memory byte after byte, it's always endian safe */ +#define op_POWER_lscbx(start, ra, rb) \ +(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb) +#if defined(CONFIG_USER_ONLY) +static GenOpFunc3 *gen_op_POWER_lscbx[] = { + &gen_op_POWER_lscbx_raw, + &gen_op_POWER_lscbx_raw, +}; +#else +static GenOpFunc3 *gen_op_POWER_lscbx[] = { + &gen_op_POWER_lscbx_user, + &gen_op_POWER_lscbx_user, + &gen_op_POWER_lscbx_kernel, + &gen_op_POWER_lscbx_kernel, +}; +#endif + +/* lscbx - lscbx. */ +GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR) +{ + int ra = rA(ctx->opcode); + int rb = rB(ctx->opcode); + + gen_addr_reg_index(ctx); + if (ra == 0) { + ra = rb; + } + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_op_load_xer_bc(); + gen_op_load_xer_cmp(); + op_POWER_lscbx(rD(ctx->opcode), ra, rb); + gen_op_store_xer_bc(); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* maskg - maskg. */ +GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_maskg(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* maskir - maskir. */ +GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_maskir(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* mul - mul. */ +GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_mul(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* mulo - mulo. */ +GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_mulo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* nabs - nabs. */ +GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_nabs(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* nabso - nabso. */ +GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_POWER_nabso(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* rlmi - rlmi. */ +GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR) +{ + uint32_t mb, me; + + mb = MB(ctx->opcode); + me = ME(ctx->opcode); + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me)); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* rrib - rrib. */ +GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rA(ctx->opcode)); + gen_op_load_gpr_T2(rB(ctx->opcode)); + gen_op_POWER_rrib(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sle - sle. */ +GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sle(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sleq - sleq. */ +GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sleq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sliq - sliq. */ +GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sle(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* slliq - slliq. */ +GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sleq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sllq - sllq. */ +GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sllq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* slq - slq. */ +GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_slq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sraiq -sraiq. */ +GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_sraq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sraq - sraq. */ +GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sraq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sre - sre. */ +GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sre(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srea - srea. */ +GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srea(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sreq */ +GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_sreq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* sriq */ +GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_srq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srliq */ +GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_set_T1(SH(ctx->opcode)); + gen_op_POWER_srlq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srlq */ +GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srlq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* srq */ +GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_POWER_srq(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + if (unlikely(Rc(ctx->opcode) != 0)) + gen_set_Rc0(ctx); +} + +/* PowerPC 602 specific instructions */ +/* dsa */ +GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +/* esa */ +GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +/* mfrom */ +GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_602_mfrom(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* 602 - 603 - G2 TLB management */ +/* tlbld */ +GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_6xx_tlbld(); + RET_STOP(ctx); +#endif +} + +/* tlbli */ +GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rB(ctx->opcode)); + gen_op_6xx_tlbli(); + RET_STOP(ctx); +#endif +} + +/* POWER instructions not in PowerPC 601 */ +/* clf */ +GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER) +{ + /* Cache line flush: implemented as no-op */ +} + +/* cli */ +GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER) +{ + /* Cache line invalidate: priviledged and treated as no-op */ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } +#endif +} + +/* dclst */ +GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER) +{ + /* Data cache line store: treated as no-op */ +} + +GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + int ra = rA(ctx->opcode); + int rd = rD(ctx->opcode); + + gen_addr_reg_index(ctx); + gen_op_POWER_mfsri(); + gen_op_store_T0_gpr(rd); + if (ra != 0 && ra != rd) + gen_op_store_T1_gpr(ra); +#endif +} + +GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + gen_op_POWER_rac(); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_POWER_rfsvc(); + RET_CHG_FLOW(ctx); +#endif +} + +/* svc is not implemented for now */ + +/* POWER2 specific instructions */ +/* Quad manipulation (load/store two floats at a time) */ +#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])() +#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])() +#if defined(CONFIG_USER_ONLY) +static GenOpFunc *gen_op_POWER2_lfq[] = { + &gen_op_POWER2_lfq_le_raw, + &gen_op_POWER2_lfq_raw, +}; +static GenOpFunc *gen_op_POWER2_stfq[] = { + &gen_op_POWER2_stfq_le_raw, + &gen_op_POWER2_stfq_raw, +}; +#else +static GenOpFunc *gen_op_POWER2_lfq[] = { + &gen_op_POWER2_lfq_le_user, + &gen_op_POWER2_lfq_user, + &gen_op_POWER2_lfq_le_kernel, + &gen_op_POWER2_lfq_kernel, +}; +static GenOpFunc *gen_op_POWER2_stfq[] = { + &gen_op_POWER2_stfq_le_user, + &gen_op_POWER2_stfq_user, + &gen_op_POWER2_stfq_le_kernel, + &gen_op_POWER2_stfq_kernel, +}; +#endif + +/* lfq */ +GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); +} + +/* lfqu */ +GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* lfqux */ +GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* lfqx */ +GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + op_POWER2_lfq(); + gen_op_store_FT0_fpr(rD(ctx->opcode)); + gen_op_store_FT1_fpr(rD(ctx->opcode) + 1); +} + +/* stfq */ +GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); +} + +/* stfqu */ +GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_imm_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* stfqux */ +GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2) +{ + int ra = rA(ctx->opcode); + + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); + if (ra != 0) + gen_op_store_T0_gpr(ra); +} + +/* stfqx */ +GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2) +{ + /* NIP cannot be restored if the memory exception comes from an helper */ + gen_op_update_nip(ctx->nip - 4); + gen_addr_reg_index(ctx); + gen_op_load_fpr_FT0(rS(ctx->opcode)); + gen_op_load_fpr_FT1(rS(ctx->opcode) + 1); + op_POWER2_stfq(); +} + +/* BookE specific instructions */ +GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE) +{ + /* XXX: TODO */ + RET_INVAL(ctx); +} + +GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + /* Use the same micro-ops as for tlbie */ + gen_op_tlbie(); + RET_STOP(ctx); +#endif +} + +/* All 405 MAC instructions are translated here */ +static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3, + int ra, int rb, int rt, int Rc) +{ + gen_op_load_gpr_T0(ra); + gen_op_load_gpr_T1(rb); + switch (opc3 & 0x0D) { + case 0x05: + /* macchw - macchw. - macchwo - macchwo. */ + /* macchws - macchws. - macchwso - macchwso. */ + /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */ + /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */ + /* mulchw - mulchw. */ + gen_op_405_mulchw(); + break; + case 0x04: + /* macchwu - macchwu. - macchwuo - macchwuo. */ + /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */ + /* mulchwu - mulchwu. */ + gen_op_405_mulchwu(); + break; + case 0x01: + /* machhw - machhw. - machhwo - machhwo. */ + /* machhws - machhws. - machhwso - machhwso. */ + /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */ + /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */ + /* mulhhw - mulhhw. */ + gen_op_405_mulhhw(); + break; + case 0x00: + /* machhwu - machhwu. - machhwuo - machhwuo. */ + /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */ + /* mulhhwu - mulhhwu. */ + gen_op_405_mulhhwu(); + break; + case 0x0D: + /* maclhw - maclhw. - maclhwo - maclhwo. */ + /* maclhws - maclhws. - maclhwso - maclhwso. */ + /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */ + /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */ + /* mullhw - mullhw. */ + gen_op_405_mullhw(); + break; + case 0x0C: + /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */ + /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */ + /* mullhwu - mullhwu. */ + gen_op_405_mullhwu(); + break; + } + if (opc2 & 0x02) { + /* nmultiply-and-accumulate (0x0E) */ + gen_op_neg(); + } + if (opc2 & 0x04) { + /* (n)multiply-and-accumulate (0x0C - 0x0E) */ + gen_op_load_gpr_T2(rt); + gen_op_move_T1_T0(); + gen_op_405_add_T0_T2(); + } + if (opc3 & 0x10) { + /* Check overflow */ + if (opc3 & 0x01) + gen_op_405_check_ov(); + else + gen_op_405_check_ovu(); + } + if (opc3 & 0x02) { + /* Saturate */ + if (opc3 & 0x01) + gen_op_405_check_sat(); + else + gen_op_405_check_satu(); + } + gen_op_store_T0_gpr(rt); + if (unlikely(Rc) != 0) { + /* Update Rc0 */ + gen_set_Rc0(ctx); + } +} + +#define GEN_MAC_HANDLER(name, opc2, opc3) \ +GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \ +{ \ + gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \ + rD(ctx->opcode), Rc(ctx->opcode)); \ +} + +/* macchw - macchw. */ +GEN_MAC_HANDLER(macchw, 0x0C, 0x05); +/* macchwo - macchwo. */ +GEN_MAC_HANDLER(macchwo, 0x0C, 0x15); +/* macchws - macchws. */ +GEN_MAC_HANDLER(macchws, 0x0C, 0x07); +/* macchwso - macchwso. */ +GEN_MAC_HANDLER(macchwso, 0x0C, 0x17); +/* macchwsu - macchwsu. */ +GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06); +/* macchwsuo - macchwsuo. */ +GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16); +/* macchwu - macchwu. */ +GEN_MAC_HANDLER(macchwu, 0x0C, 0x04); +/* macchwuo - macchwuo. */ +GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14); +/* machhw - machhw. */ +GEN_MAC_HANDLER(machhw, 0x0C, 0x01); +/* machhwo - machhwo. */ +GEN_MAC_HANDLER(machhwo, 0x0C, 0x11); +/* machhws - machhws. */ +GEN_MAC_HANDLER(machhws, 0x0C, 0x03); +/* machhwso - machhwso. */ +GEN_MAC_HANDLER(machhwso, 0x0C, 0x13); +/* machhwsu - machhwsu. */ +GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02); +/* machhwsuo - machhwsuo. */ +GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12); +/* machhwu - machhwu. */ +GEN_MAC_HANDLER(machhwu, 0x0C, 0x00); +/* machhwuo - machhwuo. */ +GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10); +/* maclhw - maclhw. */ +GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D); +/* maclhwo - maclhwo. */ +GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D); +/* maclhws - maclhws. */ +GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F); +/* maclhwso - maclhwso. */ +GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F); +/* maclhwu - maclhwu. */ +GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C); +/* maclhwuo - maclhwuo. */ +GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C); +/* maclhwsu - maclhwsu. */ +GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E); +/* maclhwsuo - maclhwsuo. */ +GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E); +/* nmacchw - nmacchw. */ +GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05); +/* nmacchwo - nmacchwo. */ +GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15); +/* nmacchws - nmacchws. */ +GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07); +/* nmacchwso - nmacchwso. */ +GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17); +/* nmachhw - nmachhw. */ +GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01); +/* nmachhwo - nmachhwo. */ +GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11); +/* nmachhws - nmachhws. */ +GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03); +/* nmachhwso - nmachhwso. */ +GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13); +/* nmaclhw - nmaclhw. */ +GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D); +/* nmaclhwo - nmaclhwo. */ +GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D); +/* nmaclhws - nmaclhws. */ +GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F); +/* nmaclhwso - nmaclhwso. */ +GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F); + +/* mulchw - mulchw. */ +GEN_MAC_HANDLER(mulchw, 0x08, 0x05); +/* mulchwu - mulchwu. */ +GEN_MAC_HANDLER(mulchwu, 0x08, 0x04); +/* mulhhw - mulhhw. */ +GEN_MAC_HANDLER(mulhhw, 0x08, 0x01); +/* mulhhwu - mulhhwu. */ +GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00); +/* mullhw - mullhw. */ +GEN_MAC_HANDLER(mullhw, 0x08, 0x0D); +/* mullhwu - mullhwu. */ +GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C); + +/* mfdcr */ +GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + uint32_t dcrn = SPR(ctx->opcode); + + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_4xx_load_dcr(dcrn); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* mtdcr */ +GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVREG(ctx); +#else + uint32_t dcrn = SPR(ctx->opcode); + + if (unlikely(!ctx->supervisor)) { + RET_PRIVREG(ctx); + return; + } + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_4xx_store_dcr(dcrn); +#endif +} + +/* dccci */ +GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* dcread */ +GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + op_ldst(lwz); + gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif +} + +/* icbt */ +GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ +} + +/* iccci */ +GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* icread */ +GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* interpreted as no-op */ +#endif +} + +/* rfci (supervisor only) */ +GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + /* Restore CPU state */ + gen_op_4xx_rfci(); + RET_CHG_FLOW(ctx); +#endif +} + +/* tlbre */ +GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); + gen_op_4xx_tlbre_hi(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_4xx_tlbre_lo(); + gen_op_store_T0_gpr(rD(ctx->opcode)); + break; + default: + RET_INVAL(ctx); + break; } - op_eciwx(); +#endif +} + +/* tlbsx - tlbsx. */ /* Named tlbs in BookE */ +GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_addr_reg_index(ctx); + if (Rc(ctx->opcode)) + gen_op_4xx_tlbsx_(); + else + gen_op_4xx_tlbsx(); gen_op_store_T0_gpr(rD(ctx->opcode)); +#endif } -/* ecowx */ -GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN) +/* tlbwe */ +GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON) { - /* Should check EAR[E] & alignment ! */ - if (rA(ctx->opcode) == 0) { - gen_op_load_gpr_T0(rB(ctx->opcode)); - } else { +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + switch (rB(ctx->opcode)) { + case 0: gen_op_load_gpr_T0(rA(ctx->opcode)); - gen_op_load_gpr_T1(rB(ctx->opcode)); - gen_op_add(); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_4xx_tlbwe_hi(); + break; + case 1: + gen_op_load_gpr_T0(rA(ctx->opcode)); + gen_op_load_gpr_T1(rS(ctx->opcode)); + gen_op_4xx_tlbwe_lo(); + break; + default: + RET_INVAL(ctx); + break; } - gen_op_load_gpr_T2(rS(ctx->opcode)); - op_ecowx(); +#endif +} + +/* wrtee */ +GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_load_gpr_T0(rD(ctx->opcode)); + gen_op_4xx_wrte(); + RET_EXCP(ctx, EXCP_MTMSR, 0); +#endif +} + +/* wrteei */ +GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON) +{ +#if defined(CONFIG_USER_ONLY) + RET_PRIVOPC(ctx); +#else + if (unlikely(!ctx->supervisor)) { + RET_PRIVOPC(ctx); + return; + } + gen_op_set_T0(ctx->opcode & 0x00010000); + gen_op_4xx_wrte(); + RET_EXCP(ctx, EXCP_MTMSR, 0); +#endif +} + +/* PPC 440 specific instructions */ +/* dlmzb */ +GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC) +{ + gen_op_load_gpr_T0(rS(ctx->opcode)); + gen_op_load_gpr_T1(rB(ctx->opcode)); + gen_op_440_dlmzb(); + gen_op_store_T0_gpr(rA(ctx->opcode)); + gen_op_store_xer_bc(); + if (Rc(ctx->opcode)) { + gen_op_440_dlmzb_update_Rc(); + gen_op_store_T0_crf(0); + } +} + +/* mbar replaces eieio on 440 */ +GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE) +{ + /* interpreted as no-op */ +} + +/* msync replaces sync on 440 */ +GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE) +{ + /* interpreted as no-op */ +} + +/* icbt */ +GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE) +{ + /* interpreted as no-op */ + /* XXX: specification say this is treated as a load by the MMU + * but does not generate any exception + */ } /* End opcode list */ @@ -2439,18 +3548,25 @@ GEN_OPCODE_MARK(end); /*****************************************************************************/ /* Misc PowerPC helpers */ +static inline uint32_t load_xer (CPUState *env) +{ + return (xer_so << XER_SO) | + (xer_ov << XER_OV) | + (xer_ca << XER_CA) | + (xer_bc << XER_BC) | + (xer_cmp << XER_CMP); +} + void cpu_dump_state(CPUState *env, FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...), int flags) { #if defined(TARGET_PPC64) || 1 #define FILL "" -#define REGX "%016" PRIx64 #define RGPL 4 #define RFPL 4 #else #define FILL " " -#define REGX "%08" PRIx64 #define RGPL 8 #define RFPL 4 #endif @@ -2459,30 +3575,38 @@ void cpu_dump_state(CPUState *env, FILE *f, cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n", env->nip, env->lr, env->ctr); - cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n", - do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env), - cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env)); - for (i = 0; i < 32; i++) { + cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x " +#if !defined(CONFIG_USER_ONLY) + "DECR %08x" +#endif + "\n", + do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env), + cpu_ppc_load_tbl(env) +#if !defined(CONFIG_USER_ONLY) + , cpu_ppc_load_decr(env) +#endif + ); + for (i = 0; i < 32; i++) { if ((i & (RGPL - 1)) == 0) cpu_fprintf(f, "GPR%02d", i); cpu_fprintf(f, " " REGX, env->gpr[i]); if ((i & (RGPL - 1)) == (RGPL - 1)) cpu_fprintf(f, "\n"); - } + } cpu_fprintf(f, "CR "); - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) cpu_fprintf(f, "%01x", env->crf[i]); cpu_fprintf(f, " ["); - for (i = 0; i < 8; i++) { - char a = '-'; - if (env->crf[i] & 0x08) - a = 'L'; - else if (env->crf[i] & 0x04) - a = 'G'; - else if (env->crf[i] & 0x02) - a = 'E'; + for (i = 0; i < 8; i++) { + char a = '-'; + if (env->crf[i] & 0x08) + a = 'L'; + else if (env->crf[i] & 0x04) + a = 'G'; + else if (env->crf[i] & 0x02) + a = 'E'; cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); - } + } cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve); for (i = 0; i < 32; i++) { if ((i & (RFPL - 1)) == 0) @@ -2501,6 +3625,53 @@ void cpu_dump_state(CPUState *env, FILE *f, #undef FILL } +void cpu_dump_statistics (CPUState *env, FILE*f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ +#if defined(DO_PPC_STATISTICS) + opc_handler_t **t1, **t2, **t3, *handler; + int op1, op2, op3; + + t1 = env->opcodes; + for (op1 = 0; op1 < 64; op1++) { + handler = t1[op1]; + if (is_indirect_opcode(handler)) { + t2 = ind_table(handler); + for (op2 = 0; op2 < 32; op2++) { + handler = t2[op2]; + if (is_indirect_opcode(handler)) { + t3 = ind_table(handler); + for (op3 = 0; op3 < 32; op3++) { + handler = t3[op3]; + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: " + "%016llx %lld\n", + op1, op2, op3, op1, (op3 << 5) | op2, + handler->oname, + handler->count, handler->count); + } + } else { + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: " + "%016llx %lld\n", + op1, op2, op1, op2, handler->oname, + handler->count, handler->count); + } + } + } else { + if (handler->count == 0) + continue; + cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n", + op1, op1, handler->oname, + handler->count, handler->count); + } + } +#endif +} + /*****************************************************************************/ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, int search_pc) @@ -2534,8 +3705,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif /* Set env in case of segfault during code fetch */ while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { + if (unlikely(env->nb_breakpoints > 0)) { + for (j = 0; j < env->nb_breakpoints; j++) { if (env->breakpoints[j] == ctx.nip) { gen_op_update_nip(ctx.nip); gen_op_debug(); @@ -2543,7 +3714,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } } - if (search_pc) { + if (unlikely(search_pc)) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; @@ -2586,11 +3757,11 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } } /* Is opcode *REALLY* valid ? */ - if (handler->handler == &gen_invalid) { + if (unlikely(handler->handler == &gen_invalid)) { if (loglevel > 0) { - fprintf(logfile, "invalid/unsupported opcode: " + fprintf(logfile, "invalid/unsupported opcode: " "%02x - %02x - %02x (%08x) 0x%08x %d\n", - opc1(ctx.opcode), opc2(ctx.opcode), + opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } else { printf("invalid/unsupported opcode: " @@ -2598,8 +3769,8 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir); } - } else { - if ((ctx.opcode & handler->inval) != 0) { + } else { + if (unlikely((ctx.opcode & handler->inval) != 0)) { if (loglevel > 0) { fprintf(logfile, "invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", @@ -2609,38 +3780,40 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } else { printf("invalid bits: %08x for opcode: " "%02x -%02x - %02x (0x%08x) (0x%08x)\n", - ctx.opcode & handler->inval, opc1(ctx.opcode), - opc2(ctx.opcode), opc3(ctx.opcode), + ctx.opcode & handler->inval, opc1(ctx.opcode), + opc2(ctx.opcode), opc3(ctx.opcode), ctx.opcode, ctx.nip - 4); - } + } RET_INVAL(ctxp); break; } } (*(handler->handler))(&ctx); +#if defined(DO_PPC_STATISTICS) + handler->count++; +#endif /* Check trace mode exceptions */ - if ((msr_be && ctx.exception == EXCP_BRANCH) || - /* Check in single step trace mode - * we need to stop except if: - * - rfi, trap or syscall - * - first instruction of an exception handler - */ - (msr_se && (ctx.nip < 0x100 || - ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && - ctx.exception != EXCP_SYSCALL && - ctx.exception != EXCP_SYSCALL_USER && - ctx.exception != EXCP_TRAP)) { + if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) || + /* Check in single step trace mode + * we need to stop except if: + * - rfi, trap or syscall + * - first instruction of an exception handler + */ + (msr_se && (ctx.nip < 0x100 || + ctx.nip > 0xF00 || + (ctx.nip & 0xFC) != 0x04) && + ctx.exception != EXCP_SYSCALL && + ctx.exception != EXCP_SYSCALL_USER && + ctx.exception != EXCP_TRAP))) { RET_EXCP(ctxp, EXCP_TRACE, 0); } - /* if we reach a page boundary or are single stepping, stop * generation */ - if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || - (env->singlestep_enabled)) { + if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || + (env->singlestep_enabled))) { break; - } + } #if defined (DO_SINGLE_STEP) break; #endif @@ -2648,28 +3821,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (ctx.exception == EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != EXCP_BRANCH) { - gen_op_set_T0(0); + gen_op_reset_T0(); + /* Generate the return instruction */ + gen_op_exit_tb(); } -#if 1 - /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump - * do bad business and then qemu crashes ! - */ - gen_op_set_T0(0); -#endif - /* Generate the return instruction */ - gen_op_exit_tb(); *gen_opc_ptr = INDEX_op_end; - if (search_pc) { + if (unlikely(search_pc)) { j = gen_opc_ptr - gen_opc_buf; lj++; while (lj <= j) gen_opc_instr_start[lj++] = 0; tb->size = 0; -#if 0 - if (loglevel > 0) { - page_dump(logfile); - } -#endif } else { tb->size = ctx.nip - pc_start; } @@ -2679,8 +3841,10 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, cpu_dump_state(env, logfile, fprintf, 0); } if (loglevel & CPU_LOG_TB_IN_ASM) { + int flags; + flags = msr_le; fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); - target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le); + target_disas(logfile, pc_start, ctx.nip - pc_start, flags); fprintf(logfile, "\n"); } if (loglevel & CPU_LOG_TB_OP) { 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,151 +866,1366 @@ static void gen_spr_604 (CPUPPCState *env) 0x00000000); } -// XXX: TODO (64 bits PPC sprs) -/* - * ASR => SPR 280 (64 bits) - * FPECR => SPR 1022 (?) - * VRSAVE => SPR 256 (Altivec) - * SCOMC => SPR 276 (64 bits ?) - * SCOMD => SPR 277 (64 bits ?) - * HSPRG0 => SPR 304 (hypervisor) - * HSPRG1 => SPR 305 (hypervisor) - * HDEC => SPR 310 (hypervisor) - * HIOR => SPR 311 (hypervisor) - * RMOR => SPR 312 (970) - * HRMOR => SPR 313 (hypervisor) - * HSRR0 => SPR 314 (hypervisor) - * HSRR1 => SPR 315 (hypervisor) - * LPCR => SPR 316 (970) - * LPIDR => SPR 317 (970) - * ... and more (thermal management, performance counters, ...) - */ - -static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +/* SPR specific to PowerPC 603 implementation */ +static void gen_spr_603 (CPUPPCState *env) { - /* Default MMU definitions */ - env->nb_BATs = -1; - env->nb_tlb = 0; - env->nb_ways = 0; - /* XXX: missing: - * 32 bits PPC: - * - MPC5xx(x) - * - MPC8xx(x) - * - RCPU (MPC5xx) - */ - spr_register(env, SPR_PVR, "PVR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, SPR_NOACCESS, - def->pvr); - switch (def->pvr & def->pvr_mask) { - case CPU_PPC_604: /* PPC 604 */ - case CPU_PPC_604E: /* PPC 604e */ - case CPU_PPC_604R: /* PPC 604r */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_604(env); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - case CPU_PPC_74x: /* PPC 740 / 750 */ - case CPU_PPC_74xP: /* PPC 740P / 750P */ - case CPU_PPC_750CXE: /* IBM PPC 750cxe */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - case CPU_PPC_750FX: /* IBM PPC 750 FX */ - case CPU_PPC_750GX: /* IBM PPC 750 GX */ - gen_spr_generic(env); - gen_spr_ne_601(env); - /* Memory management */ - gen_low_BATs(env); - /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ - gen_high_BATs(env); - /* Time base */ - gen_tbl(env); - gen_spr_7xx(env); - /* XXX : not implemented */ - spr_register(env, SPR_L2CR, "L2CR", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* Hardware implementation registers */ - /* XXX : not implemented */ - spr_register(env, SPR_HID0, "HID0", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_HID1, "HID1", + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - /* XXX : not implemented */ - spr_register(env, SPR_750_HID2, "HID2", - SPR_NOACCESS, SPR_NOACCESS, - &spr_read_generic, &spr_write_generic, - 0x00000000); - break; - - default: - gen_spr_generic(env); - break; - } - if (env->nb_BATs == -1) - env->nb_BATs = 4; + &spr_read_generic, &spr_write_generic, + 0x00000000); } -#if defined(PPC_DUMP_CPU) -static void dump_sprs (CPUPPCState *env) +/* SPR specific to PowerPC G2 implementation */ +static void gen_spr_G2 (CPUPPCState *env) { - ppc_spr_t *spr; - uint32_t pvr = env->spr[SPR_PVR]; - uint32_t sr, sw, ur, uw; - int i, j, n; - - printf("* SPRs for PVR=%08x\n", pvr); - for (i = 0; i < 32; i++) { - for (j = 0; j < 32; j++) { - n = (i << 5) | j; - spr = &env->spr_cb[n]; + /* Memory base address */ + /* MBAR */ + spr_register(env, SPR_MBAR, "MBAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* System version register */ + /* SVR */ + spr_register(env, SPR_SVR, "SVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Exception processing */ + spr_register(env, SPR_CSRR0, "CSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_CSRR1, "CSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Breakpoints */ + /* XXX : not implemented */ + spr_register(env, SPR_DABR, "DABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DABR2, "DABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR, "IABR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IABR2, "IABR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_IBCR, "IBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_DBCR, "DBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 602 implementation */ +static void gen_spr_602 (CPUPPCState *env) +{ + /* ESA registers */ + /* XXX : not implemented */ + spr_register(env, SPR_SER, "SER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_SEBR, "SEBR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_ESASR, "ESASR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Floating point status */ + /* XXX : not implemented */ + spr_register(env, SPR_SP, "SP", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_LT, "LT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Watchdog timer */ + /* XXX : not implemented */ + spr_register(env, SPR_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Interrupt base */ + spr_register(env, SPR_IBR, "IBR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 601 implementation */ +static void gen_spr_601 (CPUPPCState *env) +{ + /* Multiplication/division register */ + /* MQ */ + spr_register(env, SPR_MQ, "MQ", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* RTC registers */ + spr_register(env, SPR_601_RTCU, "RTCU", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_601_rtcu, + 0x00000000); + spr_register(env, SPR_601_VRTCU, "RTCU", + &spr_read_601_rtcu, SPR_NOACCESS, + &spr_read_601_rtcu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_601_RTCL, "RTCL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_601_rtcl, + 0x00000000); + spr_register(env, SPR_601_VRTCL, "RTCL", + &spr_read_601_rtcl, SPR_NOACCESS, + &spr_read_601_rtcl, SPR_NOACCESS, + 0x00000000); + /* Timer */ +#if 0 /* ? */ + spr_register(env, SPR_601_UDECR, "UDECR", + &spr_read_decr, SPR_NOACCESS, + &spr_read_decr, SPR_NOACCESS, + 0x00000000); +#endif + /* External access control */ + /* XXX : not implemented */ + spr_register(env, SPR_EAR, "EAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Memory management */ + spr_register(env, SPR_IBAT0U, "IBAT0U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT0L, "IBAT0L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT1U, "IBAT1U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT1L, "IBAT1L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT2U, "IBAT2U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT2L, "IBAT2L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); + spr_register(env, SPR_IBAT3U, "IBAT3U", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatu, + 0x00000000); + spr_register(env, SPR_IBAT3L, "IBAT3L", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_601_ubat, &spr_write_601_ubatl, + 0x00000000); +} + +/* PowerPC BookE SPR */ +static void gen_spr_BookE (CPUPPCState *env) +{ + /* Processor identification */ + spr_register(env, SPR_BOOKE_PIR, "PIR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_pir, + 0x00000000); + /* Interrupt processing */ + spr_register(env, SPR_CSRR0, "CSRR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_CSRR1, "CSRR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC1, "IAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC1, "DAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR0, "DBCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR1, "DBCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBCR2, "DBCR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_BOOKE_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_DEAR, "DEAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_ESR, "ESR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_EVPR, "EVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR0, "IVOR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR1, "IVOR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR2, "IVOR2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR3, "IVOR3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR4, "IVOR4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR5, "IVOR5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR6, "IVOR6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR7, "IVOR7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR8, "IVOR8", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR9, "IVOR9", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR10, "IVOR10", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR11, "IVOR11", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR12, "IVOR12", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR13, "IVOR13", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR14, "IVOR14", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_IVOR15, "IVOR15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_BOOKE_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); + spr_register(env, SPR_BOOKE_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + /* Timer */ + spr_register(env, SPR_DECR, "DECR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_decr, &spr_write_decr, + 0x00000000); + spr_register(env, SPR_BOOKE_DECAR, "DECAR", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_USPRG0, "USPRG0", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); +} + +/* SPR specific to PowerPC 440 implementation */ +static void gen_spr_440 (CPUPPCState *env) +{ + /* Cache control */ + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV0, "DNV0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV1, "DNV1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV2, "DNV2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DNV3, "DNV3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT0, "DVT0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT1, "DVT1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT2, "DVT2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVT3, "DVT3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DVLIM, "DVLIM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV0, "INV0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV1, "INV1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV2, "INV2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_INV3, "INV3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT0, "IVT0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT1, "IVT1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT2, "IVT2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVT3, "IVT3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_IVLIM, "IVLIM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Cache debug */ + /* XXX : not implemented */ + spr_register(env, SPR_440_DCBTRH, "DCBTRH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DCBTRL, "DCBTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_ICBTRH, "ICBTRH", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_ICBTRL, "ICBTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_440_DBDR, "DBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Processor control */ + spr_register(env, SPR_4xx_CCR0, "CCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_440_RSTCFG, "RSTCFG", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Storage control */ + spr_register(env, SPR_440_MMUCR, "MMUCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR shared between PowerPC 40x implementations */ +static void gen_spr_40x (CPUPPCState *env) +{ + /* Cache */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCCR, "DCCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DCWR, "DCWR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_ICCR, "ICCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_4xx_ICDBDR, "ICDBDR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + 0x00000000); + /* Bus access control */ + spr_register(env, SPR_40x_SGR, "SGR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0xFFFFFFFF); + spr_register(env, SPR_40x_ZPR, "ZPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* MMU */ + spr_register(env, SPR_40x_PID, "PID", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Exception */ + spr_register(env, SPR_40x_DEAR, "DEAR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_ESR, "ESR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_EVPR, "EVPR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_SRR2, "SRR2", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_SRR3, "SRR3", + &spr_read_generic, &spr_write_generic, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Timers */ + spr_register(env, SPR_40x_PIT, "PIT", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_40x_pit, &spr_write_40x_pit, + 0x00000000); + spr_register(env, SPR_40x_TCR, "TCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tcr, + 0x00000000); + spr_register(env, SPR_40x_TSR, "TSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_booke_tsr, + 0x00000000); + /* Debug interface */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC1, "DAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBCR0, "DBCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_DBSR, "DBSR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + /* Last reset was system reset (system boot */ + 0x00000300); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC1, "IAC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 405 implementation */ +static void gen_spr_405 (CPUPPCState *env) +{ + spr_register(env, SPR_4xx_CCR0, "CCR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00700000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_405_DBCR1, "DBCR1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_DVC1, "DVC1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_DVC2, "DVC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_IAC3, "IAC3", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_IAC4, "IAC4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Storage control */ + /* XXX : not implemented */ + spr_register(env, SPR_405_SLER, "SLER", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_405_SU0R, "SU0R", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* SPRG */ + spr_register(env, SPR_USPRG0, "USPRG0", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR shared between PowerPC 401 & 403 implementations */ +static void gen_spr_401_403 (CPUPPCState *env) +{ + /* Time base */ + spr_register(env, SPR_403_VTBL, "TBL", + &spr_read_tbl, SPR_NOACCESS, + &spr_read_tbl, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_403_TBL, "TBL", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbl, + 0x00000000); + spr_register(env, SPR_403_VTBU, "TBU", + &spr_read_tbu, SPR_NOACCESS, + &spr_read_tbu, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_403_TBU, "TBU", + SPR_NOACCESS, SPR_NOACCESS, + SPR_NOACCESS, &spr_write_tbu, + 0x00000000); + /* Debug */ + /* XXX: not implemented */ + spr_register(env, SPR_403_CDBCR, "CDBCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC 403 implementation */ +static void gen_spr_403 (CPUPPCState *env) +{ + /* MMU */ + spr_register(env, SPR_403_PBL1, "PBL1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBU1, "PBU1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBL2, "PBL2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + spr_register(env, SPR_403_PBU2, "PBU2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_403_pbr, &spr_write_403_pbr, + 0x00000000); + /* Debug */ + /* XXX : not implemented */ + spr_register(env, SPR_40x_DAC2, "DAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_40x_IAC2, "IAC2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} + +/* SPR specific to PowerPC compression coprocessor extension */ +#if defined (TODO) +static void gen_spr_compress (CPUPPCState *env) +{ + spr_register(env, SPR_401_SKR, "SKR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +} +#endif + +// XXX: TODO (64 bits PowerPC SPRs) +/* + * ASR => SPR 280 (64 bits) + * FPECR => SPR 1022 (?) + * VRSAVE => SPR 256 (Altivec) + * SCOMC => SPR 276 (64 bits ?) + * SCOMD => SPR 277 (64 bits ?) + * HSPRG0 => SPR 304 (hypervisor) + * HSPRG1 => SPR 305 (hypervisor) + * HDEC => SPR 310 (hypervisor) + * HIOR => SPR 311 (hypervisor) + * RMOR => SPR 312 (970) + * HRMOR => SPR 313 (hypervisor) + * HSRR0 => SPR 314 (hypervisor) + * HSRR1 => SPR 315 (hypervisor) + * LPCR => SPR 316 (970) + * LPIDR => SPR 317 (970) + * ... and more (thermal management, performance counters, ...) + */ + +static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def) +{ + env->reserve = -1; + /* Default MMU definitions */ + env->nb_BATs = -1; + env->nb_tlb = 0; + env->nb_ways = 0; + /* XXX: missing: + * 32 bits PowerPC: + * - MPC5xx(x) + * - MPC8xx(x) + * - RCPU (same as MPC5xx ?) + */ + spr_register(env, SPR_PVR, "PVR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, SPR_NOACCESS, + def->pvr); + printf("%s: PVR %08x mask %08x => %08x\n", __func__, + def->pvr, def->pvr_mask, def->pvr & def->pvr_mask); + switch (def->pvr & def->pvr_mask) { + /* Embedded PowerPC from IBM */ + case CPU_PPC_401A1: /* 401 A1 family */ + case CPU_PPC_401B2: /* 401 B2 family */ + case CPU_PPC_401C2: /* 401 C2 family */ + case CPU_PPC_401D2: /* 401 D2 family */ + case CPU_PPC_401E2: /* 401 E2 family */ + case CPU_PPC_401F2: /* 401 F2 family */ + case CPU_PPC_401G2: /* 401 G2 family */ + case CPU_PPC_IOP480: /* IOP 480 family */ + case CPU_PPC_COBRA: /* IBM Processor for Network Resources */ + gen_spr_generic(env); + gen_spr_40x(env); + gen_spr_401_403(env); +#if defined (TODO) + /* XXX: optional ? */ + gen_spr_compress(env); +#endif + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_403GA: /* 403 GA family */ + case CPU_PPC_403GB: /* 403 GB family */ + case CPU_PPC_403GC: /* 403 GC family */ + case CPU_PPC_403GCX: /* 403 GCX family */ + gen_spr_generic(env); + gen_spr_40x(env); + gen_spr_401_403(env); + gen_spr_403(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_405CR: /* 405 GP/CR family */ + case CPU_PPC_405EP: /* 405 EP family */ + case CPU_PPC_405GPR: /* 405 GPR family */ + case CPU_PPC_405D2: /* 405 D2 family */ + case CPU_PPC_405D4: /* 405 D4 family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_NPE405H: /* NPe405 H family */ + case CPU_PPC_NPE405H2: + case CPU_PPC_NPE405L: /* Npe405 L family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + +#if defined (TODO) + case CPU_PPC_STB01000: +#endif +#if defined (TODO) + case CPU_PPC_STB01010: +#endif +#if defined (TODO) + case CPU_PPC_STB0210: +#endif + case CPU_PPC_STB03: /* STB03 family */ +#if defined (TODO) + case CPU_PPC_STB043: /* STB043 family */ +#endif +#if defined (TODO) + case CPU_PPC_STB045: /* STB045 family */ +#endif + case CPU_PPC_STB25: /* STB25 family */ +#if defined (TODO) + case CPU_PPC_STB130: /* STB130 family */ +#endif + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_40x(env); + gen_spr_405(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + case CPU_PPC_440EP: /* 440 EP family */ + case CPU_PPC_440GP: /* 440 GP family */ + case CPU_PPC_440GX: /* 440 GX family */ + case CPU_PPC_440GXc: /* 440 GXc family */ + case CPU_PPC_440GXf: /* 440 GXf family */ + case CPU_PPC_440SP: /* 440 SP family */ + case CPU_PPC_440SP2: + case CPU_PPC_440SPE: /* 440 SPE family */ + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + gen_spr_440(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + + /* Embedded PowerPC from Freescale */ +#if defined (TODO) + case CPU_PPC_5xx: + break; +#endif +#if defined (TODO) + case CPU_PPC_8xx: /* MPC821 / 823 / 850 / 860 */ + break; +#endif +#if defined (TODO) + case CPU_PPC_82xx_HIP3: /* MPC8240 / 8260 */ + case CPU_PPC_82xx_HIP4: /* MPC8240 / 8260 */ + break; +#endif +#if defined (TODO) + case CPU_PPC_827x: /* MPC 827x / 828x */ + break; +#endif + + /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */ + case CPU_PPC_e500v110: + case CPU_PPC_e500v120: + case CPU_PPC_e500v210: + case CPU_PPC_e500v220: + gen_spr_generic(env); + /* Time base */ + gen_tbl(env); + gen_spr_BookE(env); + env->nb_BATs = 0; + env->nb_tlb = 64; + env->nb_ways = 1; + env->id_tlbs = 0; + break; + +#if defined (TODO) + case CPU_PPC_e600: + break; +#endif + + /* 32 bits PowerPC */ + case CPU_PPC_601: /* PowerPC 601 */ + gen_spr_generic(env); + gen_spr_ne_601(env); + gen_spr_601(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_601_HID5, "HID5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ +#if 0 /* ? */ + spr_register(env, SPR_601_HID15, "HID15", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); +#endif + env->nb_tlb = 64; + env->nb_ways = 2; + env->id_tlbs = 0; + env->id_tlbs = 0; + break; + + case CPU_PPC_602: /* PowerPC 602 */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_602(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_603: /* PowerPC 603 */ + case CPU_PPC_603E: /* PowerPC 603e */ + case CPU_PPC_603E7v: + case CPU_PPC_603E7v2: + case CPU_PPC_603P: /* PowerPC 603p */ + case CPU_PPC_603R: /* PowerPC 603r */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_603(env); + /* hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_G2: /* PowerPC G2 family */ + case CPU_PPC_G2H4: + case CPU_PPC_G2gp: + case CPU_PPC_G2ls: + case CPU_PPC_G2LE: /* PowerPC G2LE family */ + case CPU_PPC_G2LEgp: + case CPU_PPC_G2LEls: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + /* Memory management */ + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_G2_755(env); + gen_spr_G2(env); + /* Hardware implementation register */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_604: /* PowerPC 604 */ + case CPU_PPC_604E: /* PowerPC 604e */ + case CPU_PPC_604R: /* PowerPC 604r */ + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_604(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_74x: /* PowerPC 740 / 750 */ + case CPU_PPC_740E: + case CPU_PPC_750E: + case CPU_PPC_74xP: /* PowerPC 740P / 750P */ + case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe */ + case CPU_PPC_750CXE22: + case CPU_PPC_750CXE23: + case CPU_PPC_750CXE24: + case CPU_PPC_750CXE24b: + case CPU_PPC_750CXE31: + case CPU_PPC_750CXE31b: + case CPU_PPC_750CXR: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */ + case CPU_PPC_750FX20: + case CPU_PPC_750FX21: + case CPU_PPC_750FX22: + case CPU_PPC_750FX23: + case CPU_PPC_750GX10: /* IBM PowerPC 750 GX */ + case CPU_PPC_750GX11: + case CPU_PPC_750GX12: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */ + gen_high_BATs(env); + /* Time base */ + gen_tbl(env); + gen_spr_7xx(env); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_750_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + + case CPU_PPC_755_10: /* PowerPC 755 */ + case CPU_PPC_755_11: + case CPU_PPC_755_20: + case CPU_PPC_755D: + case CPU_PPC_755E: + gen_spr_generic(env); + gen_spr_ne_601(env); + /* Memory management */ + gen_low_BATs(env); + /* Time base */ + gen_tbl(env); + /* Memory management */ + gen_high_BATs(env); + gen_6xx_7xx_soft_tlb(env, 64, 2); + gen_spr_G2_755(env); + /* L2 cache control */ + /* XXX : not implemented */ + spr_register(env, SPR_ICTC, "ICTC", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_L2PM, "L2PM", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* Hardware implementation registers */ + /* XXX : not implemented */ + spr_register(env, SPR_HID0, "HID0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID1, "HID1", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_HID2, "HID2", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + break; + +#if defined (TODO) + /* G4 family */ + case CPU_PPC_7400: /* PowerPC 7400 */ + case CPU_PPC_7410C: /* PowerPC 7410 */ + case CPU_PPC_7410D: + case CPU_PPC_7410E: + case CPU_PPC_7441: /* PowerPC 7441 */ + case CPU_PPC_7445: /* PowerPC 7445 */ + case CPU_PPC_7447: /* PowerPC 7447 */ + case CPU_PPC_7447A: /* PowerPC 7447A */ + case CPU_PPC_7448: /* PowerPC 7448 */ + case CPU_PPC_7450: /* PowerPC 7450 */ + case CPU_PPC_7450b: + case CPU_PPC_7451: /* PowerPC 7451 */ + case CPU_PPC_7451G: + case CPU_PPC_7455: /* PowerPC 7455 */ + case CPU_PPC_7455F: + case CPU_PPC_7455G: + case CPU_PPC_7457: /* PowerPC 7457 */ + case CPU_PPC_7457C: + case CPU_PPC_7457A: /* PowerPC 7457A */ + break; +#endif + +#if defined (TODO) + /* 64 bits PowerPC */ + case CPU_PPC_620: /* PowerPC 620 */ + case CPU_PPC_630: /* PowerPC 630 (Power 3) */ + case CPU_PPC_631: /* PowerPC 631 (Power 3+) */ + case CPU_PPC_POWER4: /* Power 4 */ + case CPU_PPC_POWER4P: /* Power 4+ */ + case CPU_PPC_POWER5: /* Power 5 */ + case CPU_PPC_POWER5P: /* Power 5+ */ + case CPU_PPC_970: /* PowerPC 970 */ + case CPU_PPC_970FX10: /* PowerPC 970 FX */ + case CPU_PPC_970FX20: + case CPU_PPC_970FX21: + case CPU_PPC_970FX30: + case CPU_PPC_970FX31: + case CPU_PPC_970MP10: /* PowerPC 970 MP */ + case CPU_PPC_970MP11: + case CPU_PPC_CELL10: /* Cell family */ + case CPU_PPC_CELL20: + case CPU_PPC_CELL30: + case CPU_PPC_CELL31: + case CPU_PPC_RS64: /* Apache (RS64/A35) */ + case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */ + case CPU_PPC_RS64III: /* Pulsar (RS64-III) */ + case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */ + break; +#endif + +#if defined (TODO) + /* POWER */ + case CPU_POWER: /* POWER */ + case CPU_POWER2: /* POWER2 */ + break; +#endif + + default: + gen_spr_generic(env); + break; + } + if (env->nb_BATs == -1) + env->nb_BATs = 4; + /* Allocate TLBs buffer when needed */ + if (env->nb_tlb != 0) { + int nb_tlb = env->nb_tlb; + if (env->id_tlbs != 0) + nb_tlb *= 2; + env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t)); + /* Pre-compute some useful values */ + env->tlb_per_way = env->nb_tlb / env->nb_ways; + } +} + +#if defined(PPC_DUMP_CPU) +static void dump_sprs (CPUPPCState *env) +{ + ppc_spr_t *spr; + uint32_t pvr = env->spr[SPR_PVR]; + uint32_t sr, sw, ur, uw; + int i, j, n; + + printf("* SPRs for PVR=%08x\n", pvr); + for (i = 0; i < 32; i++) { + for (j = 0; j < 32; j++) { + n = (i << 5) | j; + spr = &env->spr_cb[n]; +#if !defined(CONFIG_USER_ONLY) sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS; sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS; +#else + sw = 0; + sr = 0; +#endif uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS; ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS; if (sw || sr || uw || ur) { @@ -889,7 +2301,7 @@ static int register_direct_insn (opc_handler_t **ppc_opcodes, { if (insert_in_table(ppc_opcodes, idx, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in main " - "opcode table\n", idx); + "opcode table\n", idx); return -1; } @@ -903,20 +2315,20 @@ static int register_ind_in_table (opc_handler_t **table, if (table[idx1] == &invalid_handler) { if (create_new_table(table, idx1) < 0) { printf("*** ERROR: unable to create indirect table " - "idx=%02x\n", idx1); + "idx=%02x\n", idx1); return -1; } } else { if (!is_indirect_opcode(table[idx1])) { printf("*** ERROR: idx %02x already assigned to a direct " - "opcode\n", idx1); + "opcode\n", idx1); return -1; } } if (handler != NULL && insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) { printf("*** ERROR: opcode %02x already assigned in " - "opcode table %02x\n", idx2, idx1); + "opcode table %02x\n", idx2, idx1); return -1; } @@ -925,7 +2337,7 @@ static int register_ind_in_table (opc_handler_t **table, static int register_ind_insn (opc_handler_t **ppc_opcodes, unsigned char idx1, unsigned char idx2, - opc_handler_t *handler) + opc_handler_t *handler) { int ret; @@ -936,17 +2348,17 @@ static int register_ind_insn (opc_handler_t **ppc_opcodes, static int register_dblind_insn (opc_handler_t **ppc_opcodes, unsigned char idx1, unsigned char idx2, - unsigned char idx3, opc_handler_t *handler) + unsigned char idx3, opc_handler_t *handler) { if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) { printf("*** ERROR: unable to join indirect table idx " - "[%02x-%02x]\n", idx1, idx2); + "[%02x-%02x]\n", idx1, idx2); return -1; } if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3, handler) < 0) { printf("*** ERROR: unable to insert opcode " - "[%02x-%02x-%02x]\n", idx1, idx2, idx3); + "[%02x-%02x-%02x]\n", idx1, idx2, idx3); return -1; } @@ -1012,21 +2424,22 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) fill_new_table(env->opcodes, 0x40); #if defined(PPC_DUMP_CPU) - printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name); + printf("* PowerPC instructions for PVR %08x: %s flags %08x %08x\n", + def->pvr, def->name, def->insns_flags, def->flags); #endif if (&opc_start < &opc_end) { - start = &opc_start; - end = &opc_end; + start = &opc_start; + end = &opc_end; } else { - start = &opc_end; - end = &opc_start; + start = &opc_end; + end = &opc_start; } for (opc = start + 1; opc != end; opc++) { if ((opc->handler.type & def->insns_flags) != 0) { if (register_insn(env->opcodes, opc) < 0) { - printf("*** ERROR initializing PPC instruction " - "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, - opc->opc3); + printf("*** ERROR initializing PowerPC instruction " + "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2, + opc->opc3); return -1; } #if defined(PPC_DUMP_CPU) @@ -1038,7 +2451,7 @@ static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def) } else { printf(" %02x %02x -- (%2d %4d) : %s\n", opc->opc1, opc->opc2, opc->opc1, opc->opc2, - opc->oname); + opc->oname); } } else { printf(" %02x %02x %02x (%2d %4d) : %s\n", @@ -1061,23 +2474,22 @@ int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def) { env->msr_mask = def->msr_mask; env->flags = def->flags; - if (create_ppc_opcodes(env, def) < 0) { - printf("Error creating opcodes table\n"); - fflush(stdout); - fflush(stderr); + if (create_ppc_opcodes(env, def) < 0) return -1; - } init_ppc_proc(env, def); #if defined(PPC_DUMP_CPU) dump_sprs(env); + if (env->tlb != NULL) { + printf("%d %s TLB in %d ways\n", env->nb_tlb, + env->id_tlbs ? "splitted" : "merged", env->nb_ways); + } #endif - fflush(stdout); - fflush(stderr); return 0; } -CPUPPCState *cpu_ppc_init(void) +void do_compute_hflags (CPUPPCState *env); +CPUPPCState *cpu_ppc_init (void) { CPUPPCState *env; @@ -1112,911 +2524,1171 @@ void cpu_ppc_close(CPUPPCState *env) /*****************************************************************************/ /* PowerPC CPU definitions */ static ppc_def_t ppc_defs[] = -{ - /* Embedded PPC */ -#if defined (TODO) - /* PPC 401 */ { - .name = "401", - .pvr = CPU_PPC_401, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, + /* Embedded PowerPC */ +#if defined (TODO) + /* PowerPC 401 */ + { + .name = "401", + .pvr = CPU_PPC_401, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* IOP480 (401 microcontroler) */ - { - .name = "iop480", - .pvr = CPU_PPC_IOP480, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_401, - .flags = PPC_FLAGS_401, - .msr_mask = xxx, - }, + /* IOP480 (401 microcontroler) */ + { + .name = "iop480", + .pvr = CPU_PPC_IOP480, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PPC 403 GA */ - { - .name = "403ga", - .pvr = CPU_PPC_403GA, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* IBM Processor for Network Resources */ + { + .name = "Cobra", + .pvr = CPU_PPC_COBRA, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_401, + .flags = PPC_FLAGS_401, + .msr_mask = xxx, + }, #endif #if defined (TODO) - /* PPC 403 GB */ - { - .name = "403gb", - .pvr = CPU_PPC_403GB, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* Generic PowerPC 403 */ + { + .name = "403", + .pvr = CPU_PPC_403, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 403 GC */ - { - .name = "403gc", - .pvr = CPU_PPC_403GC, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* PowerPC 403 GA */ + { + .name = "403ga", + .pvr = CPU_PPC_403GA, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 403 GCX */ - { - .name = "403gcx", - .pvr = CPU_PPC_403GCX, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_403, - .flags = PPC_FLAGS_403, - .msr_mask = 0x000000000007D23D, - }, + /* PowerPC 403 GB */ + { + .name = "403gb", + .pvr = CPU_PPC_403GB, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 CR */ - { - .name = "405cr", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GC */ + { + .name = "403gc", + .pvr = CPU_PPC_403GC, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 GP */ - { - .name = "405gp", - .pvr = CPU_PPC_405, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 403 GCX */ + { + .name = "403gcx", + .pvr = CPU_PPC_403GCX, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_403, + .flags = PPC_FLAGS_403, + .msr_mask = 0x000000000007D23D, + }, #endif #if defined (TODO) - /* PPC 405 EP */ - { - .name = "405ep", - .pvr = CPU_PPC_405EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Generic PowerPC 405 */ + { + .name = "405", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 GPR */ - { - .name = "405gpr", - .pvr = CPU_PPC_405GPR, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 CR */ + { + .name = "405cr", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 D2 */ - { - .name = "405d2", - .pvr = CPU_PPC_405D2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 GP */ + { + .name = "405gp", + .pvr = CPU_PPC_405, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 405 D4 */ - { - .name = "405d4", - .pvr = CPU_PPC_405D4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 EP */ + { + .name = "405ep", + .pvr = CPU_PPC_405EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* Npe405 H */ - { - .name = "Npe405H", - .pvr = CPU_PPC_NPE405H, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 GPR */ + { + .name = "405gpr", + .pvr = CPU_PPC_405GPR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* Npe405 L */ - { - .name = "Npe405L", - .pvr = CPU_PPC_NPE405L, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D2 */ + { + .name = "405d2", + .pvr = CPU_PPC_405D2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB03xx */ - { - .name = "STB03", - .pvr = CPU_PPC_STB03, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* PowerPC 405 D4 */ + { + .name = "405d4", + .pvr = CPU_PPC_405D4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB04xx */ - { - .name = "STB04", - .pvr = CPU_PPC_STB04, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Npe405 H */ + { + .name = "Npe405H", + .pvr = CPU_PPC_NPE405H, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* STB25xx */ - { - .name = "STB25", - .pvr = CPU_PPC_STB25, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_405, - .msr_mask = 0x00000000020EFF30, - }, + /* Npe405 L */ + { + .name = "Npe405L", + .pvr = CPU_PPC_NPE405L, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 EP */ - { - .name = "440ep", - .pvr = CPU_PPC_440EP, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB010000 */ + { + .name = "STB01000", + .pvr = CPU_PPC_STB01000, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 GP */ - { - .name = "440gp", - .pvr = CPU_PPC_440GP, - .pvr_mask = 0xFFFFFF00, - .insns_flags = PPC_INSNS_440, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB01010 */ + { + .name = "STB01010", + .pvr = CPU_PPC_STB01010, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 440 GX */ - { - .name = "440gx", - .pvr = CPU_PPC_440GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_405, - .flags = PPC_FLAGS_440, - .msr_mask = 0x000000000006D630, - }, + /* STB0210 */ + { + .name = "STB0210", + .pvr = CPU_PPC_STB0210, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif - - /* 32 bits "classic" powerpc */ #if defined (TODO) - /* PPC 601 */ - { - .name = "601", - .pvr = CPU_PPC_601, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_601, - .flags = PPC_FLAGS_601, - .msr_mask = 0x000000000000FD70, - }, + /* STB03xx */ + { + .name = "STB03", + .pvr = CPU_PPC_STB03, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 602 */ - { - .name = "602", - .pvr = CPU_PPC_602, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_602, - .flags = PPC_FLAGS_602, - .msr_mask = 0x0000000000C7FF73, - }, + /* STB043x */ + { + .name = "STB043", + .pvr = CPU_PPC_STB043, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603 */ - { - .name = "603", - .pvr = CPU_PPC_603, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB045x */ + { + .name = "STB045", + .pvr = CPU_PPC_STB045, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603e */ - { - .name = "603e", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Stretch", - .pvr = CPU_PPC_603E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB25xx */ + { + .name = "STB25", + .pvr = CPU_PPC_STB25, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* PPC 603ev */ - { - .name = "603ev", - .pvr = CPU_PPC_603EV, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + /* STB130 */ + { + .name = "STB130", + .pvr = CPU_PPC_STB130, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif + /* Xilinx PowerPC 405 cores */ #if defined (TODO) - /* PPC 603r */ - { - .name = "603r", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, - { - .name = "Goldeneye", - .pvr = CPU_PPC_603R, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_603, - .flags = PPC_FLAGS_603, - .msr_mask = 0x000000000007FF73, - }, + { + .name = "x2vp4", + .pvr = CPU_PPC_X2VP4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp7", + .pvr = CPU_PPC_X2VP7, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp20", + .pvr = CPU_PPC_X2VP20, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, + { + .name = "x2vp50", + .pvr = CPU_PPC_X2VP50, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_405, + .msr_mask = 0x00000000020EFF30, + }, #endif #if defined (TODO) - /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ - { - .name = "G2", - .pvr = CPU_PPC_G2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000006FFF2, - }, - { /* Same as G2, with LE mode support */ - .name = "G2le", - .pvr = CPU_PPC_G2LE, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_G2, - .flags = PPC_FLAGS_G2, - .msr_mask = 0x000000000007FFF3, - }, -#endif - /* PPC 604 */ - { - .name = "604", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PPC 604e */ - { - .name = "604e", - .pvr = CPU_PPC_604E, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* PPC 604r */ - { - .name = "604r", - .pvr = CPU_PPC_604R, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_604, - .flags = PPC_FLAGS_604, - .msr_mask = 0x000000000005FF77, - }, - /* generic G3 */ - { - .name = "G3", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC740 (G3) */ - { - .name = "740", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Arthur", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 EP */ + { + .name = "440ep", + .pvr = CPU_PPC_440EP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC745 (G3) */ - { - .name = "745", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Goldfinger", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750 (G3) */ - { - .name = "750", - .pvr = CPU_PPC_74x, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755 (G3) */ - { - .name = "755", - .pvr = CPU_PPC_755, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 GR */ + { + .name = "440gr", + .pvr = CPU_PPC_440GR, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC740P (G3) */ - { - .name = "740p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - { - .name = "Conan/Doyle", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, + /* PowerPC 440 GP */ + { + .name = "440gp", + .pvr = CPU_PPC_440GP, + .pvr_mask = 0xFFFFFF00, + .insns_flags = PPC_INSNS_440, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* MPC745P (G3) */ - { - .name = "745p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* MPC750P (G3) */ - { - .name = "750p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* MPC755P (G3) */ - { - .name = "755p", - .pvr = CPU_PPC_74xP, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x5, - .flags = PPC_FLAGS_7x5, - .msr_mask = 0x000000000007FF77, - }, -#endif - /* IBM 750CXe (G3 embedded) */ - { - .name = "750cxe", - .pvr = CPU_PPC_750CXE, - .pvr_mask = 0xFFFFF000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750FX (G3 embedded) */ - { - .name = "750fx", - .pvr = CPU_PPC_750FX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, - /* IBM 750GX (G3 embedded) */ - { - .name = "750gx", - .pvr = CPU_PPC_750GX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_7x0, - .flags = PPC_FLAGS_7x0, - .msr_mask = 0x000000000007FF77, - }, -#if defined (TODO) - /* generic G4 */ - { - .name = "G4", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GX */ + { + .name = "440gx", + .pvr = CPU_PPC_440GX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7400 (G4) */ - { - .name = "7400", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Max", - .pvr = CPU_PPC_7400, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GXc */ + { + .name = "440gxc", + .pvr = CPU_PPC_440GXC, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7410 (G4) */ - { - .name = "7410", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Nitro", - .pvr = CPU_PPC_7410, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, -#endif - /* XXX: 7441 */ - /* XXX: 7445 */ - /* XXX: 7447 */ - /* XXX: 7447A */ -#if defined (TODO) - /* PPC 7450 (G4) */ - { - .name = "7450", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Vger", - .pvr = CPU_PPC_7450, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 GXf */ + { + .name = "440gxf", + .pvr = CPU_PPC_440GXF, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif - /* XXX: 7451 */ #if defined (TODO) - /* PPC 7455 (G4) */ - { - .name = "7455", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 6", - .pvr = CPU_PPC_7455, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SP */ + { + .name = "440sp", + .pvr = CPU_PPC_440SP, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7457 (G4) */ - { - .name = "7457", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7", - .pvr = CPU_PPC_7457, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SP2 */ + { + .name = "440sp2", + .pvr = CPU_PPC_440SP2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif #if defined (TODO) - /* PPC 7457A (G4) */ - { - .name = "7457A", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, - { - .name = "Apollo 7 PM", - .pvr = CPU_PPC_7457A, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_74xx, - .flags = PPC_FLAGS_74xx, - .msr_mask = 0x000000000205FF77, - }, + /* PowerPC 440 SPE */ + { + .name = "440spe", + .pvr = CPU_PPC_440SPE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_405, + .flags = PPC_FLAGS_440, + .msr_mask = 0x000000000006D630, + }, #endif - /* 64 bits PPC */ + /* Fake generic BookE PowerPC */ + { + .name = "BookE", + .pvr = CPU_PPC_e500, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_BOOKE, + .flags = PPC_FLAGS_BOOKE, + .msr_mask = 0x000000000006D630, + }, + /* PowerPC 460 cores - TODO */ + /* PowerPC MPC 5xx cores - TODO */ + /* PowerPC MPC 8xx cores - TODO */ + /* PowerPC MPC 8xxx cores - TODO */ + /* e200 cores - TODO */ + /* e500 cores - TODO */ + /* e600 cores - TODO */ + + /* 32 bits "classic" PowerPC */ #if defined (TODO) - /* PPC 620 */ - { - .name = "620", - .pvr = CPU_PPC_620, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_620, - .flags = PPC_FLAGS_620, - .msr_mask = 0x800000000005FF73, - }, + /* PowerPC 601 */ + { + .name = "601", + .pvr = CPU_PPC_601, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_601, + .flags = PPC_FLAGS_601, + .msr_mask = 0x000000000000FD70, + }, #endif #if defined (TODO) - /* PPC 630 (POWER3) */ - { - .name = "630", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } - { - .name = "POWER3", - .pvr = CPU_PPC_630, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_630, - .flags = PPC_FLAGS_630, - .msr_mask = xxx, - } + /* PowerPC 602 */ + { + .name = "602", + .pvr = CPU_PPC_602, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_602, + .flags = PPC_FLAGS_602, + .msr_mask = 0x0000000000C7FF73, + }, #endif + /* PowerPC 603 */ + { + .name = "603", + .pvr = CPU_PPC_603, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e */ + { + .name = "603e", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Stretch", + .pvr = CPU_PPC_603E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603p */ + { + .name = "603p", + .pvr = CPU_PPC_603P, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7 */ + { + .name = "603e7", + .pvr = CPU_PPC_603E7, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v */ + { + .name = "603e7v", + .pvr = CPU_PPC_603E7v, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603e7v2 */ + { + .name = "603e7v2", + .pvr = CPU_PPC_603E7v2, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + /* PowerPC 603r */ + { + .name = "603r", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, + { + .name = "Goldeneye", + .pvr = CPU_PPC_603R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_603, + .flags = PPC_FLAGS_603, + .msr_mask = 0x000000000007FF73, + }, #if defined (TODO) - /* PPC 631 (Power 3+)*/ - { - .name = "631", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, - { - .name = "POWER3+", - .pvr = CPU_PPC_631, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_631, - .flags = PPC_FLAGS_631, - .msr_mask = xxx, - }, + /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */ + { + .name = "G2", + .pvr = CPU_PPC_G2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2h4", + .pvr = CPU_PPC_G2H4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2gp", + .pvr = CPU_PPC_G2gp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { + .name = "G2ls", + .pvr = CPU_PPC_G2ls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000006FFF2, + }, + { /* Same as G2, with LE mode support */ + .name = "G2le", + .pvr = CPU_PPC_G2LE, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2legp", + .pvr = CPU_PPC_G2LEgp, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, + { + .name = "G2lels", + .pvr = CPU_PPC_G2LEls, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_G2, + .flags = PPC_FLAGS_G2, + .msr_mask = 0x000000000007FFF3, + }, #endif + /* PowerPC 604 */ + { + .name = "604", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604e */ + { + .name = "604e", + .pvr = CPU_PPC_604E, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* PowerPC 604r */ + { + .name = "604r", + .pvr = CPU_PPC_604R, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_604, + .flags = PPC_FLAGS_604, + .msr_mask = 0x000000000005FF77, + }, + /* generic G3 */ + { + .name = "G3", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* MPC740 (G3) */ + { + .name = "740", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Arthur", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER4 */ - { - .name = "POWER4", - .pvr = CPU_PPC_POWER4, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, + /* MPC745 (G3) */ + { + .name = "745", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Goldfinger", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC750 (G3) */ + { + .name = "750", + .pvr = CPU_PPC_74x, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER4p */ - { - .name = "POWER4+", - .pvr = CPU_PPC_POWER4P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER4, - .flags = PPC_FLAGS_POWER4, - .msr_mask = xxx, - }, + /* MPC755 (G3) */ + { + .name = "755", + .pvr = CPU_PPC_755, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC740P (G3) */ + { + .name = "740p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + { + .name = "Conan/Doyle", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER5 */ - { - .name = "POWER5", - .pvr = CPU_PPC_POWER5, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, + /* MPC745P (G3) */ + { + .name = "745p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* MPC750P (G3) */ + { + .name = "750p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* POWER5+ */ - { - .name = "POWER5+", - .pvr = CPU_PPC_POWER5P, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER5, - .flags = PPC_FLAGS_POWER5, - .msr_mask = xxx, - }, + /* MPC755P (G3) */ + { + .name = "755p", + .pvr = CPU_PPC_74xP, + .pvr_mask = 0xFFFFF000, + .insns_flags = PPC_INSNS_7x5, + .flags = PPC_FLAGS_7x5, + .msr_mask = 0x000000000007FF77, + }, #endif + /* IBM 750CXe (G3 embedded) */ + { + .name = "750cxe", + .pvr = CPU_PPC_750CXE, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750FX (G3 embedded) */ + { + .name = "750fx", + .pvr = CPU_PPC_750FX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, + /* IBM 750GX (G3 embedded) */ + { + .name = "750gx", + .pvr = CPU_PPC_750GX, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_7x0, + .flags = PPC_FLAGS_7x0, + .msr_mask = 0x000000000007FF77, + }, #if defined (TODO) - /* PPC 970 */ - { - .name = "970", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970, - .flags = PPC_FLAGS_970, - .msr_mask = 0x900000000204FF36, - }, + /* generic G4 */ + { + .name = "G4", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* PPC 970FX (G5) */ - { - .name = "970fx", - .pvr = CPU_PPC_970FX, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_970FX, - .flags = PPC_FLAGS_970FX, - .msr_mask = 0x800000000204FF36, - }, -#endif -#if defined (TODO) - /* RS64 (Apache/A35) */ - /* This one seems to support the whole POWER2 instruction set - * and the PowerPC 64 one. - */ - { - .name = "RS64", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Apache", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A35", - .pvr = CPU_PPC_RS64, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7400 (G4) */ + { + .name = "7400", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Max", + .pvr = CPU_PPC_7400, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* RS64-II (NorthStar/A50) */ - { - .name = "RS64-II", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "NortStar", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "A50", - .pvr = CPU_PPC_RS64II, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7410 (G4) */ + { + .name = "7410", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Nitro", + .pvr = CPU_PPC_7410, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif + /* XXX: 7441 */ + /* XXX: 7445 */ + /* XXX: 7447 */ + /* XXX: 7447A */ #if defined (TODO) - /* RS64-III (Pulsar) */ - { - .name = "RS64-III", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "Pulsar", - .pvr = CPU_PPC_RS64III, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7450 (G4) */ + { + .name = "7450", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Vger", + .pvr = CPU_PPC_7450, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif + /* XXX: 7451 */ #if defined (TODO) - /* RS64-IV (IceStar/IStar/SStar) */ - { - .name = "RS64-IV", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IceStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "IStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, - { - .name = "SStar", - .pvr = CPU_PPC_RS64IV, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_RS64, - .flags = PPC_FLAGS_RS64, - .msr_mask = xxx, - }, + /* PowerPC 7455 (G4) */ + { + .name = "7455", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 6", + .pvr = CPU_PPC_7455, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif - /* POWER */ #if defined (TODO) - /* Original POWER */ - { - .name = "POWER", - .pvr = CPU_POWER, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, + /* PowerPC 7457 (G4) */ + { + .name = "7457", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7", + .pvr = CPU_PPC_7457, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif #if defined (TODO) - /* POWER2 */ - { - .name = "POWER2", - .pvr = CPU_POWER2, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_POWER, - .flags = PPC_FLAGS_POWER, - .msr_mask = xxx, - }, + /* PowerPC 7457A (G4) */ + { + .name = "7457A", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, + { + .name = "Apollo 7 PM", + .pvr = CPU_PPC_7457A, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_74xx, + .flags = PPC_FLAGS_74xx, + .msr_mask = 0x000000000205FF77, + }, #endif - /* Generic PowerPCs */ + /* 64 bits PowerPC */ #if defined (TODO) - { - .name = "ppc64", - .pvr = CPU_PPC_970, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC64, - .flags = PPC_FLAGS_PPC64, - .msr_mask = 0xA00000000204FF36, - }, + /* PowerPC 620 */ + { + .name = "620", + .pvr = CPU_PPC_620, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_620, + .flags = PPC_FLAGS_620, + .msr_mask = 0x800000000005FF73, + }, #endif - { - .name = "ppc32", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, - /* Fallback */ - { - .name = "ppc", - .pvr = CPU_PPC_604, - .pvr_mask = 0xFFFF0000, - .insns_flags = PPC_INSNS_PPC32, - .flags = PPC_FLAGS_PPC32, - .msr_mask = 0x000000000005FF77, - }, -}; +#if defined (TODO) + /* PowerPC 630 (POWER3) */ + { + .name = "630", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } + { + .name = "POWER3", + .pvr = CPU_PPC_630, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_630, + .flags = PPC_FLAGS_630, + .msr_mask = xxx, + } +#endif +#if defined (TODO) + /* PowerPC 631 (Power 3+)*/ + { + .name = "631", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, + { + .name = "POWER3+", + .pvr = CPU_PPC_631, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_631, + .flags = PPC_FLAGS_631, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4 */ + { + .name = "POWER4", + .pvr = CPU_PPC_POWER4, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER4p */ + { + .name = "POWER4+", + .pvr = CPU_PPC_POWER4P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER4, + .flags = PPC_FLAGS_POWER4, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5 */ + { + .name = "POWER5", + .pvr = CPU_PPC_POWER5, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER5+ */ + { + .name = "POWER5+", + .pvr = CPU_PPC_POWER5P, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER5, + .flags = PPC_FLAGS_POWER5, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* PowerPC 970 */ + { + .name = "970", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970, + .flags = PPC_FLAGS_970, + .msr_mask = 0x900000000204FF36, + }, +#endif +#if defined (TODO) + /* PowerPC 970FX (G5) */ + { + .name = "970fx", + .pvr = CPU_PPC_970FX, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_970FX, + .flags = PPC_FLAGS_970FX, + .msr_mask = 0x800000000204FF36, + }, +#endif +#if defined (TODO) + /* RS64 (Apache/A35) */ + /* This one seems to support the whole POWER2 instruction set + * and the PowerPC 64 one. + */ + { + .name = "RS64", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Apache", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A35", + .pvr = CPU_PPC_RS64, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-II (NorthStar/A50) */ + { + .name = "RS64-II", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "NortStar", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "A50", + .pvr = CPU_PPC_RS64II, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-III (Pulsar) */ + { + .name = "RS64-III", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "Pulsar", + .pvr = CPU_PPC_RS64III, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* RS64-IV (IceStar/IStar/SStar) */ + { + .name = "RS64-IV", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IceStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "IStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, + { + .name = "SStar", + .pvr = CPU_PPC_RS64IV, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_RS64, + .flags = PPC_FLAGS_RS64, + .msr_mask = xxx, + }, +#endif + /* POWER */ +#if defined (TODO) + /* Original POWER */ + { + .name = "POWER", + .pvr = CPU_POWER, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif +#if defined (TODO) + /* POWER2 */ + { + .name = "POWER2", + .pvr = CPU_POWER2, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_POWER, + .flags = PPC_FLAGS_POWER, + .msr_mask = xxx, + }, +#endif + /* Generic PowerPCs */ +#if defined (TODO) + { + .name = "ppc64", + .pvr = CPU_PPC_970, + .pvr_mask = 0xFFFF0000, + .insns_flags = PPC_INSNS_PPC64, + .flags = PPC_FLAGS_PPC64, + .msr_mask = 0xA00000000204FF36, + }, +#endif + { + .name = "ppc32", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + /* Fallback */ + { + .name = "ppc", + .pvr = CPU_PPC_604, + .pvr_mask = 0xFFFFFFFF, + .insns_flags = PPC_INSNS_PPC32, + .flags = PPC_FLAGS_PPC32, + .msr_mask = 0x000000000005FF77, + }, + }; int ppc_find_by_name (const unsigned char *name, ppc_def_t **def) { @@ -2058,7 +3730,7 @@ void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) int i; for (i = 0; ; i++) { - (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n", + (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n", ppc_defs[i].name, ppc_defs[i].pvr, ppc_defs[i].pvr_mask); if (strcmp(ppc_defs[i].name, "ppc") == 0) -- cgit v1.2.1