]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
PPC core.
authorToni Wilen <twilen@winuae.net>
Thu, 7 Aug 2014 17:30:19 +0000 (20:30 +0300)
committerToni Wilen <twilen@winuae.net>
Thu, 7 Aug 2014 17:30:19 +0000 (20:30 +0300)
44 files changed:
ppc/pearpc/config.h [new file with mode: 0644]
ppc/pearpc/cpu/common.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_alu.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_alu.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_cpu.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_cpu.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_dec.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_dec.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_exc.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_exc.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_fpu.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_fpu.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_mmu.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_mmu.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_opc.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_opc.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_tools.h [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_vec.cpp [new file with mode: 0644]
ppc/pearpc/cpu/cpu_generic/ppc_vec.h [new file with mode: 0644]
ppc/pearpc/cpu/debug.h [new file with mode: 0644]
ppc/pearpc/cpu/mem.h [new file with mode: 0644]
ppc/pearpc/info.h [new file with mode: 0644]
ppc/pearpc/io/io.h [new file with mode: 0644]
ppc/pearpc/system/arch/generic/sysendian.h [new file with mode: 0644]
ppc/pearpc/system/arch/generic/sysfeatures.h [new file with mode: 0644]
ppc/pearpc/system/arch/sysendian.h [new file with mode: 0644]
ppc/pearpc/system/arch/sysfeatures.h [new file with mode: 0644]
ppc/pearpc/system/arch/x86/sysendian.h [new file with mode: 0644]
ppc/pearpc/system/arch/x86/sysfeatures.h [new file with mode: 0644]
ppc/pearpc/system/arch/x86/sysvaccel.cc [new file with mode: 0644]
ppc/pearpc/system/arch/x86/vaccel.S [new file with mode: 0644]
ppc/pearpc/system/arch/x86_64/sysendian.h [new file with mode: 0644]
ppc/pearpc/system/arch/x86_64/sysfeatures.h [new file with mode: 0644]
ppc/pearpc/system/arch/x86_64/sysvaccel.cc [new file with mode: 0644]
ppc/pearpc/system/systhread.h [new file with mode: 0644]
ppc/pearpc/system/types.h [new file with mode: 0644]
ppc/pearpc/tools/debug.h [new file with mode: 0644]
ppc/pearpc/tools/endianess.h [new file with mode: 0644]
ppc/pearpc/tools/snprintf.h [new file with mode: 0644]
ppc/pearpc/uaeglue.cpp [new file with mode: 0644]
ppc/ppc.cpp [new file with mode: 0644]
ppc/ppcd.cpp [new file with mode: 0644]
ppc/ppcd.h [new file with mode: 0644]

diff --git a/ppc/pearpc/config.h b/ppc/pearpc/config.h
new file mode 100644 (file)
index 0000000..d8bf6f5
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifdef WIN64
+#define SYSTEM_ARCH_SPECIFIC_ENDIAN_DIR "system/arch/x86_64/sysendian.h"
+#else
+#define SYSTEM_ARCH_SPECIFIC_ENDIAN_DIR "system/arch/x86/sysendian.h"
+#endif
+
+#define HOST_ENDIANESS HOST_ENDIANESS_LE
diff --git a/ppc/pearpc/cpu/common.h b/ppc/pearpc/cpu/common.h
new file mode 100644 (file)
index 0000000..54ba399
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ *     PearPC
+ *     common.h
+ *
+ *     Copyright (C) 2003-2006 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CPU_COMMON_H__
+#define __CPU_COMMON_H__
+
+#include <stddef.h>
+#include "system/types.h"
+
+typedef union Vector_t {
+        uint64 d[2];
+        sint64 sd[2];
+        float f[4];
+        uint32 w[4];
+        sint32 sw[4];
+        uint16 h[8];
+        sint16 sh[8];
+        uint8 b[16];
+        sint8 sb[16];
+} Vector_t;
+
+/*
+cr: .67
+ 0- 3 cr0
+ 4- 7 cr1
+ 8-11 cr2
+12-15 cr3
+16-19 cr4
+20-23 cr5
+24-27 cr6
+28-31 cr7
+*/
+
+#define CR_CR0(v) ((v)>>28)
+#define CR_CR1(v) (((v)>>24)&0xf)
+#define CR_CRx(v, x) (((v)>>(4*(7-(x))))&0xf)
+
+/*
+cr0 bits: .68
+lt
+gt
+eq
+so
+*/
+
+#define CR_CR0_LT (1<<31)
+#define CR_CR0_GT (1<<30)
+#define CR_CR0_EQ (1<<29)
+#define CR_CR0_SO (1<<28)
+
+/*
+cr1 bits: .68
+4 Floating-point exception (FX)
+5 Floating-point enabled exception (FEX)
+6 Floating-point invalid exception (VX)
+7 Floating-point overflow exception (OX)
+*/
+
+#define CR_CR1_FX (1<<27)
+#define CR_CR1_FEX (1<<26)
+#define CR_CR1_VX (1<<25)
+#define CR_CR1_OX (1<<24)
+
+/*
+FPSCR bits: .70
+
+*/
+#define FPSCR_FX (1<<31)
+#define FPSCR_FEX (1<<30)
+#define FPSCR_VX (1<<29)
+#define FPSCR_OX (1<<28)
+#define FPSCR_UX (1<<27)
+#define FPSCR_ZX (1<<26)
+#define FPSCR_XX (1<<25)
+#define FPSCR_VXSNAN (1<<24)
+#define FPSCR_VXISI (1<<23)
+#define FPSCR_VXIDI (1<<22)
+#define FPSCR_VXZDZ (1<<21)
+#define FPSCR_VXIMZ (1<<20)
+#define FPSCR_VXVC (1<<19)
+#define FPSCR_FR (1<<18)
+#define FPSCR_FI (1<<17)
+
+#define FPSCR_FPRF(v) (((v)>>12)&0x1f)
+
+#define FPSCR_res0 (1<<11)
+#define FPSCR_VXSOFT (1<<10)
+#define FPSCR_VXSQRT (1<<9)
+#define FPSCR_VXCVI (1<<8)
+#define FPSCR_VXVE (1<<7)
+#define FPSCR_VXOE (1<<6)
+#define FPSCR_VXUE (1<<5)
+#define FPSCR_VXZE (1<<4)
+#define FPSCR_VXXE (1<<3)
+#define FPSCR_VXNI (1<<2)
+#define FPSCR_RN(v) ((v)&3)
+
+#define FPSCR_RN_NEAR 0
+#define FPSCR_RN_ZERO 1
+#define FPSCR_RN_PINF 2
+#define FPSCR_RN_MINF 3 
+
+/*
+VSCR bits:
+        sat = summary saturation
+        nj = non-java floating-point mode
+*/
+#define VSCR_SAT 1
+#define VSCR_NJ (1<<16)
+
+/*
+xer bits:
+0 so
+1 ov
+2 carry
+3-24 res
+25-31 number of bytes for lswx/stswx
+*/
+
+#define XER_SO (1<<31)
+#define XER_OV (1<<30)
+#define XER_CA (1<<29)
+#define XER_n(v) ((v)&0x7f)
+
+/*
+msr: .83
+0-12 res
+13   POW       power management enabled
+14     res
+15     ILE     exception little-endian mode
+16     EE      enable external interrupt
+17     PR      privilege level (0=sv)
+18     FP      floating point avail
+19     ME      maschine check exception enable
+20     FE0     floation point exception mode 0
+21     SE   single step enable
+22     BE      branch trace enable
+23     FE1     floation point exception mode 1
+24     res
+25   IP        exception prefix
+26   IR   intruction address translation
+27   DR   data address translation
+28-29res
+30     RI      recoverable exception
+31     LE   little endian mode
+
+*/
+
+#define MSR_UNKNOWN    (1<<30)
+#define MSR_UNKNOWN2   (1<<27)
+#define MSR_VEC                (1<<25)
+#define MSR_KEY                (1<<19)         // 603e
+#define MSR_POW                (1<<18)
+#define MSR_TGPR       (1<<15)         // 603(e)
+#define MSR_ILE                (1<<16)
+#define MSR_EE         (1<<15)
+#define MSR_PR         (1<<14)
+#define MSR_FP         (1<<13)
+#define MSR_ME         (1<<12)
+#define MSR_FE0                (1<<11)
+#define MSR_SE         (1<<10)
+#define MSR_BE         (1<<9)
+#define MSR_FE1                (1<<8)
+#define MSR_IP         (1<<6)
+#define MSR_IR         (1<<5)
+#define MSR_DR         (1<<4)
+#define MSR_PM         (1<<2)
+#define MSR_RI         (1<<1)
+#define MSR_LE         (1<<0)
+
+//#define PPC_CPU_UNSUPPORTED_MSR_BITS (/*MSR_POW|*/MSR_ILE|MSR_BE|MSR_IP|MSR_LE)
+#define PPC_CPU_UNSUPPORTED_MSR_BITS (~(MSR_POW | MSR_UNKNOWN | MSR_UNKNOWN2 | MSR_VEC | MSR_EE | MSR_PR | MSR_FP | MSR_ME | MSR_FE0 | MSR_SE | MSR_FE1 | MSR_IR | MSR_DR | MSR_RI | MSR_IP))
+
+#define MSR_RFI_SAVE_MASK (0x87c0ff73) // was ff73
+
+/*
+BAT Register: .88
+upper:
+0-14  BEPI Block effective page index.
+15-18 res
+19-29 BL   Block length.
+30    Vs   Supervisor mode valid bit.
+31    Vp   User mode valid bit.
+lower:
+0-14  BRPN This field is used in conjunction with the BL field to generate highorder bits of the physical address of the block.
+15-24 res
+25-28 WIMG Memory/cache access mode bits
+29    res
+30-31 PP   Protection bits for block.
+
+BAT Area
+Length         BL Encoding
+128 Kbytes     000 0000 0000
+256 Kbytes     000 0000 0001
+512 Kbytes     000 0000 0011
+1 Mbyte                000 0000 0111
+2 Mbytes       000 0000 1111
+4 Mbytes       000 0001 1111
+8 Mbytes       000 0011 1111
+16 Mbytes      000 0111 1111
+32 Mbytes      000 1111 1111
+64 Mbytes      001 1111 1111
+128 Mbytes     011 1111 1111
+256 Mbytes     111 1111 1111
+*/
+
+#define BATU_BEPI(v) ((v)&0xfffe0000)
+#define BATU_BL(v)   (((v)&0x1ffc)>>2)
+#define BATU_Vs      (1<<1)
+#define BATU_Vp      (1)
+#define BATL_BRPN(v) ((v)&0xfffe0000)
+
+#define BAT_EA_OFFSET(v) ((v)&0x1ffff)
+#define BAT_EA_11(v)     ((v)&0x0ffe0000)
+#define BAT_EA_4(v)      ((v)&0xf0000000)
+
+/*
+sdr1: .91
+0-15 The high-order 16 bits of the 32-bit physical address of the page table
+16-22 res
+23-31 Mask for page table address
+*/
+
+#define SDR1_HTABORG(v) (((v)>>16)&0xffff)
+#define SDR1_HTABMASK(v) ((v)&0x1ff)
+#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff)
+
+/*
+sr: .94
+0    T=0:
+1    Ks   sv prot
+2    Kp   user prot
+3    N    No execute
+4-7  res
+8-31 VSID Virtual Segment ID
+
+0     T=1:
+1     Ks
+2     Kp
+3-11  BUID       Bus Unit ID
+12-31 CNTRL_SPEC
+ */
+#define SR_T                   (1<<31)
+#define SR_Ks                  (1<<30)
+#define SR_Kp                  (1<<29)
+#define SR_N                   (1<<28)
+#define SR_VSID(v)             ((v)&0xffffff)
+#define SR_BUID(v)             (((v)>>20)&0x1ff)
+#define SR_CNTRL_SPEC(v)       ((v)&0xfffff)
+
+#define EA_SR(v)               (((v)>>28)&0xf)
+#define EA_PageIndex(v)                (((v)>>12)&0xffff)
+#define EA_Offset(v)           ((v)&0xfff)
+#define EA_API(v)              (((v)>>22)&0x3f)
+
+#define PA_RPN(v)              (((v)>>12)&0xfffff)
+#define PA_Offset(v)           ((v)&0xfff)
+
+/*
+PTE: .364
+0     V
+1-24  VSID
+25    H
+26-31 API
+*/
+
+#define PTE1_V       (1<<31)
+#define PTE1_VSID(v) (((v)>>7)&0xffffff)
+#define PTE1_H       (1<<6)
+#define PTE1_API(v)  ((v)&0x3f)
+
+#define PTE2_RPN(v)  ((v)&0xfffff000)
+#define PTE2_R       (1<<8)
+#define PTE2_C       (1<<7)
+#define PTE2_WIMG(v) (((v)>>3)&0xf)
+#define PTE2_PP(v)   ((v)&3)
+
+#define PPC_L1_CACHE_LINE_SIZE         32
+#define PPC_LG_L1_CACHE_LINE_SIZE      5
+#define PPC_MAX_L1_COPY_PREFETCH       4
+
+/*
+ *     special registers
+ */
+#define HID0   1008    /* Checkstop and misc enables */
+#define HID1   1009    /* Clock configuration */
+#define IABR   1010    /* Instruction address breakpoint register */
+#define ICTRL  1011    /* Instruction Cache Control */
+#define LDSTDB 1012    /* Load/Store Debug */
+#define DABR   1013    /* Data address breakpoint register */
+#define MSSCR0 1014    /* Memory subsystem control */
+#define MSSCR1 1015    /* Memory subsystem debug */
+#define MSSSR0 1015    /* Memory Subsystem Status */
+#define LDSTCR 1016    /* Load/Store Status/Control */
+#define L2CR2  1016    /* L2 Cache control 2 */
+#define L2CR   1017    /* L2 Cache control */
+#define L3CR   1018    /* L3 Cache control */
+#define ICTC   1019    /* I-cache throttling control */
+#define THRM1  1020    /* Thermal management 1 */
+#define THRM2  1021    /* Thermal management 2 */
+#define THRM3  1022    /* Thermal management 3 */
+#define PIR    1023    /* Processor ID Register */
+
+//;    hid0 bits
+#define HID0_emcp      0
+#define HID0_emcpm     0x80000000
+#define HID0_dbp       1
+#define HID0_dbpm      0x40000000
+#define HID0_eba       2
+#define HID0_ebam      0x20000000
+#define HID0_ebd       3
+#define HID0_ebdm      0x10000000
+#define HID0_sbclk     4
+#define HID0_sbclkm    0x08000000
+#define HID0_eclk      6
+#define HID0_eclkm     0x02000000
+#define HID0_par       7
+#define HID0_parm      0x01000000
+#define HID0_sten      7
+#define HID0_stenm     0x01000000
+#define HID0_doze      8
+#define HID0_dozem     0x00800000
+#define HID0_nap       9
+#define HID0_napm      0x00400000
+#define HID0_sleep     10
+#define HID0_sleepm    0x00200000
+#define HID0_dpm       11
+#define HID0_dpmm      0x00100000
+#define HID0_riseg     12
+#define HID0_risegm    0x00080000
+#define HID0_eiec      13
+#define HID0_eiecm     0x00040000
+#define HID0_mum       14
+#define HID0_mumm      0x00020000
+#define HID0_nhr       15
+#define HID0_nhrm      0x00010000
+#define HID0_ice       16
+#define HID0_icem      0x00008000
+#define HID0_dce       17
+#define HID0_dcem      0x00004000
+#define HID0_ilock     18
+#define HID0_ilockm    0x00002000
+#define HID0_dlock     19
+#define HID0_dlockm    0x00001000
+#define HID0_icfi      20
+#define HID0_icfim     0x00000800
+#define HID0_dcfi      21
+#define HID0_dcfim     0x00000400
+#define HID0_spd       22
+#define HID0_spdm      0x00000200
+#define HID0_sge       24
+#define HID0_sgem      0x00000080
+#define HID0_dcfa      25
+#define HID0_dcfam     0x00000040
+#define HID0_btic      26
+#define HID0_bticm     0x00000020
+#define HID0_lrstk     27
+#define HID0_lrstkm    0x00000010
+#define HID0_abe       28
+#define HID0_abem      0x00000008
+#define HID0_fold      28
+#define HID0_foldm     0x00000008
+#define HID0_bht       29
+#define HID0_bhtm      0x00000004
+#define HID0_nopdst    30
+#define HID0_nopdstm   0x00000002
+#define HID0_nopti     31
+#define HID0_noptim    0x00000001
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu.h b/ppc/pearpc/cpu/cpu.h
new file mode 100644 (file)
index 0000000..ba96934
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *     PearPC
+ *     cpu.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __CPU_H__
+#define __CPU_H__
+
+#include "system/types.h"
+
+uint64 ppc_get_clock_frequency(int cpu);
+uint64 ppc_get_bus_frequency(int cpu);
+uint64 ppc_get_timebase_frequency(int cpu);
+
+bool   ppc_cpu_init(uint32);
+void   ppc_cpu_init_config();
+
+void   ppc_cpu_stop();
+void   ppc_cpu_wakeup();
+
+void   ppc_machine_check_exception();
+
+void   ppc_cpu_raise_ext_exception();
+void   ppc_cpu_cancel_ext_exception();
+
+/*
+ * May only be called from within a CPU thread.
+ */
+
+void   ppc_cpu_run();
+uint32 ppc_cpu_get_gpr(int cpu, int i);
+void   ppc_cpu_set_gpr(int cpu, int i, uint32 newvalue);
+void   ppc_cpu_set_msr(int cpu, uint32 newvalue);
+void   ppc_cpu_set_pc(int cpu, uint32 newvalue);
+uint32 ppc_cpu_get_pc(int cpu);
+uint32 ppc_cpu_get_pvr(int cpu);
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_alu.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_alu.cpp
new file mode 100644 (file)
index 0000000..eceeb17
--- /dev/null
@@ -0,0 +1,1374 @@
+/*
+ *     PearPC
+ *     ppc_alu.cc
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "debug/tracers.h"
+#include "cpu/debug.h"
+#include "ppc_alu.h"
+#include "ppc_dec.h"
+#include "ppc_exc.h"
+#include "ppc_cpu.h"
+#include "ppc_opc.h"
+#include "ppc_tools.h"
+
+static inline uint32 ppc_mask(int MB, int ME)
+{
+       uint32 mask;
+       if (MB <= ME) {
+               if (ME-MB == 31) {
+                       mask = 0xffffffff;
+               } else {
+                       mask = ((1<<(ME-MB+1))-1)<<(31-ME);
+               }
+       } else {
+               mask = ppc_word_rotl((1<<(32-MB+ME+1))-1, 31-ME);
+       }
+       return mask;
+}
+
+/*
+ *     addx            Add
+ *     .422
+ */
+void ppc_opc_addx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     addox           Add with Overflow
+ *     .422
+ */
+void ppc_opc_addox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       gCPU.gpr[rD] = gCPU.gpr[rA] + gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("addox unimplemented\n");
+}
+/*
+ *     addcx           Add Carrying
+ *     .423
+ */
+void ppc_opc_addcx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       gCPU.gpr[rD] = a + gCPU.gpr[rB];
+       // update xer
+       if (gCPU.gpr[rD] < a) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     addcox          Add Carrying with Overflow
+ *     .423
+ */
+void ppc_opc_addcox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       gCPU.gpr[rD] = a + gCPU.gpr[rB];
+       // update xer
+       if (gCPU.gpr[rD] < a) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("addcox unimplemented\n");
+}
+/*
+ *     addex           Add Extended
+ *     .424
+ */
+void ppc_opc_addex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + b + ca;
+       // update xer
+       if (ppc_carry_3(a, b, ca)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     addeox          Add Extended with Overflow
+ *     .424
+ */
+void ppc_opc_addeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + b + ca;
+       // update xer
+       if (ppc_carry_3(a, b, ca)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("addeox unimplemented\n");
+}
+/*
+ *     addi            Add Immediate
+ *     .425
+ */
+void ppc_opc_addi()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm;
+}
+/*
+ *     addic           Add Immediate Carrying
+ *     .426
+ */
+void ppc_opc_addic()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint32 a = gCPU.gpr[rA];
+       gCPU.gpr[rD] = a + imm; 
+       // update XER
+       if (gCPU.gpr[rD] < a) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+}
+/*
+ *     addic.          Add Immediate Carrying and Record
+ *     .427
+ */
+void ppc_opc_addic_()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint32 a = gCPU.gpr[rA];
+       gCPU.gpr[rD] = a + imm;
+       // update XER
+       if (gCPU.gpr[rD] < a) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       // update cr0 flags
+       ppc_update_cr0(gCPU.gpr[rD]);
+}
+/*
+ *     addis           Add Immediate Shifted
+ *     .428
+ */
+void ppc_opc_addis()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rD, rA, imm);
+       gCPU.gpr[rD] = (rA ? gCPU.gpr[rA] : 0) + imm;
+}
+/*
+ *     addmex          Add to Minus One Extended
+ *     .429
+ */
+void ppc_opc_addmex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + ca + 0xffffffff;
+       if (a || ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     addmeox         Add to Minus One Extended with Overflow
+ *     .429
+ */
+void ppc_opc_addmeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + ca + 0xffffffff;
+       if (a || ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("addmeox unimplemented\n");
+}
+/*
+ *     addzex          Add to Zero Extended
+ *     .430
+ */
+void ppc_opc_addzex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + ca;
+       if ((a == 0xffffffff) && ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       // update xer
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     addzeox         Add to Zero Extended with Overflow
+ *     .430
+ */
+void ppc_opc_addzeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = a + ca;
+       if ((a == 0xffffffff) && ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       // update xer
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("addzeox unimplemented\n");
+}
+
+/*
+ *     andx            AND
+ *     .431
+ */
+void ppc_opc_andx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = gCPU.gpr[rS] & gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     andcx           AND with Complement
+ *     .432
+ */
+void ppc_opc_andcx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = gCPU.gpr[rS] & ~gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     andi.           AND Immediate
+ *     .433
+ */
+void ppc_opc_andi_()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] & imm;
+       // update cr0 flags
+       ppc_update_cr0(gCPU.gpr[rA]);
+}
+/*
+ *     andis.          AND Immediate Shifted
+ *     .434
+ */
+void ppc_opc_andis_()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] & imm;
+       // update cr0 flags
+       ppc_update_cr0(gCPU.gpr[rA]);
+}
+
+/*
+ *     cmp             Compare
+ *     .442
+ */
+static uint32 ppc_cmp_and_mask[8] = {
+       0xfffffff0,
+       0xffffff0f,
+       0xfffff0ff,
+       0xffff0fff,
+       0xfff0ffff,
+       0xff0fffff,
+       0xf0ffffff,
+       0x0fffffff,
+};
+
+void ppc_opc_cmp()
+{
+       uint32 cr;
+       int rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB);
+       cr >>= 2;
+       sint32 a = gCPU.gpr[rA];
+       sint32 b = gCPU.gpr[rB];
+       uint32 c;
+       if (a < b) {
+               c = 8;
+       } else if (a > b) {
+               c = 4;
+       } else {
+               c = 2;
+       }
+       if (gCPU.xer & XER_SO) c |= 1;
+       cr = 7-cr;
+       gCPU.cr &= ppc_cmp_and_mask[cr];
+       gCPU.cr |= c<<(cr*4);
+}
+/*
+ *     cmpi            Compare Immediate
+ *     .443
+ */
+void ppc_opc_cmpi()
+{
+       uint32 cr;
+       int rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, cr, rA, imm);
+       cr >>= 2;
+       sint32 a = gCPU.gpr[rA];
+       sint32 b = imm;
+       uint32 c;
+/*     if (!VALGRIND_CHECK_READABLE(a, sizeof a)) {
+               ht_printf("%08x <--i\n", gCPU.pc);
+//             SINGLESTEP("");
+       }*/
+       if (a < b) {
+               c = 8;
+       } else if (a > b) {
+               c = 4;
+       } else {
+               c = 2;
+       }
+       if (gCPU.xer & XER_SO) c |= 1;
+       cr = 7-cr;
+       gCPU.cr &= ppc_cmp_and_mask[cr];
+       gCPU.cr |= c<<(cr*4);
+}
+/*
+ *     cmpl            Compare Logical
+ *     .444
+ */
+void ppc_opc_cmpl()
+{
+       uint32 cr;
+       int rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, cr, rA, rB);
+       cr >>= 2;
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       uint32 c;
+       if (a < b) {
+               c = 8;
+       } else if (a > b) {
+               c = 4;
+       } else {
+               c = 2;
+       }
+       if (gCPU.xer & XER_SO) c |= 1;
+       cr = 7-cr;
+       gCPU.cr &= ppc_cmp_and_mask[cr];
+       gCPU.cr |= c<<(cr*4);
+}
+/*
+ *     cmpli           Compare Logical Immediate
+ *     .445
+ */
+void ppc_opc_cmpli()
+{
+       uint32 cr;
+       int rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, cr, rA, imm);
+       cr >>= 2;
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = imm;
+       uint32 c;
+       if (a < b) {
+               c = 8;
+       } else if (a > b) {
+               c = 4;
+       } else {
+               c = 2;
+       }
+       if (gCPU.xer & XER_SO) c |= 1;
+       cr = 7-cr;
+       gCPU.cr &= ppc_cmp_and_mask[cr];
+       gCPU.cr |= c<<(cr*4);
+}
+
+/*
+ *     cntlzwx         Count Leading Zeros Word
+ *     .447
+ */
+void ppc_opc_cntlzwx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       PPC_OPC_ASSERT(rB==0);
+       uint32 n=0;
+       uint32 x=0x80000000;
+       uint32 v=gCPU.gpr[rS];
+       while (!(v & x)) {
+               n++;
+               if (n==32) break;
+               x>>=1;
+       }
+       gCPU.gpr[rA] = n;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     crand           Condition Register AND
+ *     .448
+ */
+void ppc_opc_crand()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if ((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB)))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     crandc          Condition Register AND with Complement
+ *     .449
+ */
+void ppc_opc_crandc()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB)))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     creqv           Condition Register Equivalent
+ *     .450
+ */
+void ppc_opc_creqv()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if (((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))
+         || (!(gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     crnand          Condition Register NAND
+ *     .451
+ */
+void ppc_opc_crnand()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if (!((gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     crnor           Condition Register NOR
+ *     .452
+ */
+void ppc_opc_crnor()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       uint32 t = (1<<(31-crA)) | (1<<(31-crB));
+       if (!(gCPU.cr & t)) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     cror            Condition Register OR
+ *     .453
+ */
+void ppc_opc_cror()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       uint32 t = (1<<(31-crA)) | (1<<(31-crB));
+       if (gCPU.cr & t) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     crorc           Condition Register OR with Complement
+ *     .454
+ */
+void ppc_opc_crorc()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if ((gCPU.cr & (1<<(31-crA))) || !(gCPU.cr & (1<<(31-crB)))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+/*
+ *     crxor           Condition Register XOR
+ *     .448
+ */
+void ppc_opc_crxor()
+{
+       int crD, crA, crB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crA, crB);
+       if ((!(gCPU.cr & (1<<(31-crA))) && (gCPU.cr & (1<<(31-crB))))
+         || ((gCPU.cr & (1<<(31-crA))) && !(gCPU.cr & (1<<(31-crB))))) {
+               gCPU.cr |= (1<<(31-crD));
+       } else {
+               gCPU.cr &= ~(1<<(31-crD));
+       }
+}
+
+/*
+ *     divwx           Divide Word
+ *     .470
+ */
+void ppc_opc_divwx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       if (!gCPU.gpr[rB]) {
+               PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc);
+               SINGLESTEP("");
+       }
+       sint32 a = gCPU.gpr[rA];
+       sint32 b = gCPU.gpr[rB];
+       gCPU.gpr[rD] = a / b;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     divwox          Divide Word with Overflow
+ *     .470
+ */
+void ppc_opc_divwox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       if (!gCPU.gpr[rB]) {
+               PPC_ALU_ERR("division by zero\n");
+       }
+       sint32 a = gCPU.gpr[rA];
+       sint32 b = gCPU.gpr[rB];
+       gCPU.gpr[rD] = a / b;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("divwox unimplemented\n");
+}
+/*
+ *     divwux          Divide Word Unsigned
+ *     .472
+ */
+void ppc_opc_divwux()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       if (!gCPU.gpr[rB]) {
+               PPC_ALU_WARN("division by zero @%08x\n", gCPU.pc);
+               SINGLESTEP("");
+       }
+       gCPU.gpr[rD] = gCPU.gpr[rA] / gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     divwuox         Divide Word Unsigned with Overflow
+ *     .472
+ */
+void ppc_opc_divwuox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       if (!gCPU.gpr[rB]) {
+//             PPC_ALU_ERR("division by zero\n");
+       }
+       gCPU.gpr[rD] = gCPU.gpr[rA] / gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("divwuox unimplemented\n");
+}
+
+/*
+ *     eqvx            Equivalent
+ *     .480
+ */
+void ppc_opc_eqvx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = ~(gCPU.gpr[rS] ^ gCPU.gpr[rB]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     extsbx          Extend Sign Byte
+ *     .481
+ */
+void ppc_opc_extsbx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       PPC_OPC_ASSERT(rB==0);
+       gCPU.gpr[rA] = gCPU.gpr[rS];
+       if (gCPU.gpr[rA] & 0x80) {
+               gCPU.gpr[rA] |= 0xffffff00;
+       } else {
+               gCPU.gpr[rA] &= ~0xffffff00;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     extshx          Extend Sign Half Word
+ *     .482
+ */
+void ppc_opc_extshx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       PPC_OPC_ASSERT(rB==0);
+       gCPU.gpr[rA] = gCPU.gpr[rS];
+       if (gCPU.gpr[rA] & 0x8000) {
+               gCPU.gpr[rA] |= 0xffff0000;
+       } else {
+               gCPU.gpr[rA] &= ~0xffff0000;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     mulhwx          Multiply High Word
+ *     .595
+ */
+void ppc_opc_mulhwx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       sint64 a = (sint32)gCPU.gpr[rA];
+       sint64 b = (sint32)gCPU.gpr[rB];
+       sint64 c = a*b;
+       gCPU.gpr[rD] = ((uint64)c)>>32;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+//             PPC_ALU_WARN("mulhw. correct?\n");
+       }
+}
+/*
+ *     mulhwux         Multiply High Word Unsigned
+ *     .596
+ */
+void ppc_opc_mulhwux()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint64 a = gCPU.gpr[rA];
+       uint64 b = gCPU.gpr[rB];
+       uint64 c = a*b;
+       gCPU.gpr[rD] = c>>32;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     mulli           Multiply Low Immediate
+ *     .598
+ */
+void ppc_opc_mulli()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       // FIXME: signed / unsigned correct?
+       gCPU.gpr[rD] = gCPU.gpr[rA] * imm;
+}
+/*
+ *     mullwx          Multiply Low Word
+ *     .599
+ */
+void ppc_opc_mullwx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       gCPU.gpr[rD] = gCPU.gpr[rA] * gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       if (gCPU.current_opc & PPC_OPC_OE) {
+               // update XER flags
+               PPC_ALU_ERR("mullwx unimplemented\n");
+       }
+}
+
+/*
+ *     nandx           NAND
+ *     .600
+ */
+void ppc_opc_nandx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = ~(gCPU.gpr[rS] & gCPU.gpr[rB]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     negx            Negate
+ *     .601
+ */
+void ppc_opc_negx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       gCPU.gpr[rD] = -gCPU.gpr[rA];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     negox           Negate with Overflow
+ *     .601
+ */
+void ppc_opc_negox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       gCPU.gpr[rD] = -gCPU.gpr[rA];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("negox unimplemented\n");
+}
+/*
+ *     norx            NOR
+ *     .602
+ */
+void ppc_opc_norx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = ~(gCPU.gpr[rS] | gCPU.gpr[rB]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     orx             OR
+ *     .603
+ */
+void ppc_opc_orx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = gCPU.gpr[rS] | gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     orcx            OR with Complement
+ *     .604
+ */
+void ppc_opc_orcx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = gCPU.gpr[rS] | ~gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     ori             OR Immediate
+ *     .605
+ */
+void ppc_opc_ori()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] | imm;
+}
+/*
+ *     oris            OR Immediate Shifted
+ *     .606
+ */
+void ppc_opc_oris()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] | imm;
+}
+
+/*
+ *     rlwimix         Rotate Left Word Immediate then Mask Insert
+ *     .617
+ */
+void ppc_opc_rlwimix()
+{
+       int rS, rA, SH, MB, ME;
+       PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, SH, MB, ME);
+       uint32 v = ppc_word_rotl(gCPU.gpr[rS], SH);
+       uint32 mask = ppc_mask(MB, ME);
+       gCPU.gpr[rA] = (v & mask) | (gCPU.gpr[rA] & ~mask);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     rlwinmx         Rotate Left Word Immediate then AND with Mask
+ *     .618
+ */
+void ppc_opc_rlwinmx()
+{
+       int rS, rA, SH, MB, ME;
+       PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, SH, MB, ME);
+       uint32 v = ppc_word_rotl(gCPU.gpr[rS], SH);
+       uint32 mask = ppc_mask(MB, ME);
+       gCPU.gpr[rA] = v & mask;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     rlwnmx          Rotate Left Word then AND with Mask
+ *     .620
+ */
+void ppc_opc_rlwnmx()
+{
+       int rS, rA, rB, MB, ME;
+       PPC_OPC_TEMPL_M(gCPU.current_opc, rS, rA, rB, MB, ME);
+       uint32 v = ppc_word_rotl(gCPU.gpr[rS], gCPU.gpr[rB]);
+       uint32 mask = ppc_mask(MB, ME);
+       gCPU.gpr[rA] = v & mask;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     slwx            Shift Left Word
+ *     .625
+ */
+void ppc_opc_slwx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       uint32 s = gCPU.gpr[rB] & 0x3f;
+       if (s > 31) {
+               gCPU.gpr[rA] = 0;
+       } else {
+               gCPU.gpr[rA] = gCPU.gpr[rS] << s;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     srawx           Shift Right Algebraic Word
+ *     .628
+ */
+void ppc_opc_srawx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       uint32 SH = gCPU.gpr[rB] & 0x3f;
+       gCPU.gpr[rA] = gCPU.gpr[rS];
+       gCPU.xer &= ~XER_CA;
+       if (gCPU.gpr[rA] & 0x80000000) {
+               uint32 ca = 0;
+               for (uint i=0; i < SH; i++) {
+                       if (gCPU.gpr[rA] & 1) ca = 1;
+                       gCPU.gpr[rA] >>= 1;
+                       gCPU.gpr[rA] |= 0x80000000;
+               }
+               if (ca) gCPU.xer |= XER_CA;
+       } else {
+               if (SH > 31) {
+                       gCPU.gpr[rA] = 0;
+               } else {
+                       gCPU.gpr[rA] >>= SH;
+               }
+       }     
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     srawix          Shift Right Algebraic Word Immediate
+ *     .629
+ */
+void ppc_opc_srawix()
+{
+       int rS, rA;
+       uint32 SH;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, SH);
+       gCPU.gpr[rA] = gCPU.gpr[rS];
+       gCPU.xer &= ~XER_CA;
+       if (gCPU.gpr[rA] & 0x80000000) {
+               uint32 ca = 0;
+               for (uint i=0; i < SH; i++) {
+                       if (gCPU.gpr[rA] & 1) ca = 1;
+                       gCPU.gpr[rA] >>= 1;
+                       gCPU.gpr[rA] |= 0x80000000;
+               }
+               if (ca) gCPU.xer |= XER_CA;
+       } else {
+               if (SH > 31) {
+                       gCPU.gpr[rA] = 0;
+               } else {
+                       gCPU.gpr[rA] >>= SH;
+               }
+       }     
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     srwx            Shift Right Word
+ *     .631
+ */
+void ppc_opc_srwx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       uint32 v = gCPU.gpr[rB] & 0x3f;
+       if (v > 31) {
+               gCPU.gpr[rA] = 0;
+       } else {
+               gCPU.gpr[rA] = gCPU.gpr[rS] >> v;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+
+/*
+ *     subfx           Subtract From
+ *     .666
+ */
+void ppc_opc_subfx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       gCPU.gpr[rD] = ~gCPU.gpr[rA] + gCPU.gpr[rB] + 1;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     subfox          Subtract From with Overflow
+ *     .666
+ */
+void ppc_opc_subfox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       gCPU.gpr[rD] = ~gCPU.gpr[rA] + gCPU.gpr[rB] + 1;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("subfox unimplemented\n");
+}
+/*
+ *     subfcx          Subtract From Carrying
+ *     .667
+ */
+void ppc_opc_subfcx()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       gCPU.gpr[rD] = ~a + b + 1;
+       // update xer
+       if (ppc_carry_3(~a, b, 1)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     subfcox         Subtract From Carrying with Overflow
+ *     .667
+ */
+void ppc_opc_subfcox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       gCPU.gpr[rD] = ~a + b + 1;
+       // update xer
+       if (ppc_carry_3(~a, b, 1)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("subfcox unimplemented\n");
+}
+/*
+ *     subfex          Subtract From Extended
+ *     .668
+ */
+void ppc_opc_subfex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + b + ca;
+       // update xer
+       if (ppc_carry_3(~a, b, ca)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     subfeox         Subtract From Extended with Overflow
+ *     .668
+ */
+void ppc_opc_subfeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + b + ca;
+       // update xer
+       if (ppc_carry_3(~a, b, ca)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("subfeox unimplemented\n");
+}
+/*
+ *     subfic          Subtract From Immediate Carrying
+ *     .669
+ */
+void ppc_opc_subfic()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint32 a = gCPU.gpr[rA];
+       gCPU.gpr[rD] = ~a + imm + 1;
+       // update XER
+       if (ppc_carry_3(~a, imm, 1)) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+}
+/*
+ *     subfmex         Subtract From Minus One Extended
+ *     .670
+ */
+void ppc_opc_subfmex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + ca + 0xffffffff;
+       // update XER
+       if ((a!=0xffffffff) || ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     subfmeox        Subtract From Minus One Extended with Overflow
+ *     .670
+ */
+void ppc_opc_subfmeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + ca + 0xffffffff;
+       // update XER
+       if ((a!=0xffffffff) || ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("subfmeox unimplemented\n");
+}
+/*
+ *     subfzex         Subtract From Zero Extended
+ *     .671
+ */
+void ppc_opc_subfzex()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + ca;
+       if (!a && ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+}
+/*
+ *     subfzeox        Subtract From Zero Extended with Overflow
+ *     .671
+ */
+void ppc_opc_subfzeox()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rB == 0);
+       uint32 a = gCPU.gpr[rA];
+       uint32 ca = ((gCPU.xer&XER_CA)?1:0);
+       gCPU.gpr[rD] = ~a + ca;
+       if (!a && ca) {
+               gCPU.xer |= XER_CA;
+       } else {
+               gCPU.xer &= ~XER_CA;
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rD]);
+       }
+       // update XER flags
+       PPC_ALU_ERR("subfzeox unimplemented\n");
+}
+
+/*
+ *     xorx            XOR
+ *     .680
+ */
+void ppc_opc_xorx()
+{
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.gpr[rA] = gCPU.gpr[rS] ^ gCPU.gpr[rB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr0 flags
+               ppc_update_cr0(gCPU.gpr[rA]);
+       }
+}
+/*
+ *     xori            XOR Immediate
+ *     .681
+ */
+void ppc_opc_xori()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_UImm(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] ^ imm;
+}
+/*
+ *     xoris           XOR Immediate Shifted
+ *     .682
+ */
+void ppc_opc_xoris()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_Shift16(gCPU.current_opc, rS, rA, imm);
+       gCPU.gpr[rA] = gCPU.gpr[rS] ^ imm;
+}
+
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_alu.h b/ppc/pearpc/cpu/cpu_generic/ppc_alu.h
new file mode 100644 (file)
index 0000000..aef4f2b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *     PearPC
+ *     ppc_alu.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_ALU_H__
+#define __PPC_ALU_H__
+
+void ppc_opc_addx();
+void ppc_opc_addcx();
+void ppc_opc_addex();
+void ppc_opc_addi();
+void ppc_opc_addic();
+void ppc_opc_addic_();
+void ppc_opc_addis();
+void ppc_opc_addmex();
+void ppc_opc_addzex();
+
+void ppc_opc_andx();
+void ppc_opc_andcx();
+void ppc_opc_andi_();
+void ppc_opc_andis_();
+
+void ppc_opc_cmp();
+void ppc_opc_cmpi();
+void ppc_opc_cmpl();
+void ppc_opc_cmpli();
+
+void ppc_opc_cntlzwx();
+
+void ppc_opc_crand();
+void ppc_opc_crandc();
+void ppc_opc_creqv();
+void ppc_opc_crnand();
+void ppc_opc_crnor();
+void ppc_opc_cror();
+void ppc_opc_crorc();
+void ppc_opc_crxor();
+
+void ppc_opc_divwx();
+void ppc_opc_divwux();
+
+void ppc_opc_eqvx();
+
+void ppc_opc_extsbx();
+void ppc_opc_extshx();
+
+void ppc_opc_mulhwx();
+void ppc_opc_mulhwux();
+void ppc_opc_mulli();
+void ppc_opc_mullwx();
+
+void ppc_opc_nandx();
+
+void ppc_opc_negx();
+void ppc_opc_norx();
+
+void ppc_opc_orx();
+void ppc_opc_orcx();
+void ppc_opc_ori();
+void ppc_opc_oris();
+
+void ppc_opc_rlwimix();
+void ppc_opc_rlwinmx();
+void ppc_opc_rlwnmx();
+
+void ppc_opc_slwx();
+void ppc_opc_srawx();
+void ppc_opc_srawix();
+void ppc_opc_srwx();
+
+void ppc_opc_subfx();
+void ppc_opc_subfcx();
+void ppc_opc_subfex();
+void ppc_opc_subfic();
+void ppc_opc_subfmex();
+void ppc_opc_subfzex();
+
+void ppc_opc_xorx();
+void ppc_opc_xori();
+void ppc_opc_xoris();
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_cpu.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_cpu.cpp
new file mode 100644 (file)
index 0000000..801be36
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *     PearPC
+ *     ppc_cpu.cc
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *      Portions Copyright (C) 2004 Apple Computer, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <cstring>
+#include <cstdio>
+
+#include "system/systhread.h"
+#include "system/arch/sysendian.h"
+//#include "tools/snprintf.h"
+#include "debug/tracers.h"
+#include "cpu/cpu.h"
+#include "cpu/debug.h"
+#include "info.h"
+//#include "io/pic/pic.h"
+//#include "debug/debugger.h"
+#include "debug/tracers.h"
+#include "ppc_cpu.h"
+#include "ppc_dec.h"
+#include "ppc_fpu.h"
+#include "ppc_exc.h"
+#include "ppc_mmu.h"
+#include "ppc_tools.h"
+#include "ppc.h"
+
+//#include "io/graphic/gcard.h"
+
+PPC_CPU_State gCPU;
+//Debugger *gDebugger;
+
+static bool gSinglestep = false;
+
+bool activate = false;
+static inline void ppc_debug_hook()
+{
+}
+
+sys_mutex exception_mutex;
+
+void ppc_cpu_atomic_raise_ext_exception()
+{
+       sys_lock_mutex(exception_mutex);
+       gCPU.ext_exception = true;
+       gCPU.exception_pending = true;
+       sys_unlock_mutex(exception_mutex);
+}
+
+void ppc_cpu_atomic_cancel_ext_exception()
+{
+       sys_lock_mutex(exception_mutex);
+       gCPU.ext_exception = false;
+       if (!gCPU.dec_exception) gCPU.exception_pending = false;
+       sys_unlock_mutex(exception_mutex);
+}
+
+void ppc_cpu_atomic_raise_dec_exception()
+{
+       sys_lock_mutex(exception_mutex);
+       gCPU.dec_exception = true;
+       gCPU.exception_pending = true;
+       sys_unlock_mutex(exception_mutex);
+}
+
+void ppc_cpu_wakeup()
+{
+}
+
+extern int ppc_cycle_count;
+void ppc_hsync_handler(void)
+{
+#if 0
+       if (!ppc_state)
+               return;
+       uint64 oldpdec = gCPU.pdec;
+       //gCPU.ptb += ppc_cycle_count;
+       gCPU.pdec -= ppc_cycle_count;
+       if (gCPU.pdec > oldpdec) {
+               ppc_wakeup();
+               sys_lock_mutex(exception_mutex);
+               gCPU.exception_pending = true;
+               gCPU.dec_exception = true;
+               gCPU.pdec=(uint64)0xffffffff*TB_TO_PTB_FACTOR;
+               sys_unlock_mutex(exception_mutex);
+       }
+#endif
+}
+
+void ppc_cpu_run()
+{
+//     gDebugger = new Debugger();
+//     gDebugger->mAlwaysShowRegs = true;
+       PPC_CPU_TRACE("execution started at %08x\n", gCPU.pc);
+       uint ops=0;
+       gCPU.effective_code_page = 0xffffffff;
+//     ppc_fpu_test();
+//     return;
+       while (true) {
+               gCPU.npc = gCPU.pc+4;
+               if ((gCPU.pc & ~0xfff) == gCPU.effective_code_page) {
+                       gCPU.current_opc = ppc_word_from_BE(*((uint32*)(&gCPU.physical_code_page[gCPU.pc & 0xfff])));
+                       ppc_debug_hook();
+               } else {
+                       int ret;
+                       if ((ret = ppc_direct_effective_memory_handle_code(gCPU.pc & ~0xfff, gCPU.physical_code_page))) {
+                               if (ret == PPC_MMU_EXC) {
+                                       gCPU.pc = gCPU.npc;
+                                       continue;
+                               } else {
+                                       PPC_CPU_ERR("?\n");
+                               }
+                       }
+                       gCPU.effective_code_page = gCPU.pc & ~0xfff;
+                       continue;
+               }
+               //ht_printf("%08x %04x\n", gCPU.pc, gCPU.current_opc);
+               ppc_exec_opc();
+               ops++;
+               gCPU.ptb++;
+#if 1
+               if (gCPU.pdec == 0) {
+                       gCPU.exception_pending = true;
+                       gCPU.dec_exception = true;
+                       gCPU.pdec=(uint64)0xffffffff*TB_TO_PTB_FACTOR;
+               } else {
+                       gCPU.pdec--;
+               }
+#endif
+               if ((ops & 0x3ffff)==0) {
+/*                     if (pic_check_interrupt()) {
+                               gCPU.exception_pending = true;
+                               gCPU.ext_exception = true;
+                       }*/
+                       if ((ops & 0x0fffff)==0) {
+//                             uint32 j=0;
+//                             ppc_read_effective_word(0xc046b2f8, j);
+
+                               ht_printf("@%08x (%u ops) pdec: %08x lr: %08x\n", gCPU.pc, ops, gCPU.pdec, gCPU.lr);
+#if 0
+                               extern uint32 PIC_enable_low;
+                               extern uint32 PIC_enable_high;
+                               ht_printf("enable ");
+                               int x = 1;
+                               for (int i=0; i<31; i++) {
+                                       if (PIC_enable_low & x) {
+                                               ht_printf("%d ", i);
+                                       }
+                                       x<<=1;
+                               }
+                               x=1;
+                               for (int i=0; i<31; i++) {
+                                       if (PIC_enable_high & x) {
+                                               ht_printf("%d ", 32+i);
+                                       }
+                                       x<<=1;
+                               }
+                               ht_printf("\n");
+#endif
+                       }
+               }
+               
+               gCPU.pc = gCPU.npc;
+               
+               extern int debugger_active, pause_emulation;
+               extern void sleep_millis(int);
+               while (debugger_active || pause_emulation) {
+                       sleep_millis(10);
+               }
+
+               if (gCPU.exception_pending) {
+                       if (gCPU.stop_exception) {
+                               gCPU.stop_exception = false;
+                               if (!gCPU.dec_exception && !gCPU.ext_exception) gCPU.exception_pending = false;
+                               break;
+                       }
+                       if (gCPU.msr & MSR_EE) {
+                               sys_lock_mutex(exception_mutex);
+                               if (gCPU.ext_exception) {
+                                       ppc_exception(PPC_EXC_EXT_INT);
+                                       gCPU.ext_exception = false;
+                                       gCPU.pc = gCPU.npc;
+                                       if (!gCPU.dec_exception) gCPU.exception_pending = false;
+                                       sys_unlock_mutex(exception_mutex);
+                                       continue;
+                               }
+                               if (gCPU.dec_exception) {
+                                       ppc_exception(PPC_EXC_DEC);
+                                       gCPU.dec_exception = false;
+                                       gCPU.pc = gCPU.npc;
+                                       gCPU.exception_pending = false;
+                                       sys_unlock_mutex(exception_mutex);
+                                       continue;
+                               }
+                               sys_unlock_mutex(exception_mutex);
+                               PPC_CPU_ERR("no interrupt, but signaled?!\n");
+                       }
+               }
+#ifdef PPC_CPU_ENABLE_SINGLESTEP
+               if (gCPU.msr & MSR_SE) {
+                       if (gCPU.singlestep_ignore) {
+                               gCPU.singlestep_ignore = false;
+                       } else {
+                               ppc_exception(PPC_EXC_TRACE2);
+                               gCPU.pc = gCPU.npc;
+                               continue;
+                       }
+               }
+#endif
+       }
+}
+
+void ppc_cpu_stop()
+{
+       sys_lock_mutex(exception_mutex);
+       gCPU.stop_exception = true;
+       gCPU.exception_pending = true;
+       sys_unlock_mutex(exception_mutex);
+}
+
+uint64 ppc_get_clock_frequency(int cpu)
+{
+       return PPC_CLOCK_FREQUENCY;
+}
+
+uint64 ppc_get_bus_frequency(int cpu)
+{
+       return PPC_BUS_FREQUENCY;
+}
+
+uint64 ppc_get_timebase_frequency(int cpu)
+{
+       return PPC_TIMEBASE_FREQUENCY;
+}
+
+
+void ppc_machine_check_exception()
+{
+       PPC_CPU_ERR("machine check exception\n");
+}
+
+uint32 ppc_cpu_get_gpr(int cpu, int i)
+{
+       return gCPU.gpr[i];
+}
+
+void   ppc_cpu_set_gpr(int cpu, int i, uint32 newvalue)
+{
+       gCPU.gpr[i] = newvalue;
+}
+
+void   ppc_cpu_set_msr(int cpu, uint32 newvalue)
+{
+       gCPU.msr = newvalue;
+}
+
+void   ppc_cpu_set_pc(int cpu, uint32 newvalue)
+{
+       gCPU.pc = newvalue;
+}
+
+uint32 ppc_cpu_get_pc(int cpu)
+{
+       return gCPU.pc;
+}
+
+uint32 ppc_cpu_get_pvr(int cpu)
+{
+       return gCPU.pvr;
+}
+
+void ppc_cpu_map_framebuffer(uint32 pa, uint32 ea)
+{
+       // use BAT for framebuffer
+       gCPU.dbatu[0] = ea|(7<<2)|0x3;
+       gCPU.dbat_bl17[0] = ~(BATU_BL(gCPU.dbatu[0])<<17);
+       gCPU.dbatl[0] = pa;
+}
+
+void ppc_set_singlestep_v(bool v, const char *file, int line, const char *format, ...)
+{
+       char buffer[200];
+       va_list arg;
+       va_start(arg, format);
+       ht_printf("singlestep %s from %s:%d, info: ", v ? "set" : "cleared", file, line);
+       vsprintf(buffer, format, arg);
+       ht_printf("%s\n", buffer);
+       va_end(arg);
+       ppc_crash();
+       gSinglestep = v;
+}
+
+void ppc_set_singlestep_nonverbose(bool v)
+{
+       gSinglestep = v;
+}
+
+#define CPU_KEY_PVR    "cpu_pvr"
+
+//#include "configparser.h"
+
+bool ppc_cpu_init(uint32 pvr)
+{
+       memset(&gCPU, 0, sizeof gCPU);
+       gCPU.pvr = pvr; //gConfig->getConfigInt(CPU_KEY_PVR);
+       gCPU.hid[1] = 0x80000000;
+       
+       ppc_dec_init();
+       // initialize srs (mostly for prom)
+       for (int i=0; i<16; i++) {
+               gCPU.sr[i] = 0x2aa*i;
+       }
+       sys_create_mutex(&exception_mutex);
+
+       PPC_CPU_WARN("You are using the generic CPU!\n");
+       PPC_CPU_WARN("This is much slower than the just-in-time compiler and\n");
+       PPC_CPU_WARN("should only be used for debugging purposes or if there's\n");
+       PPC_CPU_WARN("no just-in-time compiler for your platform.\n");
+       
+       return true;
+}
+
+#if 0
+void ppc_cpu_init_config()
+{
+       gConfig->acceptConfigEntryIntDef("cpu_pvr", 0x000c0201);
+}
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_cpu.h b/ppc/pearpc/cpu/cpu_generic/ppc_cpu.h
new file mode 100644 (file)
index 0000000..2f4c575
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *     PearPC
+ *     ppc_cpu.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_CPU_H__
+#define __PPC_CPU_H__
+
+#include <stddef.h>
+#include "system/types.h"
+#include "cpu/common.h"
+
+#define PPC_MHz(v) ((v)*1000*1000)
+
+#define TB_TO_PTB_FACTOR       10
+
+#define PPC_MODEL "ppc_model"
+#define PPC_CPU_MODEL "ppc_cpu"
+#define PPC_CLOCK_FREQUENCY PPC_MHz(10)
+#define PPC_BUS_FREQUENCY PPC_MHz(10)
+#define PPC_TIMEBASE_FREQUENCY (PPC_CLOCK_FREQUENCY / TB_TO_PTB_FACTOR)
+
+struct PPC_CPU_State { 
+       // * uisa
+       uint32 gpr[32];
+       uint64 fpr[32];
+       uint32 cr;
+       uint32 fpscr;
+       uint32 xer;     // spr 1
+       uint32 xer_ca;  // carry from xer
+       uint32 lr;      // spr 8
+       uint32 ctr;     // spr 9
+       // * oea
+       uint32 msr;
+       uint32 pvr;     // spr 287
+
+       //    * memory managment
+       uint32 ibatu[4];        // spr 528, 530, 532, 534
+       uint32 ibatl[4];        // spr 529, 531, 533, 535
+       uint32 ibat_bl17[4];    // for internal use
+
+       uint32 dbatu[4];        // spr 536, 538, 540, 542
+       uint32 dbatl[4];        // spr 537, 539, 541, 543
+       uint32 dbat_bl17[4];    // for internal use
+
+       uint32 sdr1;    // spr 25       (page table base address)
+
+       uint32 sr[16];
+       
+       //    * exception handling
+       uint32 dar;     // spr 19
+       uint32 dsisr;   // spr 18
+       uint32 sprg[4]; // spr 272-275
+       uint32 srr[2];  // spr 26-27
+       
+       //    * misc
+       uint32 dec;     // spr 22
+       uint32 ear;     // spr 282 .101
+       uint32 pir;     // spr 1032
+       uint64 tb;      // .75 spr 284(l)/285(u)
+       
+       uint32 hid[16];
+       // * internal
+       
+       uint32 pc;
+       uint32 npc;
+       uint32 current_opc;
+       bool   exception_pending;
+       bool   dec_exception;
+       bool   ext_exception;
+       bool   stop_exception;
+       bool   singlestep_ignore;
+
+       uint32 pagetable_base;
+       int    pagetable_hashmask;
+       uint32 reserve;
+       bool   have_reservation;
+       
+       // for generic cpu core
+       uint32 effective_code_page;
+       byte  *physical_code_page;
+       uint64 pdec;    // more precise version of dec
+       uint64 ptb;     // more precise version of tb
+
+       // for altivec
+       uint32 vscr;
+       uint32 vrsave;  // spr 256
+       Vector_t vr[36];                // <--- this MUST be 16-byte alligned
+       uint32 vtemp;
+};
+
+extern PPC_CPU_State gCPU;
+
+void ppc_cpu_atomic_raise_ext_exception();
+void ppc_cpu_atomic_cancel_ext_exception();
+
+extern uint32 gBreakpoint;
+extern uint32 gBreakpoint2;
+
+void ppc_set_singlestep_v(bool v, const char *file, int line, const char *format, ...);
+void ppc_set_singlestep_nonverbose(bool v);
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_dec.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_dec.cpp
new file mode 100644 (file)
index 0000000..4d2ea08
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ *     PearPC
+ *     ppc_dec.cc
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *     Portions Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
+ *     Portions Copyright (C) 2004 Apple Computer, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "cstring"
+
+#include "system/types.h"
+#include "cpu/debug.h"
+#include "cpu/cpu.h"
+#include "ppc_alu.h"
+#include "ppc_cpu.h"
+#include "ppc_dec.h"
+#include "ppc_exc.h"
+#include "ppc_fpu.h"
+#include "ppc_vec.h"
+#include "ppc_mmu.h"
+#include "ppc_opc.h"
+
+//#include "io/prom/promosi.h"
+
+static void ppc_opc_invalid()
+{
+#if 0
+       if (gCPU.pc == gPromOSIEntry && gCPU.current_opc == PROM_MAGIC_OPCODE) {
+               call_prom_osi();
+               return;
+       }
+       if (gCPU.current_opc == 0x00333301) {
+               // memset(r3, r4, r5)
+               uint32 dest = gCPU.gpr[3];
+               uint32 c = gCPU.gpr[4];
+               uint32 size = gCPU.gpr[5];
+               if (dest & 0xfff) {
+                       byte *dst;
+                       ppc_direct_effective_memory_handle(dest, dst);
+                       uint32 a = 4096 - (dest & 0xfff);
+                       memset(dst, c, a);
+                       size -= a;
+                       dest += a;
+               }
+               while (size >= 4096) {
+                       byte *dst;
+                       ppc_direct_effective_memory_handle(dest, dst);
+                       memset(dst, c, 4096);
+                       dest += 4096;
+                       size -= 4096;
+               }
+               if (size) {
+                       byte *dst;
+                       ppc_direct_effective_memory_handle(dest, dst);
+                       memset(dst, c, size);
+               }
+               gCPU.pc = gCPU.npc;
+               return;
+       }
+       if (gCPU.current_opc == 0x00333302) {
+               // memcpy
+               uint32 dest = gCPU.gpr[3];
+               uint32 src = gCPU.gpr[4];
+               uint32 size = gCPU.gpr[5];
+               byte *d, *s;
+               ppc_direct_effective_memory_handle(dest, d);
+               ppc_direct_effective_memory_handle(src, s);
+               while (size--) {
+                       if (!(dest & 0xfff)) ppc_direct_effective_memory_handle(dest, d);
+                       if (!(src & 0xfff)) ppc_direct_effective_memory_handle(src, s);
+                       *d = *s;
+                       src++; dest++; d++; s++;
+               }
+               gCPU.pc = gCPU.npc;
+               return;
+       }
+#endif
+       ht_printf("[PPC/DEC] Bad opcode: %08x (%u:%u)\n",
+               gCPU.current_opc, PPC_OPC_MAIN(gCPU.current_opc),
+               PPC_OPC_EXT(gCPU.current_opc));
+
+       SINGLESTEP("unknown instruction\n");
+}
+
+// main opcode 19
+static void ppc_opc_group_1()
+{
+       uint32 ext = PPC_OPC_EXT(gCPU.current_opc);
+       if (ext & 1) {
+               // crxxx
+               if (ext <= 225) {
+                       switch (ext) {
+                               case 33: ppc_opc_crnor(); return;
+                               case 129: ppc_opc_crandc(); return;
+                               case 193: ppc_opc_crxor(); return;
+                               case 225: ppc_opc_crnand(); return;
+                       }
+               } else {
+                       switch (ext) {
+                               case 257: ppc_opc_crand(); return;
+                               case 289: ppc_opc_creqv(); return;
+                               case 417: ppc_opc_crorc(); return;
+                               case 449: ppc_opc_cror(); return;
+                       }
+               }
+       } else if (ext & (1<<9)) {
+               // bcctrx
+               if (ext == 528) {
+                       ppc_opc_bcctrx(); 
+                       return;
+               }
+       } else {
+               switch (ext) {
+                       case 16: ppc_opc_bclrx(); return;
+                       case 0: ppc_opc_mcrf(); return;
+                       case 50: ppc_opc_rfi(); return;
+                       case 150: ppc_opc_isync(); return;
+               }
+       }
+       ppc_opc_invalid();
+}
+
+ppc_opc_function ppc_opc_table_group2[1015];
+
+// main opcode 31
+static void ppc_opc_init_group2()
+{
+       for (uint i=0; i<(sizeof ppc_opc_table_group2 / sizeof ppc_opc_table_group2[0]); i++) {
+               ppc_opc_table_group2[i] = ppc_opc_invalid;
+       }
+       ppc_opc_table_group2[0] = ppc_opc_cmp;
+       ppc_opc_table_group2[4] = ppc_opc_tw;
+       ppc_opc_table_group2[8] = ppc_opc_subfcx;//+
+       ppc_opc_table_group2[10] = ppc_opc_addcx;//+
+       ppc_opc_table_group2[11] = ppc_opc_mulhwux;
+       ppc_opc_table_group2[19] = ppc_opc_mfcr;
+       ppc_opc_table_group2[20] = ppc_opc_lwarx;
+       ppc_opc_table_group2[23] = ppc_opc_lwzx;
+       ppc_opc_table_group2[24] = ppc_opc_slwx;
+       ppc_opc_table_group2[26] = ppc_opc_cntlzwx;
+       ppc_opc_table_group2[28] = ppc_opc_andx;
+       ppc_opc_table_group2[32] = ppc_opc_cmpl;
+       ppc_opc_table_group2[40] = ppc_opc_subfx;
+       ppc_opc_table_group2[54] = ppc_opc_dcbst;
+       ppc_opc_table_group2[55] = ppc_opc_lwzux;
+       ppc_opc_table_group2[60] = ppc_opc_andcx;
+       ppc_opc_table_group2[75] = ppc_opc_mulhwx;
+       ppc_opc_table_group2[83] = ppc_opc_mfmsr;
+       ppc_opc_table_group2[86] = ppc_opc_dcbf;
+       ppc_opc_table_group2[87] = ppc_opc_lbzx;
+       ppc_opc_table_group2[104] = ppc_opc_negx;
+       ppc_opc_table_group2[119] = ppc_opc_lbzux;
+       ppc_opc_table_group2[124] = ppc_opc_norx;
+       ppc_opc_table_group2[136] = ppc_opc_subfex;//+
+       ppc_opc_table_group2[138] = ppc_opc_addex;//+
+       ppc_opc_table_group2[144] = ppc_opc_mtcrf;
+       ppc_opc_table_group2[146] = ppc_opc_mtmsr;
+       ppc_opc_table_group2[150] = ppc_opc_stwcx_;
+       ppc_opc_table_group2[151] = ppc_opc_stwx;
+       ppc_opc_table_group2[183] = ppc_opc_stwux;
+       ppc_opc_table_group2[200] = ppc_opc_subfzex;//+
+       ppc_opc_table_group2[202] = ppc_opc_addzex;//+
+       ppc_opc_table_group2[210] = ppc_opc_mtsr;
+       ppc_opc_table_group2[215] = ppc_opc_stbx;
+       ppc_opc_table_group2[232] = ppc_opc_subfmex;//+
+       ppc_opc_table_group2[234] = ppc_opc_addmex;
+       ppc_opc_table_group2[235] = ppc_opc_mullwx;//+
+       ppc_opc_table_group2[242] = ppc_opc_mtsrin;
+       ppc_opc_table_group2[246] = ppc_opc_dcbtst;
+       ppc_opc_table_group2[247] = ppc_opc_stbux;
+       ppc_opc_table_group2[266] = ppc_opc_addx;//+
+       ppc_opc_table_group2[278] = ppc_opc_dcbt;
+       ppc_opc_table_group2[279] = ppc_opc_lhzx;
+       ppc_opc_table_group2[284] = ppc_opc_eqvx;
+       ppc_opc_table_group2[306] = ppc_opc_tlbie;
+       ppc_opc_table_group2[310] = ppc_opc_eciwx;
+       ppc_opc_table_group2[311] = ppc_opc_lhzux;
+       ppc_opc_table_group2[316] = ppc_opc_xorx;
+       ppc_opc_table_group2[339] = ppc_opc_mfspr;
+       ppc_opc_table_group2[343] = ppc_opc_lhax;
+       ppc_opc_table_group2[370] = ppc_opc_tlbia;
+       ppc_opc_table_group2[371] = ppc_opc_mftb;
+       ppc_opc_table_group2[375] = ppc_opc_lhaux;
+       ppc_opc_table_group2[407] = ppc_opc_sthx;
+       ppc_opc_table_group2[412] = ppc_opc_orcx;
+       ppc_opc_table_group2[438] = ppc_opc_ecowx;
+       ppc_opc_table_group2[439] = ppc_opc_sthux;
+       ppc_opc_table_group2[444] = ppc_opc_orx;
+       ppc_opc_table_group2[459] = ppc_opc_divwux;//+
+       ppc_opc_table_group2[467] = ppc_opc_mtspr;
+       ppc_opc_table_group2[470] = ppc_opc_dcbi;
+       ppc_opc_table_group2[476] = ppc_opc_nandx;
+       ppc_opc_table_group2[491] = ppc_opc_divwx;//+
+       ppc_opc_table_group2[512] = ppc_opc_mcrxr;
+       ppc_opc_table_group2[533] = ppc_opc_lswx;
+       ppc_opc_table_group2[534] = ppc_opc_lwbrx;
+       ppc_opc_table_group2[535] = ppc_opc_lfsx;
+       ppc_opc_table_group2[536] = ppc_opc_srwx;
+       ppc_opc_table_group2[566] = ppc_opc_tlbsync;
+       ppc_opc_table_group2[567] = ppc_opc_lfsux;
+       ppc_opc_table_group2[595] = ppc_opc_mfsr;
+       ppc_opc_table_group2[597] = ppc_opc_lswi;
+       ppc_opc_table_group2[598] = ppc_opc_sync;
+       ppc_opc_table_group2[599] = ppc_opc_lfdx;
+       ppc_opc_table_group2[631] = ppc_opc_lfdux;
+       ppc_opc_table_group2[659] = ppc_opc_mfsrin;
+       ppc_opc_table_group2[661] = ppc_opc_stswx;
+       ppc_opc_table_group2[662] = ppc_opc_stwbrx;
+       ppc_opc_table_group2[663] = ppc_opc_stfsx;
+       ppc_opc_table_group2[695] = ppc_opc_stfsux;
+       ppc_opc_table_group2[725] = ppc_opc_stswi;
+       ppc_opc_table_group2[727] = ppc_opc_stfdx;
+       ppc_opc_table_group2[758] = ppc_opc_dcba;
+       ppc_opc_table_group2[759] = ppc_opc_stfdux;
+       ppc_opc_table_group2[790] = ppc_opc_lhbrx;
+       ppc_opc_table_group2[792] = ppc_opc_srawx;
+       ppc_opc_table_group2[824] = ppc_opc_srawix;
+       ppc_opc_table_group2[854] = ppc_opc_eieio;
+       ppc_opc_table_group2[918] = ppc_opc_sthbrx;
+       ppc_opc_table_group2[922] = ppc_opc_extshx;
+       ppc_opc_table_group2[954] = ppc_opc_extsbx;
+       ppc_opc_table_group2[982] = ppc_opc_icbi;
+       ppc_opc_table_group2[983] = ppc_opc_stfiwx;
+       ppc_opc_table_group2[1014] = ppc_opc_dcbz;
+
+       if ((ppc_cpu_get_pvr(0) & 0xffff0000) == 0x000c0000) {
+               /* Added for Altivec support */
+               ppc_opc_table_group2[6] = ppc_opc_lvsl;
+               ppc_opc_table_group2[7] = ppc_opc_lvebx;
+               ppc_opc_table_group2[38] = ppc_opc_lvsr;
+               ppc_opc_table_group2[39] = ppc_opc_lvehx;
+               ppc_opc_table_group2[71] = ppc_opc_lvewx;
+               ppc_opc_table_group2[103] = ppc_opc_lvx;
+               ppc_opc_table_group2[135] = ppc_opc_stvebx;
+               ppc_opc_table_group2[167] = ppc_opc_stvehx;
+               ppc_opc_table_group2[199] = ppc_opc_stvewx;
+               ppc_opc_table_group2[231] = ppc_opc_stvx;
+               ppc_opc_table_group2[342] = ppc_opc_dst;
+               ppc_opc_table_group2[359] = ppc_opc_lvxl;
+               ppc_opc_table_group2[374] = ppc_opc_dstst;
+               ppc_opc_table_group2[487] = ppc_opc_stvxl;
+               ppc_opc_table_group2[822] = ppc_opc_dss;
+       }
+}
+
+// main opcode 31
+inline static void ppc_opc_group_2()
+{
+       uint32 ext = PPC_OPC_EXT(gCPU.current_opc);
+       if (ext >= (sizeof ppc_opc_table_group2 / sizeof ppc_opc_table_group2[0])) {
+               ppc_opc_invalid();
+       }
+       ppc_opc_table_group2[ext]();
+}
+
+// main opcode 59
+static void ppc_opc_group_f1()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       uint32 ext = PPC_OPC_EXT(gCPU.current_opc);
+       switch (ext & 0x1f) {
+               case 18: ppc_opc_fdivsx(); return;
+               case 20: ppc_opc_fsubsx(); return;
+               case 21: ppc_opc_faddsx(); return;
+               case 22: ppc_opc_fsqrtsx(); return;
+               case 24: ppc_opc_fresx(); return;
+               case 25: ppc_opc_fmulsx(); return;
+               case 28: ppc_opc_fmsubsx(); return;
+               case 29: ppc_opc_fmaddsx(); return;
+               case 30: ppc_opc_fnmsubsx(); return;
+               case 31: ppc_opc_fnmaddsx(); return;
+       }
+       ppc_opc_invalid();
+}
+
+// main opcode 63
+static void ppc_opc_group_f2()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       uint32 ext = PPC_OPC_EXT(gCPU.current_opc);
+       if (ext & 16) {
+               switch (ext & 0x1f) {
+               case 18: ppc_opc_fdivx(); return;
+               case 20: ppc_opc_fsubx(); return;
+               case 21: ppc_opc_faddx(); return;
+               case 22: ppc_opc_fsqrtx(); return;
+               case 23: ppc_opc_fselx(); return;
+               case 25: ppc_opc_fmulx(); return;
+               case 26: ppc_opc_frsqrtex(); return;
+               case 28: ppc_opc_fmsubx(); return;
+               case 29: ppc_opc_fmaddx(); return;
+               case 30: ppc_opc_fnmsubx(); return;
+               case 31: ppc_opc_fnmaddx(); return;
+               }
+       } else {
+               switch (ext) {
+               case 0: ppc_opc_fcmpu(); return;
+               case 12: ppc_opc_frspx(); return;
+               case 14: ppc_opc_fctiwx(); return;
+               case 15: ppc_opc_fctiwzx(); return;
+               //--
+               case 32: ppc_opc_fcmpo(); return;
+               case 38: ppc_opc_mtfsb1x(); return;
+               case 40: ppc_opc_fnegx(); return;
+               case 64: ppc_opc_mcrfs(); return;
+               case 70: ppc_opc_mtfsb0x(); return;
+               case 72: ppc_opc_fmrx(); return;
+               case 134: ppc_opc_mtfsfix(); return;
+               case 136: ppc_opc_fnabsx(); return;
+               case 264: ppc_opc_fabsx(); return;
+               case 583: ppc_opc_mffsx(); return;
+               case 711: ppc_opc_mtfsfx(); return;
+               }
+       }
+       ppc_opc_invalid();
+}
+
+ppc_opc_function ppc_opc_table_groupv[965];
+
+static void ppc_opc_init_groupv()
+{
+       for (uint i=0; i<(sizeof ppc_opc_table_groupv / sizeof ppc_opc_table_groupv[0]);i++) {
+               ppc_opc_table_groupv[i] = ppc_opc_invalid;
+       }
+       ppc_opc_table_groupv[0] = ppc_opc_vaddubm;
+       ppc_opc_table_groupv[1] = ppc_opc_vmaxub;
+       ppc_opc_table_groupv[2] = ppc_opc_vrlb;
+       ppc_opc_table_groupv[4] = ppc_opc_vmuloub;
+       ppc_opc_table_groupv[5] = ppc_opc_vaddfp;
+       ppc_opc_table_groupv[6] = ppc_opc_vmrghb;
+       ppc_opc_table_groupv[7] = ppc_opc_vpkuhum;
+       ppc_opc_table_groupv[32] = ppc_opc_vadduhm;
+       ppc_opc_table_groupv[33] = ppc_opc_vmaxuh;
+       ppc_opc_table_groupv[34] = ppc_opc_vrlh;
+       ppc_opc_table_groupv[36] = ppc_opc_vmulouh;
+       ppc_opc_table_groupv[37] = ppc_opc_vsubfp;
+       ppc_opc_table_groupv[38] = ppc_opc_vmrghh;
+       ppc_opc_table_groupv[39] = ppc_opc_vpkuwum;
+       ppc_opc_table_groupv[64] = ppc_opc_vadduwm;
+       ppc_opc_table_groupv[65] = ppc_opc_vmaxuw;
+       ppc_opc_table_groupv[66] = ppc_opc_vrlw;
+       ppc_opc_table_groupv[70] = ppc_opc_vmrghw;
+       ppc_opc_table_groupv[71] = ppc_opc_vpkuhus;
+       ppc_opc_table_groupv[103] = ppc_opc_vpkuwus;
+       ppc_opc_table_groupv[129] = ppc_opc_vmaxsb;
+       ppc_opc_table_groupv[130] = ppc_opc_vslb;
+       ppc_opc_table_groupv[132] = ppc_opc_vmulosb;
+       ppc_opc_table_groupv[133] = ppc_opc_vrefp;
+       ppc_opc_table_groupv[134] = ppc_opc_vmrglb;
+       ppc_opc_table_groupv[135] = ppc_opc_vpkshus;
+       ppc_opc_table_groupv[161] = ppc_opc_vmaxsh;
+       ppc_opc_table_groupv[162] = ppc_opc_vslh;
+       ppc_opc_table_groupv[164] = ppc_opc_vmulosh;
+       ppc_opc_table_groupv[165] = ppc_opc_vrsqrtefp;
+       ppc_opc_table_groupv[166] = ppc_opc_vmrglh;
+       ppc_opc_table_groupv[167] = ppc_opc_vpkswus;
+       ppc_opc_table_groupv[192] = ppc_opc_vaddcuw;
+       ppc_opc_table_groupv[193] = ppc_opc_vmaxsw;
+       ppc_opc_table_groupv[194] = ppc_opc_vslw;
+       ppc_opc_table_groupv[197] = ppc_opc_vexptefp;
+       ppc_opc_table_groupv[198] = ppc_opc_vmrglw;
+       ppc_opc_table_groupv[199] = ppc_opc_vpkshss;
+       ppc_opc_table_groupv[226] = ppc_opc_vsl;
+       ppc_opc_table_groupv[229] = ppc_opc_vlogefp;
+       ppc_opc_table_groupv[231] = ppc_opc_vpkswss;
+       ppc_opc_table_groupv[256] = ppc_opc_vaddubs;
+       ppc_opc_table_groupv[257] = ppc_opc_vminub;
+       ppc_opc_table_groupv[258] = ppc_opc_vsrb;
+       ppc_opc_table_groupv[260] = ppc_opc_vmuleub;
+       ppc_opc_table_groupv[261] = ppc_opc_vrfin;
+       ppc_opc_table_groupv[262] = ppc_opc_vspltb;
+       ppc_opc_table_groupv[263] = ppc_opc_vupkhsb;
+       ppc_opc_table_groupv[288] = ppc_opc_vadduhs;
+       ppc_opc_table_groupv[289] = ppc_opc_vminuh;
+       ppc_opc_table_groupv[290] = ppc_opc_vsrh;
+       ppc_opc_table_groupv[292] = ppc_opc_vmuleuh;
+       ppc_opc_table_groupv[293] = ppc_opc_vrfiz;
+       ppc_opc_table_groupv[294] = ppc_opc_vsplth;
+       ppc_opc_table_groupv[295] = ppc_opc_vupkhsh;
+       ppc_opc_table_groupv[320] = ppc_opc_vadduws;
+       ppc_opc_table_groupv[321] = ppc_opc_vminuw;
+       ppc_opc_table_groupv[322] = ppc_opc_vsrw;
+       ppc_opc_table_groupv[325] = ppc_opc_vrfip;
+       ppc_opc_table_groupv[326] = ppc_opc_vspltw;
+       ppc_opc_table_groupv[327] = ppc_opc_vupklsb;
+       ppc_opc_table_groupv[354] = ppc_opc_vsr;
+       ppc_opc_table_groupv[357] = ppc_opc_vrfim;
+       ppc_opc_table_groupv[359] = ppc_opc_vupklsh;
+       ppc_opc_table_groupv[384] = ppc_opc_vaddsbs;
+       ppc_opc_table_groupv[385] = ppc_opc_vminsb;
+       ppc_opc_table_groupv[386] = ppc_opc_vsrab;
+       ppc_opc_table_groupv[388] = ppc_opc_vmulesb;
+       ppc_opc_table_groupv[389] = ppc_opc_vcfux;
+       ppc_opc_table_groupv[390] = ppc_opc_vspltisb;
+       ppc_opc_table_groupv[391] = ppc_opc_vpkpx;
+       ppc_opc_table_groupv[416] = ppc_opc_vaddshs;
+       ppc_opc_table_groupv[417] = ppc_opc_vminsh;
+       ppc_opc_table_groupv[418] = ppc_opc_vsrah;
+       ppc_opc_table_groupv[420] = ppc_opc_vmulesh;
+       ppc_opc_table_groupv[421] = ppc_opc_vcfsx;
+       ppc_opc_table_groupv[422] = ppc_opc_vspltish;
+       ppc_opc_table_groupv[423] = ppc_opc_vupkhpx;
+       ppc_opc_table_groupv[448] = ppc_opc_vaddsws;
+       ppc_opc_table_groupv[449] = ppc_opc_vminsw;
+       ppc_opc_table_groupv[450] = ppc_opc_vsraw;
+       ppc_opc_table_groupv[453] = ppc_opc_vctuxs;
+       ppc_opc_table_groupv[454] = ppc_opc_vspltisw;
+       ppc_opc_table_groupv[485] = ppc_opc_vctsxs;
+       ppc_opc_table_groupv[487] = ppc_opc_vupklpx;
+       ppc_opc_table_groupv[512] = ppc_opc_vsububm;
+       ppc_opc_table_groupv[513] = ppc_opc_vavgub;
+       ppc_opc_table_groupv[514] = ppc_opc_vand;
+       ppc_opc_table_groupv[517] = ppc_opc_vmaxfp;
+       ppc_opc_table_groupv[518] = ppc_opc_vslo;
+       ppc_opc_table_groupv[544] = ppc_opc_vsubuhm;
+       ppc_opc_table_groupv[545] = ppc_opc_vavguh;
+       ppc_opc_table_groupv[546] = ppc_opc_vandc;
+       ppc_opc_table_groupv[549] = ppc_opc_vminfp;
+       ppc_opc_table_groupv[550] = ppc_opc_vsro;
+       ppc_opc_table_groupv[576] = ppc_opc_vsubuwm;
+       ppc_opc_table_groupv[577] = ppc_opc_vavguw;
+       ppc_opc_table_groupv[578] = ppc_opc_vor;
+       ppc_opc_table_groupv[610] = ppc_opc_vxor;
+       ppc_opc_table_groupv[641] = ppc_opc_vavgsb;
+       ppc_opc_table_groupv[642] = ppc_opc_vnor;
+       ppc_opc_table_groupv[673] = ppc_opc_vavgsh;
+       ppc_opc_table_groupv[704] = ppc_opc_vsubcuw;
+       ppc_opc_table_groupv[705] = ppc_opc_vavgsw;
+       ppc_opc_table_groupv[768] = ppc_opc_vsububs;
+       ppc_opc_table_groupv[770] = ppc_opc_mfvscr;
+       ppc_opc_table_groupv[772] = ppc_opc_vsum4ubs;
+       ppc_opc_table_groupv[800] = ppc_opc_vsubuhs;
+       ppc_opc_table_groupv[802] = ppc_opc_mtvscr;
+       ppc_opc_table_groupv[804] = ppc_opc_vsum4shs;
+       ppc_opc_table_groupv[832] = ppc_opc_vsubuws;
+       ppc_opc_table_groupv[836] = ppc_opc_vsum2sws;
+       ppc_opc_table_groupv[896] = ppc_opc_vsubsbs;
+       ppc_opc_table_groupv[900] = ppc_opc_vsum4sbs;
+       ppc_opc_table_groupv[928] = ppc_opc_vsubshs;
+       ppc_opc_table_groupv[960] = ppc_opc_vsubsws;
+       ppc_opc_table_groupv[964] = ppc_opc_vsumsws;
+}
+
+// main opcode 04
+static void ppc_opc_group_v()
+{
+       uint32 ext = PPC_OPC_EXT(gCPU.current_opc);
+#ifndef  __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       switch(ext & 0x1f) {
+               case 16:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vmhraddshs();
+                       else
+                               return ppc_opc_vmhaddshs();
+               case 17:        return ppc_opc_vmladduhm();
+               case 18:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vmsummbm();
+                       else
+                               return ppc_opc_vmsumubm();
+               case 19:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vmsumuhs();
+                       else
+                               return ppc_opc_vmsumuhm();
+               case 20:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vmsumshs();
+                       else
+                               return ppc_opc_vmsumshm();
+               case 21:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vperm();
+                       else
+                               return ppc_opc_vsel();
+               case 22:        return ppc_opc_vsldoi();
+               case 23:
+                       if (gCPU.current_opc & PPC_OPC_Rc)
+                               return ppc_opc_vnmsubfp();
+                       else
+                               return ppc_opc_vmaddfp();
+       }
+       switch(ext & 0x1ff)
+       {
+               case 3: return ppc_opc_vcmpequbx();
+               case 35: return ppc_opc_vcmpequhx();
+               case 67: return ppc_opc_vcmpequwx();
+               case 99: return ppc_opc_vcmpeqfpx();
+               case 227: return ppc_opc_vcmpgefpx();
+               case 259: return ppc_opc_vcmpgtubx();
+               case 291: return ppc_opc_vcmpgtuhx();
+               case 323: return ppc_opc_vcmpgtuwx();
+               case 355: return ppc_opc_vcmpgtfpx();
+               case 387: return ppc_opc_vcmpgtsbx();
+               case 419: return ppc_opc_vcmpgtshx();
+               case 451: return ppc_opc_vcmpgtswx();
+               case 483: return ppc_opc_vcmpbfpx();
+       }
+
+       if (ext >= (sizeof ppc_opc_table_groupv / sizeof ppc_opc_table_groupv[0])) {
+               return ppc_opc_invalid();
+       }
+       return ppc_opc_table_groupv[ext]();
+}
+
+static ppc_opc_function ppc_opc_table_main[64] = {
+       &ppc_opc_invalid,       //  0
+       &ppc_opc_invalid,       //  1
+       &ppc_opc_invalid,       //  2  (tdi on 64 bit platforms)
+       &ppc_opc_twi,           //  3
+       &ppc_opc_invalid,       //  4  (altivec group 1)
+       &ppc_opc_invalid,       //  5
+       &ppc_opc_invalid,       //  6
+       &ppc_opc_mulli,         //  7
+       &ppc_opc_subfic,        //  8
+       &ppc_opc_invalid,       //  9
+       &ppc_opc_cmpli,         // 10
+       &ppc_opc_cmpi,          // 11
+       &ppc_opc_addic,         // 12
+       &ppc_opc_addic_,        // 13
+       &ppc_opc_addi,          // 14
+       &ppc_opc_addis,         // 15
+       &ppc_opc_bcx,           // 16
+       &ppc_opc_sc,            // 17
+       &ppc_opc_bx,            // 18
+       &ppc_opc_group_1,       // 19
+       &ppc_opc_rlwimix,       // 20
+       &ppc_opc_rlwinmx,       // 21
+       &ppc_opc_invalid,       // 22
+       &ppc_opc_rlwnmx,        // 23
+       &ppc_opc_ori,           // 24
+       &ppc_opc_oris,          // 25
+       &ppc_opc_xori,          // 26
+       &ppc_opc_xoris,         // 27
+       &ppc_opc_andi_,         // 28
+       &ppc_opc_andis_,        // 29
+       &ppc_opc_invalid,       // 30  (group_rld on 64 bit platforms)
+       &ppc_opc_group_2,       // 31
+       &ppc_opc_lwz,           // 32
+       &ppc_opc_lwzu,          // 33
+       &ppc_opc_lbz,           // 34
+       &ppc_opc_lbzu,          // 35
+       &ppc_opc_stw,           // 36
+       &ppc_opc_stwu,          // 37
+       &ppc_opc_stb,           // 38
+       &ppc_opc_stbu,          // 39
+       &ppc_opc_lhz,           // 40
+       &ppc_opc_lhzu,          // 41
+       &ppc_opc_lha,           // 42
+       &ppc_opc_lhau,          // 43
+       &ppc_opc_sth,           // 44
+       &ppc_opc_sthu,          // 45
+       &ppc_opc_lmw,           // 46
+       &ppc_opc_stmw,          // 47
+       &ppc_opc_lfs,           // 48
+       &ppc_opc_lfsu,          // 49
+       &ppc_opc_lfd,           // 50
+       &ppc_opc_lfdu,          // 51
+       &ppc_opc_stfs,          // 52
+       &ppc_opc_stfsu,         // 53
+       &ppc_opc_stfd,          // 54
+       &ppc_opc_stfdu,         // 55
+       &ppc_opc_invalid,       // 56
+       &ppc_opc_invalid,       // 57
+       &ppc_opc_invalid,       // 58  (ld on 64 bit platforms)
+       &ppc_opc_group_f1,      // 59
+       &ppc_opc_invalid,       // 60
+       &ppc_opc_invalid,       // 61
+       &ppc_opc_invalid,       // 62
+       &ppc_opc_group_f2,      // 63
+};
+
+void FASTCALL ppc_exec_opc()
+{
+       uint32 mainopc = PPC_OPC_MAIN(gCPU.current_opc);
+       ppc_opc_table_main[mainopc]();
+}
+
+void ppc_dec_init()
+{
+       ppc_opc_init_group2();
+       if ((ppc_cpu_get_pvr(0) & 0xffff0000) == 0x000c0000) {
+               ppc_opc_table_main[4] = ppc_opc_group_v;
+               ppc_opc_init_groupv();
+       }
+}
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_dec.h b/ppc/pearpc/cpu/cpu_generic/ppc_dec.h
new file mode 100644 (file)
index 0000000..c0be5c7
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *     PearPC
+ *     ppc_dec.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_DEC_H__
+#define __PPC_DEC_H__
+
+#include "system/types.h"
+
+void FASTCALL ppc_exec_opc();
+void ppc_dec_init();
+
+typedef void (*ppc_opc_function)();
+
+#define PPC_OPC_ASSERT(v)
+
+#define PPC_OPC_MAIN(opc)              (((opc)>>26)&0x3f)
+#define PPC_OPC_EXT(opc)               (((opc)>>1)&0x3ff)
+#define PPC_OPC_Rc                     1
+#define PPC_OPC_OE                     (1<<10)
+#define PPC_OPC_LK                     1
+#define PPC_OPC_AA                     (1<<1)
+
+#define PPC_OPC_TEMPL_A(opc, rD, rA, rB, rC) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;rC=((opc)>>6)&0x1f;}
+#define PPC_OPC_TEMPL_B(opc, BO, BI, BD) {BO=((opc)>>21)&0x1f;BI=((opc)>>16)&0x1f;BD=(opc)&0xfffc;if (BD&0x8000) BD |= 0xffff0000;}
+#define PPC_OPC_TEMPL_D_SImm(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(opc)&0xffff;if (imm & 0x8000) imm |= 0xffff0000;}
+#define PPC_OPC_TEMPL_D_UImm(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(opc)&0xffff;}
+#define PPC_OPC_TEMPL_D_Shift16(opc, rD, rA, imm) {rD=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;imm=(opc)<<16;}
+#define PPC_OPC_TEMPL_I(opc, LI) {LI=(opc)&0x3fffffc;if (LI&0x02000000) LI |= 0xfc000000;}
+#define PPC_OPC_TEMPL_M(opc, rS, rA, SH, MB, ME) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;SH=((opc)>>11)&0x1f;MB=((opc)>>6)&0x1f;ME=((opc)>>1)&0x1f;}
+#define PPC_OPC_TEMPL_X(opc, rS, rA, rB) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;}
+#define PPC_OPC_TEMPL_XFX(opc, rS, CRM) {rS=((opc)>>21)&0x1f;CRM=((opc)>>12)&0xff;}
+#define PPC_OPC_TEMPL_XO(opc, rS, rA, rB) {rS=((opc)>>21)&0x1f;rA=((opc)>>16)&0x1f;rB=((opc)>>11)&0x1f;}
+#define PPC_OPC_TEMPL_XL(opc, BO, BI, BD) {BO=((opc)>>21)&0x1f;BI=((opc)>>16)&0x1f;BD=((opc)>>11)&0x1f;}
+#define PPC_OPC_TEMPL_XFL(opc, rB, FM) {rB=((opc)>>11)&0x1f;FM=((opc)>>17)&0xff;}
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_exc.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_exc.cpp
new file mode 100644 (file)
index 0000000..abf0b8c
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *     PearPC
+ *     ppc_exc.cc
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *     Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*     Pages marked: v.???
+ *     From: IBM PowerPC MicroProcessor Family: Altivec(tm) Technology...
+ *             Programming Environments Manual
+ */
+
+#include "tools/snprintf.h"
+#include "debug/tracers.h"
+#include "cpu/debug.h"
+#include "info.h"
+#include "ppc_cpu.h"
+#include "ppc_exc.h"
+#include "ppc_mmu.h"
+
+/*
+ *     .247
+ */
+bool FASTCALL ppc_exception(uint32 type, uint32 flags, uint32 a)
+{
+       if (type != PPC_EXC_DEC) {
+               PPC_EXC_TRACE("@%08x: type = %08x (%08x, %08x)\n", gCPU.pc, type, flags, a);
+       }
+       switch (type) {
+       case PPC_EXC_DSI: { // .271
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               gCPU.dar = a;
+               gCPU.dsisr = flags;
+               break;
+       }
+       case PPC_EXC_ISI: { // .274
+               if (gCPU.pc == 0) {
+                       PPC_EXC_WARN("pc == 0 in ISI\n");
+                       SINGLESTEP("");
+               }
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = (gCPU.msr & 0x87c0ffff) | flags;
+               break;
+       }
+       case PPC_EXC_DEC: { // .284
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_EXT_INT: {
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_SC: {  // .285
+               gCPU.srr[0] = gCPU.npc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_NO_FPU: { // .284
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_NO_VEC: {  // v.41
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_PROGRAM: { // .283
+               if (flags & PPC_EXC_PROGRAM_NEXT) {
+                       gCPU.srr[0] = gCPU.npc;
+               } else {
+                       gCPU.srr[0] = gCPU.pc;
+               }
+               gCPU.srr[1] = (gCPU.msr & 0x87c0ffff) | flags;
+               break;
+       }
+       case PPC_EXC_FLOAT_ASSIST: { // .288
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       case PPC_EXC_MACHINE_CHECK: { // .270
+               if (!(gCPU.msr & MSR_ME)) {
+                       PPC_EXC_ERR("machine check exception and MSR[ME]=0.\n");
+               }
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = (gCPU.msr & 0x87c0ffff) | MSR_RI;
+               break;
+       }
+       case PPC_EXC_TRACE2: { // .286
+               gCPU.srr[0] = gCPU.pc;
+               gCPU.srr[1] = gCPU.msr & 0x87c0ffff;
+               break;
+       }
+       default:
+               PPC_EXC_ERR("unknown\n");
+               return false;
+       }
+       ppc_mmu_tlb_invalidate();
+       if (1 || (gCPU.msr & MSR_IP))
+               type |= 0xfff00000;
+       gCPU.msr = 0;
+       gCPU.npc = type;
+       return true;
+}
+
+void ppc_cpu_raise_ext_exception()
+{
+       ppc_cpu_atomic_raise_ext_exception();
+}
+
+void ppc_cpu_cancel_ext_exception()
+{
+       ppc_cpu_atomic_cancel_ext_exception();
+}
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_exc.h b/ppc/pearpc/cpu/cpu_generic/ppc_exc.h
new file mode 100644 (file)
index 0000000..9aa8862
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *     PearPC
+ *     ppc_exc.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_EXC_H__
+#define __PPC_EXC_H__
+
+#include "system/types.h"
+
+/*
+ *     .250
+ */
+#define PPC_EXC_UNKNOWN 0
+#define PPC_EXC_SYS_RESET 0x100
+#define PPC_EXC_MACHINE_CHECK 0x00200
+#define PPC_EXC_DSI 0x00300
+#define PPC_EXC_ISI 0x00400
+#define PPC_EXC_EXT_INT 0x00500
+#define PPC_EXC_ALIGNMENT 0x00600
+#define PPC_EXC_PROGRAM 0x00700
+#define PPC_EXC_NO_FPU 0x00800
+#define PPC_EXC_DEC 0x00900
+//Reserved 0x00A00
+//Reserved 0x00B00
+#define PPC_EXC_SC 0x00C00
+#define PPC_EXC_TRACE2 0x00D00
+#define PPC_EXC_FLOAT_ASSIST 0x00E00
+#define PPC_EXC_PERF_MON 0xF00
+#define PPC_EXC_NO_VEC 0xF20
+#define PPC_EXC_ALTIVEC 0xF20
+#define PPC_EXC_ALTIVEC_ASSIST 0x1600
+#define PPC_EXC_TAU 0x1700
+
+#define PPC_EXC_DSISR_PAGE (1<<30)
+#define PPC_EXC_DSISR_PROT (1<<27)
+#define PPC_EXC_DSISR_STORE (1<<25)
+
+#define PPC_EXC_SRR1_PAGE PPC_EXC_DSISR_PAGE
+#define PPC_EXC_SRR1_GUARD (1<<28)
+#define PPC_EXC_SRR1_PROT PPC_EXC_DSISR_PROT
+
+#define PPC_EXC_PROGRAM_FLOAT (1<<20)
+#define PPC_EXC_PROGRAM_ILL   (1<<19)
+#define PPC_EXC_PROGRAM_PRIV  (1<<18)
+#define PPC_EXC_PROGRAM_TRAP  (1<<17)
+
+/* 
+ * set if srr0 does not not contain the address of the intruction
+ * causing the exception
+ */
+#define PPC_EXC_PROGRAM_NEXT  (1<<16)
+
+bool FASTCALL ppc_exception(uint32 type=0, uint32 flags=0, uint32 a=0);
+void ppc_cpu_raise_ext_exception();
+void ppc_cpu_cancel_ext_exception();
+
+#endif
+
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_fpu.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_fpu.cpp
new file mode 100644 (file)
index 0000000..a40a4eb
--- /dev/null
@@ -0,0 +1,1359 @@
+/*
+ *     PearPC
+ *     ppc_fpu.cc
+ *                        
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *     Copyright (C) 2003 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "debug/tracers.h"
+#include "ppc_cpu.h"
+#include "ppc_dec.h"
+#include "ppc_fpu.h"
+
+// .121
+
+
+#define PPC_FPR_TYPE2(a,b) (((a)<<8)|(b))
+inline void ppc_fpu_add(ppc_double &res, ppc_double &a, ppc_double &b)
+{
+       switch (PPC_FPR_TYPE2(a.type, b.type)) {
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_norm): {
+               int diff = a.e - b.e;
+               if (diff<0) {
+                       diff = -diff;
+                       if (diff <= 56) {
+                               a.m >>= diff;
+                       } else if (a.m != 0) {
+                               a.m = 1;        
+                       } else {
+                               a.m = 0;
+                       }
+                       res.e = b.e;
+               } else {
+                       if (diff <= 56) {
+                               b.m >>= diff;
+                       } else if (b.m != 0) {
+                               b.m = 1;
+                       } else {
+                               b.m = 0;
+                       }
+                       res.e = a.e;
+               }
+               res.type = ppc_fpr_norm;
+               if (a.s == b.s) {
+                       res.s = a.s;
+                       res.m = a.m + b.m;
+                       if (res.m & (1ULL<<56)) {
+                           res.m >>= 1;
+                           res.e++;
+                       }
+               } else {
+                       res.s = a.s;
+                       res.m = a.m - b.m;
+                       if (!res.m) {
+                               if (FPSCR_RN(gCPU.fpscr) == FPSCR_RN_MINF) {
+                                       res.s |= b.s;
+                               } else {
+                                       res.s &= b.s;
+                               }
+                               res.type = ppc_fpr_zero;
+                       } else {
+                               if ((sint64)res.m < 0) {
+                                       res.m = b.m - a.m;
+                                       res.s = b.s;
+                               }
+                               diff = ppc_fpu_normalize(res) - 8;
+                               res.e -= diff;
+                               res.m <<= diff;
+                       }       
+               }
+               break;
+       }
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_NaN):
+               res.s = a.s;
+               res.type = ppc_fpr_NaN;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_zero):
+               res.e = a.e;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_zero):
+               res.s = a.s;
+               res.m = a.m;
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_norm):
+               res.e = b.e;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_NaN):
+               res.s = b.s;
+               res.m = b.m;
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_Inf):
+               if (a.s != b.s) {
+                       // +oo + -oo == NaN
+                       res.s = a.s ^ b.s;
+                       res.type = ppc_fpr_NaN;
+                       break;
+               }
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_zero):
+               res.s = a.s;
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_Inf):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_Inf):
+               res.s = b.s;
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_zero):
+               // round bla
+               res.type = ppc_fpr_zero;
+               res.s = a.s && b.s;
+               break;
+       }
+}
+
+inline void ppc_fpu_quadro_mshr(ppc_quadro &q, int exp)
+{
+       if (exp >= 64) {
+               q.m1 = q.m0;
+               q.m0 = 0;
+               exp -= 64;
+       }
+       uint64 t = q.m0 & ((1ULL<<exp)-1);
+       q.m0 >>= exp;
+       q.m1 >>= exp;
+       q.m1 |= t<<(64-exp);
+}
+
+inline void ppc_fpu_quadro_mshl(ppc_quadro &q, int exp)
+{
+       if (exp >= 64) {
+               q.m0 = q.m1;
+               q.m1 = 0;
+               exp -= 64;
+       }
+       uint64 t = (q.m1 >> (64-exp)) & ((1ULL<<exp)-1);
+       q.m0 <<= exp;
+       q.m1 <<= exp;
+       q.m0 |= t;
+}
+
+inline void ppc_fpu_add_quadro_m(ppc_quadro &res, const ppc_quadro &a, const ppc_quadro &b)
+{
+       res.m1 = a.m1+b.m1;
+       if (res.m1 < a.m1) {
+               res.m0 = a.m0+b.m0+1;
+       } else {
+               res.m0 = a.m0+b.m0;
+       }
+}
+
+inline void ppc_fpu_sub_quadro_m(ppc_quadro &res, const ppc_quadro &a, const ppc_quadro &b)
+{
+       res.m1 = a.m1-b.m1;
+       if (a.m1 < b.m1) {
+               res.m0 = a.m0-b.m0-1;
+       } else {
+               res.m0 = a.m0-b.m0;
+       }
+}
+
+// res has 107 significant bits. a, b have 106 significant bits each.
+inline void ppc_fpu_add_quadro(ppc_quadro &res, ppc_quadro &a, ppc_quadro &b)
+{
+       // treat as 107 bit mantissa
+       if (a.type == ppc_fpr_norm) ppc_fpu_quadro_mshl(a, 1);
+       if (b.type == ppc_fpr_norm) ppc_fpu_quadro_mshl(b, 1);
+       switch (PPC_FPR_TYPE2(a.type, b.type)) {
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_norm): {
+               int diff = a.e - b.e;
+               if (diff < 0) {
+                       diff = -diff;
+                       if (diff <= 107) {
+                               // FIXME: may set x_prime
+                               ppc_fpu_quadro_mshr(a, diff);
+                       } else if (a.m0 || a.m1) {
+                               a.m0 = 0;
+                               a.m1 = 1;
+                       } else {
+                               a.m0 = 0;
+                               a.m1 = 0;
+                       }
+                       res.e = b.e;
+               } else {
+                       if (diff <= 107) {
+                               // FIXME: may set x_prime
+                               ppc_fpu_quadro_mshr(b, diff);
+                       } else if (b.m0 || b.m1) {
+                               b.m0 = 0;
+                               b.m1 = 1;
+                       } else {
+                               b.m0 = 0;
+                               b.m1 = 0;
+                       }
+                       res.e = a.e;
+               }
+               res.type = ppc_fpr_norm;
+               if (a.s == b.s) {
+                       res.s = a.s;
+                       ppc_fpu_add_quadro_m(res, a, b);
+                       int X_prime = res.m1 & 1;
+                       if (res.m0 & (1ULL<<(107-64))) {
+                               ppc_fpu_quadro_mshr(res, 1);
+                               res.e++;
+                       }
+                       // res = [107]
+                       res.m1 = (res.m1 & 0xfffffffffffffffeULL) | X_prime;
+               } else {
+                       res.s = a.s;
+                       int cmp;
+                       if (a.m0 < b.m0) {
+                               cmp = -1;
+                       } else if (a.m0 > b.m0) {
+                               cmp = +1;
+                       } else {
+                               if (a.m1 < b.m1) {
+                                       cmp = -1;
+                               } else if (a.m1 > b.m1) {
+                                       cmp = +1;
+                               } else {
+                                       cmp = 0;
+                               }
+                       }
+                       if (!cmp) {
+                               if (FPSCR_RN(gCPU.fpscr) == FPSCR_RN_MINF) {
+                                       res.s |= b.s;
+                               } else {
+                                       res.s &= b.s;
+                               }
+                               res.type = ppc_fpr_zero;
+                       } else {
+                               if (cmp < 0) {
+                                       ppc_fpu_sub_quadro_m(res, b, a);
+                                       res.s = b.s;
+                               } else {
+                                       ppc_fpu_sub_quadro_m(res, a, b);
+                               }
+                               diff = ppc_fpu_normalize_quadro(res) - (128-107);
+                               int X_prime = res.m1 & 1;
+                               res.m1 &= 0xfffffffffffffffeULL;
+                               ppc_fpu_quadro_mshl(res, diff);
+                               res.e -= diff;
+                               res.m1 |= X_prime;
+                       }
+                       // res = [107]
+               }
+               break;
+       }
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_NaN):
+               res.s = a.s;
+               res.type = ppc_fpr_NaN;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_zero):
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_zero):
+               res.e = a.e;
+               res.s = a.s;
+               res.m0 = a.m0;
+               res.m1 = a.m1;
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_norm):
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_NaN):
+               res.e = b.e;
+               res.s = b.s;
+               res.m0 = b.m0;
+               res.m1 = b.m1;
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_Inf):
+               if (a.s != b.s) {
+                       // +oo + -oo == NaN
+                       res.s = a.s ^ b.s;
+                       res.type = ppc_fpr_NaN;
+                       break;
+               }
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_zero):
+               res.s = a.s;
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_Inf):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_Inf):
+               res.s = b.s;
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_zero):
+               // round bla
+               res.type = ppc_fpr_zero;
+               res.s = a.s && b.s;
+               break;
+       }
+}
+
+inline void ppc_fpu_add_uint64_carry(uint64 &a, uint64 b, uint64 &carry)
+{
+       carry = (a+b < a) ? 1 : 0;
+       a += b;
+}
+
+// 'res' has 56 significant bits on return, a + b have 56 significant bits each
+inline void ppc_fpu_mul(ppc_double &res, const ppc_double &a, const ppc_double &b)
+{
+       res.s = a.s ^ b.s;
+       switch (PPC_FPR_TYPE2(a.type, b.type)) {
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_norm): {
+               res.type = ppc_fpr_norm;
+               res.e = a.e + b.e;
+//             printf("new exp: %d\n", res.e);
+//             ht_printf("MUL:\na.m: %qb\nb.m: %qb\n", a.m, b.m);
+               uint64 fH, fM1, fM2, fL;
+               fL = (a.m & 0xffffffff) * (b.m & 0xffffffff);   // [32] * [32] = [63,64]
+               fM1 = (a.m >> 32) * (b.m & 0xffffffff);         // [24] * [32] = [55,56]
+               fM2 = (a.m & 0xffffffff) * (b.m >> 32);         // [32] * [24] = [55,56]
+               fH = (a.m >> 32) * (b.m >> 32);                 // [24] * [24] = [47,48]
+//             ht_printf("fH: %qx fM1: %qx fM2: %qx fL: %qx\n", fH, fM1, fM2, fL);
+
+               // calulate fH * 2^64 + (fM1 + fM2) * 2^32 + fL
+               uint64 rL, rH;
+               rL = fL;                                        // rL = rH = [63,64]
+               rH = fH;                                        // rH = fH = [47,48]
+               uint64 split;
+               split = fM1 + fM2;
+               uint64 carry;
+               ppc_fpu_add_uint64_carry(rL, (split & 0xffffffff) << 32, carry); // rL = [63,64]
+               rH += carry;                                    // rH = [0 .. 2^48]
+               rH += split >> 32;                              // rH = [0:48], where 46, 47 or 48 set
+
+               // res.m = [0   0  .. 0  | rH_48 rH_47 .. rH_0 | rL_63 rL_62 .. rL_55]
+               //         [---------------------------------------------------------]
+               // bit   = [63  62 .. 58 | 57    56    .. 9    | 8     7        0    ]
+               //         [---------------------------------------------------------]
+               //         [15 bits zero |      49 bits rH     | 8 most sign.bits rL ]
+               res.m = rH << 9;
+               res.m |= rL >> (64-9);
+               // res.m = [58]
+
+//             ht_printf("fH: %qx fM1: %qx fM2: %qx fL: %qx\n", fH, fM1, fM2, fL);
+               if (res.m & (1ULL << 57)) {
+                       res.m >>= 2;
+                       res.e += 2;
+               } else if (res.m & (1ULL << 56)) {
+                       res.m >>= 1;
+                       res.e++;
+               }
+               // res.m = [56]
+               break;
+       }
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_NaN):
+               res.type = a.type;
+               res.e = a.e;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_zero): 
+               res.s = a.s;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_zero): 
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_NaN): 
+               res.s = b.s;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_zero): 
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_zero): 
+               res.type = ppc_fpr_NaN;
+               break;
+       }
+}
+
+// 'res' has 'prec' significant bits on return, a + b have 56 significant bits each
+// for 111 >= prec >= 64
+inline void ppc_fpu_mul_quadro(ppc_quadro &res, ppc_double &a, ppc_double &b, int prec)
+{
+       res.s = a.s ^ b.s;
+       switch (PPC_FPR_TYPE2(a.type, b.type)) {
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_norm): {
+               res.type = ppc_fpr_norm;
+               res.e = a.e + b.e;
+//             printf("new exp: %d\n", res.e);
+//             ht_printf("MUL:\na.m: %016qx\nb.m: %016qx\n", a.m, b.m);
+               uint64 fH, fM1, fM2, fL;
+               fL = (a.m & 0xffffffff) * (b.m & 0xffffffff);   // [32] * [32] = [63,64]
+               fM1 = (a.m >> 32) * (b.m & 0xffffffff);         // [24] * [32] = [55,56]
+               fM2 = (a.m & 0xffffffff) * (b.m >> 32);         // [32] * [24] = [55,56]
+               fH = (a.m >> 32) * (b.m >> 32);                 // [24] * [24] = [47,48]
+//             ht_printf("fH: %016qx fM1: %016qx fM2: %016qx fL: %016qx\n", fH, fM1, fM2, fL);
+
+               // calulate fH * 2^64 + (fM1 + fM2) * 2^32 + fL
+               uint64 rL, rH;
+               rL = fL;                                        // rL = rH = [63,64]
+               rH = fH;                                        // rH = fH = [47,48]
+               uint64 split;
+               split = fM1 + fM2;
+               uint64 carry;
+               ppc_fpu_add_uint64_carry(rL, (split & 0xffffffff) << 32, carry); // rL = [63,64]
+               rH += carry;                                    // rH = [0 .. 2^48]
+               rH += split >> 32;                              // rH = [0:48], where 46, 47 or 48 set
+
+               // res.m0 = [0    0   .. 0   | rH_48 rH_47 .. rH_0 | rL_63 rL_62 .. rL_0]
+               //          [-----------------------------------------------------------]
+               // log.bit= [127  126 .. 113 | 112            64   | 63    62       0   ]
+               //          [-----------------------------------------------------------]
+               //          [ 15 bits zero   |      49 bits rH     |      64 bits rL    ]
+               res.m0 = rH;
+               res.m1 = rL;
+               // res.m0|res.m1 = [111,112,113]
+
+//             ht_printf("res = %016qx%016qx\n", res.m0, res.m1);
+               if (res.m0 & (1ULL << 48)) {
+                       ppc_fpu_quadro_mshr(res, 2+(111-prec));
+                       res.e += 2;
+               } else if (res.m0 & (1ULL << 47)) {
+                       ppc_fpu_quadro_mshr(res, 1+(111-prec));
+                       res.e += 1;
+               } else {
+                       ppc_fpu_quadro_mshr(res, 111-prec);
+               }
+               // res.m0|res.m1 = [prec]
+               break;
+       }
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_NaN):
+               res.type = a.type;
+               res.e = a.e;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_zero): 
+               res.s = a.s;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_norm): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_zero): 
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_NaN): 
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_NaN): 
+               res.s = b.s;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_zero): 
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_Inf): 
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_zero): 
+               res.type = ppc_fpr_NaN;
+               break;
+       }
+}
+
+// calculate one of these:
+// + m1 * m2 + s
+// + m1 * m2 - s
+// - m1 * m2 + s
+// - m1 * m2 - s
+// using a 106 bit accumulator
+//
+// .752
+//
+// FIXME: There is a bug in this code that shows up in Mac OS X Finder fwd/bwd
+// button: the top line is not rendered correctly. This works with the jitc_x86
+// FPU however...
+inline void ppc_fpu_mul_add(ppc_double &res, ppc_double &m1, ppc_double &m2,
+       ppc_double &s)
+{
+       ppc_quadro p;
+/*     ht_printf("m1 = %d * %016qx * 2^%d, %s\n", m1.s, m1.m, m1.e,
+               ppc_fpu_get_fpr_type(m1.type));
+       ht_printf("m2 = %d * %016qx * 2^%d, %s\n", m2.s, m2.m, m2.e,
+               ppc_fpu_get_fpr_type(m2.type));*/
+       // create product with 106 significant bits
+       ppc_fpu_mul_quadro(p, m1, m2, 106);
+/*     ht_printf("p = %d * %016qx%016qx * 2^%d, %s\n", p.s, p.m0, p.m1, p.e,
+               ppc_fpu_get_fpr_type(p.type));*/
+       // convert s into ppc_quadro
+/*     ht_printf("s = %d * %016qx * 2^%d %s\n", s.s, s.m, s.e,
+               ppc_fpu_get_fpr_type(s.type));*/
+       ppc_quadro q;
+       q.e = s.e;
+       q.s = s.s;
+       q.type = s.type;
+       q.m0 = 0;
+       q.m1 = s.m;
+       // .. with 106 significant bits
+       ppc_fpu_quadro_mshl(q, 106-56);
+/*     ht_printf("q = %d * %016qx%016qx * 2^%d %s\n", q.s, q.m0, q.m1, q.e,
+               ppc_fpu_get_fpr_type(q.type));*/
+       // now we must add p, q.
+       ppc_quadro x;
+       ppc_fpu_add_quadro(x, p, q);
+       // x = [107]
+/*     ht_printf("x = %d * %016qx%016qx * 2^%d %s\n", x.s, x.m0, x.m1, x.e,
+               ppc_fpu_get_fpr_type(x.type));*/
+       res.type = x.type;
+       res.s = x.s;
+       res.e = x.e;
+       if (x.type == ppc_fpr_norm) {
+               res.m = x.m0 << 13;                     // 43 bits from m0
+               res.m |= (x.m1 >> (64-12)) << 1;        // 12 bits from m1
+               res.m |= x.m1 & 1;                      // X' bit from m1
+       }
+/*     ht_printf("res = %d * %016qx * 2^%d %s\n", res.s, res.m, res.e,
+               ppc_fpu_get_fpr_type(res.type));*/
+}
+
+inline void ppc_fpu_div(ppc_double &res, const ppc_double &a, const ppc_double &b)
+{
+       res.s = a.s ^ b.s;
+       switch (PPC_FPR_TYPE2(a.type, b.type)) {
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_norm): {
+               res.type = ppc_fpr_norm;
+               res.e = a.e - b.e;
+               res.m = 0;
+               uint64 am = a.m, bm = b.m;
+               uint i = 0;
+               while (am && (i<56)) {
+                       res.m <<= 1;
+                       if (am >= bm) {
+                               res.m |= 1;
+                               am -= bm;
+                       }
+                       am <<= 1;
+//                     printf("am=%llx, bm=%llx, rm=%llx\n", am, bm, res.m);
+                       i++;
+               }
+               res.m <<= 57-i;
+               if (res.m & (1ULL << 56)) {
+                       res.m >>= 1;
+               } else {
+                       res.e--;
+               }
+//             printf("final: am=%llx, bm=%llx, rm=%llx\n", am, bm, res.m);
+               break;
+       }
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_NaN):
+               res.e = a.e;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_norm):
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_Inf):
+       case PPC_FPR_TYPE2(ppc_fpr_NaN, ppc_fpr_zero):
+               res.s = a.s;
+               // fall-thru
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_norm):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_norm):
+               res.type = a.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_NaN):
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_NaN):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_NaN):
+               res.s = b.s;
+               res.type = b.type;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_Inf):
+               res.type = ppc_fpr_zero;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_norm, ppc_fpr_zero):
+               res.type = ppc_fpr_Inf;
+               break;
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_Inf):
+       case PPC_FPR_TYPE2(ppc_fpr_Inf, ppc_fpr_zero):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_Inf):
+       case PPC_FPR_TYPE2(ppc_fpr_zero, ppc_fpr_zero):
+               res.type = ppc_fpr_NaN;
+               break;
+       }
+}
+
+inline void ppc_fpu_sqrt(ppc_double &D, const ppc_double &B)
+{
+       switch (B.type) {
+       case ppc_fpr_norm:
+               if (B.s) {
+                       D.type = ppc_fpr_NaN;
+                       gCPU.fpscr |= FPSCR_VXSQRT;
+                       break;
+               }
+               // D := 1/2(D_old + B/D_old)
+               D = B;
+               D.e /= 2;
+               for (int i=0; i<6; i++) {
+                       ppc_double D_old = D;
+                       ppc_double B_div_D_old;
+                       ppc_fpu_div(B_div_D_old, B, D_old);
+                       ppc_fpu_add(D, D_old, B_div_D_old);
+                       D.e--;
+                       
+/*                     uint64 e;
+                       ppc_double E = D;
+                       ppc_fpu_pack_double(E, e);
+                       printf("%.20f\n", *(double *)&e);*/
+               }
+               break;
+       case ppc_fpr_zero:
+               D.type = ppc_fpr_zero;
+               D.s = B.s;
+               break;
+       case ppc_fpr_Inf:
+               if (B.s) {
+                       D.type = ppc_fpr_NaN;
+                       gCPU.fpscr |= FPSCR_VXSQRT;
+               } else {
+                       D.type = ppc_fpr_Inf;
+                       D.s = 0;
+               }
+               break;
+       case ppc_fpr_NaN:
+               D.type = ppc_fpr_NaN;
+               break;
+       }       
+}
+
+void ppc_fpu_test()
+{
+       ppc_double A, B, C;
+       double a, b, c;
+       A.type = B.type = ppc_fpr_norm;
+       A.s = 1;
+       A.e = 0;
+       A.m = 0;
+       A.m = ((1ULL<<56)-1)-((1ULL<<10)-1);
+       ht_printf("%qb\n", A.m);
+       B.s = 1;
+       B.e = 0;
+       B.m = 0;
+       B.m = ((1ULL<<56)-1)-((1ULL<<50)-1);
+       a = ppc_fpu_get_double(A);
+       b = ppc_fpu_get_double(B);
+       printf("%f + %f = \n", a, b);
+       ppc_fpu_add(C, A, B);
+       uint64 d;
+       uint32 s;
+       ppc_fpu_pack_double_as_single(C, d);
+       ht_printf("%064qb\n", d);
+       ppc_fpu_unpack_double(C, d);
+       ppc_fpu_pack_single(C, s);
+       ht_printf("single: %032b\n", s);
+       ppc_single Cs;
+       ppc_fpu_unpack_single(Cs, s);
+       ppc_fpu_single_to_double(Cs, C);
+//     ht_printf("%d\n", ppc_fpu_double_to_int(C));
+       c = ppc_fpu_get_double(C);
+       printf("%f\n", c);
+}
+
+/*
+ *     a and b must not be NaNs
+ */
+inline uint32 ppc_fpu_compare(ppc_double &a, ppc_double &b)
+{
+       if (a.type == ppc_fpr_zero) {
+               if (b.type == ppc_fpr_zero) return 2;
+               return (b.s) ? 4: 8;
+       }
+       if (b.type == ppc_fpr_zero) return (a.s) ? 8: 4;
+       if (a.s != b.s) return (a.s) ? 8: 4;
+       if (a.e > b.e) return (a.s) ? 8: 4;
+       if (a.e < b.e) return (a.s) ? 4: 8;
+       if (a.m > b.m) return (a.s) ? 8: 4;
+       if (a.m < b.m) return (a.s) ? 4: 8;
+       return 2;
+}
+
+double ppc_fpu_get_double(uint64 d)
+{      
+       ppc_double dd;
+       ppc_fpu_unpack_double(dd, d);
+       return ppc_fpu_get_double(dd);
+}
+
+double ppc_fpu_get_double(ppc_double &d)
+{
+       if (d.type == ppc_fpr_norm) {
+               double r = d.m;
+               for (int i=0; i<55; i++) {
+                       r = r / 2.0;
+               }
+               if (d.e < 0) {
+                       for (int i=0; i>d.e; i--) {
+                               r = r / 2.0;
+                       }
+               } else if (d.e > 0) {
+                       for (int i=0; i<d.e; i++) {
+                               r = r * 2.0;
+                       }
+               }
+               if (d.s) r = -r;
+               return r;
+       } else {
+               return 0.0;
+       }
+}
+
+/***********************************************************************************
+ *
+ */
+/*
+ *     fabsx           Floating Absolute Value
+ *     .484
+ */
+void ppc_opc_fabsx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       gCPU.fpr[frD] = gCPU.fpr[frB] & ~FPU_SIGN_BIT;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fabs.\n");
+       }
+}
+/*
+ *     faddx           Floating Add (Double-Precision)
+ *     .485
+ */
+void ppc_opc_faddx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (A.s != B.s && A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXISI;
+       }
+       ppc_fpu_add(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fadd.\n");
+       }
+}
+/*
+ *     faddx           Floating Add Single
+ *     .486
+ */
+void ppc_opc_faddsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (A.s != B.s && A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXISI;
+       }
+       ppc_fpu_add(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fadds.\n");
+       }
+}
+/*
+ *     fcmpo           Floating Compare Ordered
+ *     .488
+ */
+static uint32 ppc_fpu_cmp_and_mask[8] = {
+       0xfffffff0,
+       0xffffff0f,
+       0xfffff0ff,
+       0xffff0fff,
+       0xfff0ffff,
+       0xff0fffff,
+       0xf0ffffff,
+       0x0fffffff,
+};
+void ppc_opc_fcmpo()
+{
+       int crfD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crfD, frA, frB);
+       crfD >>= 2;
+       ppc_double A, B;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       uint32 cmp;
+       if (A.type == ppc_fpr_NaN || B.type == ppc_fpr_NaN) {
+               gCPU.fpscr |= FPSCR_VXSNAN;
+               /*if (bla)*/ gCPU.fpscr |= FPSCR_VXVC;
+               cmp = 1;
+       } else {
+               cmp = ppc_fpu_compare(A, B);
+       }
+       crfD = 7-crfD;
+       gCPU.fpscr &= ~0x1f000;
+       gCPU.fpscr |= (cmp << 12);
+       gCPU.cr &= ppc_fpu_cmp_and_mask[crfD];
+       gCPU.cr |= (cmp << (crfD * 4));
+}
+/*
+ *     fcmpu           Floating Compare Unordered
+ *     .489
+ */
+void ppc_opc_fcmpu()
+{
+       int crfD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crfD, frA, frB);
+       crfD >>= 2;
+       ppc_double A, B;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       uint32 cmp;
+       if (A.type == ppc_fpr_NaN || B.type == ppc_fpr_NaN) {
+               gCPU.fpscr |= FPSCR_VXSNAN;
+               cmp = 1;
+       } else {
+               cmp = ppc_fpu_compare(A, B);
+       }
+       crfD = 7-crfD;
+       gCPU.fpscr &= ~0x1f000;
+       gCPU.fpscr |= (cmp << 12);
+       gCPU.cr &= ppc_fpu_cmp_and_mask[crfD];
+       gCPU.cr |= (cmp << (crfD * 4));
+}
+/*
+ *     fctiwx          Floating Convert to Integer Word
+ *     .492
+ */
+void ppc_opc_fctiwx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       ppc_double B;
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       gCPU.fpr[frD] = ppc_fpu_double_to_int(B);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fctiw.\n");
+       }
+}
+/*
+ *     fctiwzx         Floating Convert to Integer Word with Round toward Zero
+ *     .493
+ */
+void ppc_opc_fctiwzx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       uint32 oldfpscr = gCPU.fpscr;
+       gCPU.fpscr &= ~3;
+       gCPU.fpscr |= 1;
+       ppc_double B;
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       gCPU.fpr[frD] = ppc_fpu_double_to_int(B);
+       gCPU.fpscr = oldfpscr;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fctiwz.\n");
+       }
+}
+/*
+ *     fdivx           Floating Divide (Double-Precision)
+ *     .494
+ */
+void ppc_opc_fdivx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (A.type == ppc_fpr_zero && B.type == ppc_fpr_zero) {
+               gCPU.fpscr |= FPSCR_VXZDZ;
+       }
+       if (A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXIDI;
+       }
+       if (B.type == ppc_fpr_zero && A.type != ppc_fpr_zero) {
+               // FIXME::
+               gCPU.fpscr |= FPSCR_VXIDI;              
+       }
+       ppc_fpu_div(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fdiv.\n");
+       }
+}
+/*
+ *     fdivsx          Floating Divide Single
+ *     .495
+ */
+void ppc_opc_fdivsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (A.type == ppc_fpr_zero && B.type == ppc_fpr_zero) {
+               gCPU.fpscr |= FPSCR_VXZDZ;
+       }
+       if (A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXIDI;
+       }
+       if (B.type == ppc_fpr_zero && A.type != ppc_fpr_zero) {
+               // FIXME::
+               gCPU.fpscr |= FPSCR_VXIDI;
+       }
+       ppc_fpu_div(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fdivs.\n");
+       }
+}
+/*
+ *     fmaddx          Floating Multiply-Add (Double-Precision)
+ *     .496
+ */
+void ppc_opc_fmaddx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       ppc_fpu_mul_add(D, A, C, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmadd.\n");
+       }
+}
+/*
+ *     fmaddx          Floating Multiply-Add Single
+ *     .497
+ */
+void ppc_opc_fmaddsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       ppc_fpu_mul_add(D, A, C, B);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmadds.\n");
+       }
+}
+/*
+ *     fmrx            Floating Move Register
+ *     .498
+ */
+void ppc_opc_fmrx()
+{
+       int frD, rA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, frB);
+       PPC_OPC_ASSERT(rA==0);
+       gCPU.fpr[frD] = gCPU.fpr[frB];
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmr.\n");
+       }
+}
+/*
+ *     fmsubx          Floating Multiply-Subtract (Double-Precision)
+ *     .499
+ */
+void ppc_opc_fmsubx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       B.s ^= 1;
+       ppc_fpu_mul_add(D, A, C, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmsub.\n");
+       }
+}
+/*
+ *     fmsubsx         Floating Multiply-Subtract Single
+ *     .500
+ */
+void ppc_opc_fmsubsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       ppc_fpu_mul_add(D, A, C, B);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmsubs.\n");
+       }
+}
+/*
+ *     fmulx           Floating Multipy (Double-Precision)
+ *     .501
+ */
+void ppc_opc_fmulx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frB==0);
+       ppc_double A, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       if ((A.type == ppc_fpr_Inf && C.type == ppc_fpr_zero)
+        || (A.type == ppc_fpr_zero && C.type == ppc_fpr_Inf)) {
+               gCPU.fpscr |= FPSCR_VXIMZ;
+       }
+       ppc_fpu_mul(D, A, C);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+//     *((double*)&gCPU.fpr[frD]) = *((double*)(&gCPU.fpr[frA]))*(*((double*)(&gCPU.fpr[frC])));
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmul.\n");
+       }
+}
+/*
+ *     fmulsx          Floating Multipy Single
+ *     .502
+ */
+void ppc_opc_fmulsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frB==0);
+       ppc_double A, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       if ((A.type == ppc_fpr_Inf && C.type == ppc_fpr_zero)
+        || (A.type == ppc_fpr_zero && C.type == ppc_fpr_Inf)) {
+               gCPU.fpscr |= FPSCR_VXIMZ;
+       }
+       ppc_fpu_mul(D, A, C);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fmuls.\n");
+       }
+}
+/*
+ *     fnabsx          Floating Negative Absolute Value
+ *     .503
+ */
+void ppc_opc_fnabsx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       gCPU.fpr[frD] = gCPU.fpr[frB] | FPU_SIGN_BIT;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fnabs.\n");
+       }
+}
+/*
+ *     fnegx           Floating Negate
+ *     .504
+ */
+void ppc_opc_fnegx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       gCPU.fpr[frD] = gCPU.fpr[frB] ^ FPU_SIGN_BIT;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fneg.\n");
+       }
+}
+/*
+ *     fnmaddx         Floating Negative Multiply-Add (Double-Precision) 
+ *     .505
+ */
+void ppc_opc_fnmaddx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D/*, E*/;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       ppc_fpu_mul_add(D, A, C, B);
+       D.s ^= 1;
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fnmadd.\n");
+       }
+}
+/*
+ *     fnmaddsx        Floating Negative Multiply-Add Single
+ *     .506
+ */
+void ppc_opc_fnmaddsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       ppc_fpu_mul_add(D, A, C, B);
+       D.s ^= 1;
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fnmadds.\n");
+       }
+}
+/*
+ *     fnmsubx         Floating Negative Multiply-Subtract (Double-Precision)
+ *     .507
+ */
+void ppc_opc_fnmsubx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       B.s ^= 1;
+       ppc_fpu_mul_add(D, A, C, B);
+       D.s ^= 1;
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fnmsub.\n");
+       }
+}
+/*
+ *     fnsubsx         Floating Negative Multiply-Subtract Single
+ *     .508
+ */
+void ppc_opc_fnmsubsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A, B, C, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_unpack_double(C, gCPU.fpr[frC]);
+       B.s ^= 1;
+       ppc_fpu_mul_add(D, A, C, B);
+       D.s ^= 1;
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fnmsubs.\n");
+       }
+}
+/*
+ *     fresx           Floating Reciprocal Estimate Single
+ *     .509
+ */
+void ppc_opc_fresx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frA==0 && frC==0);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fres.\n");
+       }
+       PPC_FPU_ERR("fres\n");
+}
+/*
+ *     frspx           Floating Round to Single
+ *     .511
+ */
+void ppc_opc_frspx()
+{
+       int frD, frA, frB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, frA, frB);
+       PPC_OPC_ASSERT(frA==0);
+       ppc_double B;
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(B, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("frsp.\n");
+       }
+}
+/*
+ *     frsqrtex        Floating Reciprocal Square Root Estimate
+ *     .512
+ */
+void ppc_opc_frsqrtex()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frA==0 && frC==0);
+       ppc_double B;
+       ppc_double D;
+       ppc_double E;
+       ppc_double Q;
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_sqrt(Q, B);
+       E.type = ppc_fpr_norm; E.s = 0; E.e = 0; E.m = 0x80000000000000ULL;
+       ppc_fpu_div(D, E, Q);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);    
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("frsqrte.\n");
+       }
+}
+/*
+ *     fselx           Floating Select
+ *     .514
+ */
+void ppc_opc_fselx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       ppc_double A;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       if (A.type == ppc_fpr_NaN || (A.type != ppc_fpr_zero && A.s)) {
+               gCPU.fpr[frD] = gCPU.fpr[frB];
+       } else {
+               gCPU.fpr[frD] = gCPU.fpr[frC];
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fsel.\n");
+       }
+}
+/*
+ *     fsqrtx          Floating Square Root (Double-Precision)
+ *     .515
+ */
+void ppc_opc_fsqrtx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frA==0 && frC==0);
+       ppc_double B;
+       ppc_double D;
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       ppc_fpu_sqrt(D, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fsqrt.\n");
+       }
+}
+/*
+ *     fsqrtsx         Floating Square Root Single
+ *     .515
+ */
+void ppc_opc_fsqrtsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frA==0 && frC==0);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fsqrts.\n");
+       }
+       PPC_FPU_ERR("fsqrts\n");
+}
+/*
+ *     fsubx           Floating Subtract (Double-Precision)
+ *     .517
+ */
+void ppc_opc_fsubx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (B.type != ppc_fpr_NaN) {
+               B.s ^= 1;
+       }
+       if (A.s != B.s && A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXISI;
+       }
+       ppc_fpu_add(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fsub.\n");
+       }
+}
+/*
+ *     fsubsx          Floating Subtract Single
+ *     .518
+ */
+void ppc_opc_fsubsx()
+{
+       int frD, frA, frB, frC;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, frD, frA, frB, frC);
+       PPC_OPC_ASSERT(frC==0);
+       ppc_double A, B, D;
+       ppc_fpu_unpack_double(A, gCPU.fpr[frA]);
+       ppc_fpu_unpack_double(B, gCPU.fpr[frB]);
+       if (B.type != ppc_fpr_NaN) {
+               B.s ^= 1;
+       }
+       if (A.s != B.s && A.type == ppc_fpr_Inf && B.type == ppc_fpr_Inf) {
+               gCPU.fpscr |= FPSCR_VXISI;
+       }
+       ppc_fpu_add(D, A, B);
+       gCPU.fpscr |= ppc_fpu_pack_double_as_single(D, gCPU.fpr[frD]);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_FPU_ERR("fsubs.\n");
+       }
+}
+
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_fpu.h b/ppc/pearpc/cpu/cpu_generic/ppc_fpu.h
new file mode 100644 (file)
index 0000000..18bca35
--- /dev/null
@@ -0,0 +1,609 @@
+/*
+ *     PearPC
+ *     ppc_fpu.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __PPC_FPU_H__
+#define __PPC_FPU_H__
+
+
+#define FPU_SIGN_BIT (0x8000000000000000ULL)
+
+#define FPD_SIGN(v) (((v)&FPU_SIGN_BIT)?1:0)
+#define FPD_EXP(v) ((v)>>52)
+#define FPD_FRAC(v) ((v)&0x000fffffffffffffULL)
+
+#define FPS_SIGN(v) ((v)&0x80000000)
+#define FPS_EXP(v) ((v)>>23)
+#define FPS_FRAC(v) ((v)&0x007fffff)
+
+// m must be uint64
+#define FPD_PACK_VAR(f, s, e, m) (f) = ((s)?FPU_SIGN_BIT:0ULL)|((((uint64)(e))&0x7ff)<<52)|((m)&((1ULL<<52)-1))
+#define FPD_UNPACK_VAR(f, s, e, m) {(s)=FPD_SIGN(f);(e)=FPD_EXP(f)&0x7ff;(m)=FPD_FRAC(f);}
+
+#define FPS_PACK_VAR(f, s, e, m) (f) = ((s)?0x80000000:0)|((e)<<23)|((m)&0x7fffff)
+#define FPS_UNPACK_VAR(f, s, e, m) {(s)=FPS_SIGN(f);(e)=FPS_EXP(f)&0xff;(m)=FPS_FRAC(f);}
+
+#define FPD_UNPACK(freg, fvar) FPD_UNPACK(freg, fvar.s, fvar.e, fvar.m)
+
+
+void ppc_fpu_test();
+
+enum ppc_fpr_type {
+       ppc_fpr_norm,
+       ppc_fpr_zero,
+       ppc_fpr_NaN,
+       ppc_fpr_Inf,
+};
+
+struct ppc_quadro {
+       ppc_fpr_type type;
+       int s;
+       int e;
+       uint64 m0;      // most  significant
+       uint64 m1;      // least significant
+};
+
+struct ppc_double {
+       ppc_fpr_type type;
+       int s;
+       int e;
+       uint64 m;
+};
+
+struct ppc_single {
+       ppc_fpr_type type;
+       int s;
+       int e;
+       uint m;
+};
+
+inline int ppc_count_leading_zeros(uint64 i)
+{
+       int ret;
+       uint32 dd = i >> 32;
+       if (dd) {
+               ret = 31;
+               if (dd > 0xffff) { ret -= 16; dd >>= 16; }
+               if (dd > 0xff) { ret -= 8; dd >>= 8; }
+               if (dd & 0xf0) { ret -= 4; dd >>= 4; }
+               if (dd & 0xc) { ret -= 2; dd >>= 2; }
+               if (dd & 0x2) ret--;
+       } else {
+               dd = (uint32)i;
+               ret = 63;
+               if (dd > 0xffff) { ret -= 16; dd >>= 16; }
+               if (dd > 0xff) { ret -= 8; dd >>= 8; }
+               if (dd & 0xf0) { ret -= 4; dd >>= 4; }
+               if (dd & 0xc) { ret -= 2; dd >>= 2; }
+               if (dd & 0x2) ret--;
+       }
+       return ret;
+}
+
+inline int ppc_fpu_normalize_quadro(ppc_quadro &d)
+{
+       int ret = d.m0 ? ppc_count_leading_zeros(d.m0) : 64 + ppc_count_leading_zeros(d.m1);
+       return ret;
+}
+
+inline int ppc_fpu_normalize(ppc_double &d)
+{
+       return ppc_count_leading_zeros(d.m);
+}
+
+inline int ppc_fpu_normalize_single(ppc_single &s)
+{
+       int ret;
+       uint32 dd = s.m;
+       ret = 31;
+       if (dd > 0xffff) { ret -= 16; dd >>= 16; }
+       if (dd > 0xff) { ret -= 8; dd >>= 8; }
+       if (dd & 0xf0) { ret -= 4; dd >>= 4; }
+       if (dd & 0xc) { ret -= 2; dd >>= 2; }
+       if (dd & 0x2) ret--;
+       return ret;
+}
+
+#include "tools/snprintf.h"
+inline void ppc_fpu_unpack_double(ppc_double &res, uint64 d)
+{
+       FPD_UNPACK_VAR(d, res.s, res.e, res.m);
+//     ht_printf("ud: %qx: s:%d e:%d m:%qx\n", d, res.s, res.e, res.m);
+       // .124
+       if (res.e == 2047) {
+               if (res.m == 0) {
+                       res.type = ppc_fpr_Inf;
+               } else {
+                       res.type = ppc_fpr_NaN;
+               }
+       } else if (res.e == 0) {
+               if (res.m == 0) {
+                       res.type = ppc_fpr_zero;
+               } else {
+                       // normalize denormalized exponent
+                       int diff = ppc_fpu_normalize(res) - 8;
+                       res.m <<= diff+3;
+                       res.e -= 1023 - 1 + diff;
+                       res.type = ppc_fpr_norm;
+               }
+       } else {
+               res.e -= 1023; // unbias exponent
+               res.type = ppc_fpr_norm;
+               // add implied bit
+               res.m |= 1ULL<<52;
+               res.m <<= 3;
+       }
+//     ht_printf("ud: %qx: s:%d e:%d m:%qx\n", d, res.s, res.e, res.m);
+}
+
+
+inline void ppc_fpu_unpack_single(ppc_single &res, uint32 d)
+{
+       FPS_UNPACK_VAR(d, res.s, res.e, res.m);
+       // .124
+       if (res.e == 255) {
+               if (res.m == 0) {
+                       res.type = ppc_fpr_Inf;
+               } else {
+                       res.type = ppc_fpr_NaN;
+               }
+       } else if (res.e == 0) {
+               if (res.m == 0) {
+                       res.type = ppc_fpr_zero;
+               } else {
+                       // normalize denormalized exponent
+                       int diff = ppc_fpu_normalize_single(res) - 8;
+                       res.m <<= diff+3;
+                       res.e -= 127 - 1 + diff;
+                       res.type = ppc_fpr_norm;
+               }
+       } else {
+               res.e -= 127; // unbias exponent
+               res.type = ppc_fpr_norm;
+               // add implied bit
+               res.m |= 1<<23;
+               res.m <<= 3;
+       }
+}
+
+inline uint32 ppc_fpu_round(ppc_double &d) 
+{
+       // .132
+       switch (FPSCR_RN(gCPU.fpscr)) {
+       case FPSCR_RN_NEAR:
+               if (d.m & 0x7) {
+                       if ((d.m & 0x7) != 4) {
+                               d.m += 4;
+                       } else if (d.m & 8) {
+                               d.m += 4;
+                       }
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_ZERO:
+               if (d.m & 0x7) {
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_PINF:
+               if (!d.s && (d.m & 0x7)) {
+                       d.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_MINF:
+               if (d.s && (d.m & 0x7)) {
+                       d.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+inline uint32 ppc_fpu_round_single(ppc_single &s) 
+{
+       switch (FPSCR_RN(gCPU.fpscr)) {
+       case FPSCR_RN_NEAR:
+               if (s.m & 0x7) {
+                       if ((s.m & 0x7) != 4) {
+                               s.m += 4;
+                       } else if (s.m & 8) {
+                               s.m += 4;
+                       }
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_ZERO:
+               if (s.m & 0x7) {
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_PINF:
+               if (!s.s && (s.m & 0x7)) {
+                       s.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_MINF:
+               if (s.s && (s.m & 0x7)) {
+                       s.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+inline uint32 ppc_fpu_round_single(ppc_double &s) 
+{
+       switch (FPSCR_RN(gCPU.fpscr)) {
+       case FPSCR_RN_NEAR:
+               if (s.m & 0x7) {
+                       if ((s.m & 0x7) != 4) {
+                               s.m += 4;
+                       } else if (s.m & 8) {
+                               s.m += 4;
+                       }
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_ZERO:
+               if (s.m & 0x7) {
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_PINF:
+               if (!s.s && (s.m & 0x7)) {
+                       s.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       case FPSCR_RN_MINF:
+               if (s.s && (s.m & 0x7)) {
+                       s.m += 8;
+                       return FPSCR_XX;
+               }
+               return 0;
+       }
+       return 0;
+}
+
+inline uint32 ppc_fpu_pack_double(ppc_double &d, uint64 &res)
+{
+       // .124
+       uint32 ret = 0;
+//     ht_printf("pd_type: %d\n", d.type);
+       switch (d.type) {
+       case ppc_fpr_norm:
+//             ht_printf("pd: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+               d.e += 1023; // bias exponent
+//             ht_printf("pd: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+               if (d.e > 0) {
+                       ret |= ppc_fpu_round(d);
+                       if (d.m & (1ULL<<56)) {
+                               d.e++;
+                               d.m >>= 4;
+                       } else {
+                               d.m >>= 3;
+                       }
+                       if (d.e >= 2047) {
+                               d.e = 2047;
+                               d.m = 0;
+                               ret |= FPSCR_OX;
+                       }
+               } else {
+                       // number is denormalized
+                       d.e = -d.e+1;
+                       if (d.e <= 56) {
+                               d.m >>= d.e;
+                               ret |= ppc_fpu_round(d);
+                               d.m <<= 1;
+                               if (d.m & (1ULL<<56)) {
+                                       d.e = 1;
+                                       d.m = 0;
+                               } else {
+                                       d.e = 0;
+                                       d.m >>= 4;
+                                       ret |= FPSCR_UX;
+                               }
+                       } else {
+                               // underflow to zero
+                               d.e = 0;
+                               d.m = 0;
+                               ret |= FPSCR_UX;
+                       }
+               }
+               break;
+       case ppc_fpr_zero:
+               d.e = 0;
+               d.m = 0;
+               break;
+       case ppc_fpr_NaN:
+               d.e = 2047;
+               d.m = 1;                
+               break;
+       case ppc_fpr_Inf:
+               d.e = 2047;
+               d.m = 0;
+               break;
+       }
+//     ht_printf("pd: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+       FPD_PACK_VAR(res, d.s, d.e, d.m);
+       return ret;
+}
+
+inline uint32 ppc_fpu_pack_single(ppc_double &d, uint32 &res)
+{
+       // .124
+       uint32 ret = 0;
+       switch (d.type) {
+       case ppc_fpr_norm:
+//             ht_printf("ps: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+               d.e += 127; // bias exponent
+               d.m >>= 29;
+//             ht_printf("ps: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+               if (d.e > 0) {
+                       ret |= ppc_fpu_round_single(d);
+                       if (d.m & (1ULL<<27)) {
+                               d.e++;
+                               d.m >>= 4;
+                       } else {
+                               d.m >>= 3;
+                       }
+                       if (d.e >= 255) {
+                               d.e = 255;
+                               d.m = 0;
+                               ret |= FPSCR_OX;
+                       }
+               } else {
+                       // number is denormalized
+                       d.e = -d.e+1;
+                       if (d.e <= 27) {
+                               d.m >>= d.e;
+                               ret |= ppc_fpu_round_single(d);
+                               d.m <<= 1;
+                               if (d.m & (1ULL<<27)) {
+                                       d.e = 1;
+                                       d.m = 0;
+                               } else {
+                                       d.e = 0;
+                                       d.m >>= 4;
+                                       ret |= FPSCR_UX;
+                               }
+                       } else {
+                               // underflow to zero
+                               d.e = 0;
+                               d.m = 0;
+                               ret |= FPSCR_UX;
+                       }
+               }
+               break;
+       case ppc_fpr_zero:
+               d.e = 0;
+               d.m = 0;
+               break;
+       case ppc_fpr_NaN:
+               d.e = 255;
+               d.m = 1;
+               break;
+       case ppc_fpr_Inf:
+               d.e = 255;
+               d.m = 0;
+               break;
+       }
+//     ht_printf("ps: %qx: s:%d e:%d m:%qx\n", d, d.s, d.e, d.m);
+       FPS_PACK_VAR(res, d.s, d.e, d.m);
+       return ret;
+}
+
+inline void ppc_fpu_single_to_double(ppc_single &s, ppc_double &d) 
+{
+       d.s = s.s;
+       d.e = s.e;
+       d.m = ((uint64)s.m)<<29;
+       d.type = s.type;
+}
+
+inline uint32 ppc_fpu_pack_double_as_single(ppc_double &d, uint64 &res)
+{
+       // .757
+       ppc_single s;
+       s.m = d.m >> 29;
+       s.e = d.e;
+       s.s = d.s;
+       s.type = d.type;
+       uint32 ret = 0;
+       
+       switch (s.type) {
+       case ppc_fpr_norm: 
+               s.e = d.e+127;
+               if (s.e > 0) {
+                       ret |= ppc_fpu_round_single(s);
+                       if (s.m & (1<<27)) {
+                               s.e++;
+                               s.m >>= 4;
+                       } else {
+                               s.m >>= 3;
+                       }
+                       if (s.e >= 255) {
+                               s.type = ppc_fpr_Inf;
+                               s.e = 255;
+                               s.m = 0;
+                               ret |= FPSCR_OX;
+                       }
+                       d.e = s.e-127;
+               } else {
+                       // number is denormalized
+                       s.e = -s.e+1;
+                       if (s.e <= 27) {
+                               s.m >>= s.e;
+                               ret |= ppc_fpu_round_single(s);
+                               s.m <<= 1;
+                               if (s.m & (1<<27)) {
+                                       s.e = 1;
+                                       s.m = 0;
+                               } else {
+                                       s.e = 0;
+                                       s.m >>= 4;
+                                       ret |= FPSCR_UX;
+                               }
+                       } else {
+                               // underflow to zero
+                               s.type = ppc_fpr_zero;
+                               s.e = 0;
+                               s.m = 0;
+                               ret |= FPSCR_UX;
+                       }
+               }
+               break;
+       case ppc_fpr_zero:
+               s.e = 0;
+               s.m = 0;
+               break;
+       case ppc_fpr_NaN:
+               s.e = 2047;
+               s.m = 1;                
+               break;
+       case ppc_fpr_Inf:
+               s.e = 2047;
+               s.m = 0;
+               break;
+       }       
+       if (s.type == ppc_fpr_norm) {
+               d.m = ((uint64)(s.m))<<32;
+       } else {
+               d.m = s.m;
+       }
+//     ht_printf("dm: %qx\n", d.m);
+       ret |= ppc_fpu_pack_double(d, res);
+       return ret;
+}
+
+inline uint32 ppc_fpu_double_to_int(ppc_double &d)
+{
+       switch (d.type) {
+       case ppc_fpr_norm: {
+               if (d.e < 0) {
+                       switch (FPSCR_RN(gCPU.fpscr)) {
+                       case FPSCR_RN_NEAR:
+                               if (d.e < -1) {
+                                       return 0;
+                               } else {
+                                       return d.s ? (uint32)-1 : 1;
+                               }
+                       case FPSCR_RN_ZERO:
+                               return 0;
+                       case FPSCR_RN_PINF:
+                               if (d.s) {
+                                       return 0;
+                               } else {
+                                       return 1;
+                               }
+                       case FPSCR_RN_MINF:
+                               if (d.s) {
+                                       return (uint32)-1;
+                               } else {
+                                       return 0;
+                               }
+                       }
+               }
+               if (d.e >= 31) {
+                       if (d.s) {
+                               return 0x80000000;
+                       } else {
+                               return 0x7fffffff;
+                       }
+               }               
+               int i=0;
+               uint64 mask = (1ULL<<(56 - d.e - 1))-1;
+               // we have to round
+               switch (FPSCR_RN(gCPU.fpscr)) {
+               case FPSCR_RN_NEAR:
+                       if (d.m & mask) {
+                               if (d.m & (1ULL<<(56 - d.e - 2))) {
+                                       i = 1;
+                               }
+                       }
+                       break;
+               case FPSCR_RN_ZERO:
+                       break;
+               case FPSCR_RN_PINF:
+                       if (!d.s && (d.m & mask)) {
+                               i = 1;
+                       }
+                       break;
+               case FPSCR_RN_MINF:
+                       if (d.s && (d.m & mask)) {
+                               i = 1;
+                       }
+                       break;
+               }
+               d.m >>= 56 - d.e - 1;
+               d.m += i;
+               return d.s ? -d.m : d.m;
+       }
+       case ppc_fpr_zero:
+               return 0;
+       case ppc_fpr_Inf:
+       case ppc_fpr_NaN:
+               if (d.s) {
+                       return 0x80000000;
+               } else {
+                       return 0x7fffffff;
+               }
+       }
+       return 0;
+}
+
+double ppc_fpu_get_double(uint64 d);
+double ppc_fpu_get_double(ppc_double &d);
+
+void ppc_opc_fabsx();
+void ppc_opc_faddx();
+void ppc_opc_faddsx();
+void ppc_opc_fcmpo();
+void ppc_opc_fcmpu();
+void ppc_opc_fctiwx();
+void ppc_opc_fctiwzx();
+void ppc_opc_fdivx();
+void ppc_opc_fdivsx();
+void ppc_opc_fmaddx();
+void ppc_opc_fmaddsx();
+void ppc_opc_fmrx();
+void ppc_opc_fmsubx();
+void ppc_opc_fmsubsx();
+void ppc_opc_fmulx();
+void ppc_opc_fmulsx();
+void ppc_opc_fnabsx();
+void ppc_opc_fnegx();
+void ppc_opc_fnmaddx();
+void ppc_opc_fnmaddsx();
+void ppc_opc_fnmsubx();
+void ppc_opc_fnmsubsx();
+void ppc_opc_fresx();
+void ppc_opc_frspx();
+void ppc_opc_frsqrtex();
+void ppc_opc_fselx();
+void ppc_opc_fsqrtx();
+void ppc_opc_fsqrtsx();
+void ppc_opc_fsubx();
+void ppc_opc_fsubsx();
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_mmu.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_mmu.cpp
new file mode 100644 (file)
index 0000000..0891ecb
--- /dev/null
@@ -0,0 +1,2149 @@
+/*
+ *     PearPC
+ *     ppc_mmu.cc
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *     Portions Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
+ *     Portions Copyright (C) 2004 Apple Computer, Inc.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*     Pages marked: v.???
+ *     From: IBM PowerPC MicroProcessor Family: Altivec(tm) Technology...
+ *             Programming Environments Manual
+ */
+
+#include <cstdlib>
+#include <cstring>
+#include "system/arch/sysendian.h"
+//#include "tools/snprintf.h"
+#include "debug/tracers.h"
+//#include "io/prom/prom.h"
+#include "io/io.h"
+#include "ppc_cpu.h"
+#include "ppc_fpu.h"
+#include "ppc_vec.h"
+#include "ppc_mmu.h"
+#include "ppc_exc.h"
+#include "ppc_tools.h"
+
+#if 0
+byte *gMemory = NULL;
+uint32 gMemorySize;
+#endif
+
+#undef TLB
+
+static int ppc_pte_protection[] = {
+       // read(0)/write(1) key pp
+       
+       // read
+       1, // r/w
+       1, // r/w
+       1, // r/w
+       1, // r
+       0, // -
+       1, // r
+       1, // r/w
+       1, // r
+       
+       // write
+       1, // r/w
+       1, // r/w
+       1, // r/w
+       0, // r
+       0, // -
+       0, // r
+       1, // r/w
+       0, // r
+};
+
+inline int FASTCALL ppc_effective_to_physical(uint32 addr, int flags, uint32 &result)
+{
+       if (flags & PPC_MMU_CODE) {
+               if (!(gCPU.msr & MSR_IR)) {
+                       result = addr;
+                       return PPC_MMU_OK;
+               }
+               /*
+                * BAT translation .329
+                */
+
+               uint32 batu = (gCPU.msr & MSR_PR ? BATU_Vp : BATU_Vs);          
+
+               for (int i=0; i<4; i++) {
+                       uint32 bl17 = gCPU.ibat_bl17[i];
+                       uint32 addr2 = addr & (bl17 | 0xf001ffff);
+                       if (BATU_BEPI(addr2) == BATU_BEPI(gCPU.ibatu[i])) {
+                               // bat applies to this address
+                               if (gCPU.ibatu[i] & batu) {
+                                       // bat entry valid
+                                       uint32 offset = BAT_EA_OFFSET(addr);
+                                       uint32 page = BAT_EA_11(addr);
+                                       page &= ~bl17;
+                                       page |= BATL_BRPN(gCPU.ibatl[i]);
+                                       // fixme: check access rights
+                                       result = page | offset;
+                                       return PPC_MMU_OK;
+                               }
+                       }
+               }
+       } else {
+               if (!(gCPU.msr & MSR_DR)) {
+                       result = addr;
+                       return PPC_MMU_OK;
+               }
+               /*
+                * BAT translation .329
+                */
+
+               uint32 batu = (gCPU.msr & MSR_PR ? BATU_Vp : BATU_Vs);
+
+               for (int i=0; i<4; i++) {
+                       uint32 bl17 = gCPU.dbat_bl17[i];
+                       uint32 addr2 = addr & (bl17 | 0xf001ffff);
+                       if (BATU_BEPI(addr2) == BATU_BEPI(gCPU.dbatu[i])) {
+                               // bat applies to this address
+                               if (gCPU.dbatu[i] & batu) {
+                                       // bat entry valid
+                                       uint32 offset = BAT_EA_OFFSET(addr);
+                                       uint32 page = BAT_EA_11(addr);
+                                       page &= ~bl17;
+                                       page |= BATL_BRPN(gCPU.dbatl[i]);
+                                       // fixme: check access rights
+                                       result = page | offset;
+                                       return PPC_MMU_OK;
+                               }
+                       }
+               }
+       }
+       
+       /*
+        * Address translation with segment register
+        */
+       uint32 sr = gCPU.sr[EA_SR(addr)];
+
+       if (sr & SR_T) {
+               // woea
+               // FIXME: implement me
+               PPC_MMU_ERR("sr & T\n");
+       } else {
+#ifdef TLB     
+               for (int i=0; i<4; i++) {
+                       if ((addr & ~0xfff) == (gCPU.tlb_va[i])) {
+                               gCPU.tlb_last = i;
+//                             ht_printf("TLB: %d: %08x -> %08x\n", i, addr, gCPU.tlb_pa[i] | (addr & 0xfff));
+                               result = gCPU.tlb_pa[i] | (addr & 0xfff);
+                               return PPC_MMU_OK;
+                       }
+               }
+#endif
+               // page address translation
+               if ((flags & PPC_MMU_CODE) && (sr & SR_N)) {
+                       // segment isnt executable
+                       if (!(flags & PPC_MMU_NO_EXC)) {
+                               ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_GUARD);
+                               return PPC_MMU_EXC;
+                       }
+                       return PPC_MMU_FATAL;
+               }
+               uint32 offset = EA_Offset(addr);         // 12 bit
+               uint32 page_index = EA_PageIndex(addr);  // 16 bit
+               uint32 VSID = SR_VSID(sr);               // 24 bit
+               uint32 api = EA_API(addr);               //  6 bit (part of page_index)
+               // VSID.page_index = Virtual Page Number (VPN)
+
+               // Hashfunction no 1 "xor" .360
+               uint32 hash1 = (VSID ^ page_index);
+               uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
+               int key;
+               if (gCPU.msr & MSR_PR) {
+                       key = (sr & SR_Kp) ? 4 : 0;
+               } else {
+                       key = (sr & SR_Ks) ? 4 : 0;
+               }
+
+               uint32 pte_protection_offset = ((flags&PPC_MMU_WRITE) ? 8:0) + key;
+
+               for (int i=0; i<8; i++) {
+                       uint32 pte;
+                       if (ppc_read_physical_word(pteg_addr, pte)) {
+                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                       PPC_MMU_ERR("read physical in address translate failed\n");
+                                       return PPC_MMU_EXC;
+                               }
+                               return PPC_MMU_FATAL;
+                       }
+                       if ((pte & PTE1_V) && (!(pte & PTE1_H))) {
+                               if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) {
+                                       // page found
+                                       if (ppc_read_physical_word(pteg_addr+4, pte)) {
+                                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                                       PPC_MMU_ERR("read physical in address translate failed\n");
+                                                       return PPC_MMU_EXC;
+                                               }
+                                               return PPC_MMU_FATAL;
+                                       }
+                                       // check accessmode .346
+                                       if (!ppc_pte_protection[pte_protection_offset + PTE2_PP(pte)]) {
+                                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                                       if (flags & PPC_MMU_CODE) {
+                                                               PPC_MMU_WARN("correct impl? code + read protection\n");
+                                                               ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PROT, addr);
+                                                               return PPC_MMU_EXC;
+                                                       } else {
+                                                               if (flags & PPC_MMU_WRITE) {
+                                                                       ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT | PPC_EXC_DSISR_STORE, addr);
+                                                               } else {
+                                                                       ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT, addr);
+                                                               }
+                                                               return PPC_MMU_EXC;
+                                                       }
+                                               }
+                                               return PPC_MMU_FATAL;
+                                       }
+                                       // ok..
+                                       uint32 pap = PTE2_RPN(pte);
+                                       result = pap | offset;
+#ifdef TLB
+                                       gCPU.tlb_last++;
+                                       gCPU.tlb_last &= 3;
+                                       gCPU.tlb_pa[gCPU.tlb_last] = pap;
+                                       gCPU.tlb_va[gCPU.tlb_last] = addr & ~0xfff;                                     
+//                                     ht_printf("TLB: STORE %d: %08x -> %08x\n", gCPU.tlb_last, addr, pap);
+#endif
+                                       // update access bits
+                                       if (flags & PPC_MMU_WRITE) {
+                                               pte |= PTE2_C | PTE2_R;
+                                       } else {
+                                               pte |= PTE2_R;
+                                       }
+                                       ppc_write_physical_word(pteg_addr+4, pte);
+                                       return PPC_MMU_OK;
+                               }
+                       }
+                       pteg_addr+=8;
+               }
+               
+               // Hashfunction no 2 "not" .360
+               hash1 = ~hash1;
+               pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
+               for (int i=0; i<8; i++) {
+                       uint32 pte;
+                       if (ppc_read_physical_word(pteg_addr, pte)) {
+                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                       PPC_MMU_ERR("read physical in address translate failed\n");
+                                       return PPC_MMU_EXC;
+                               }
+                               return PPC_MMU_FATAL;
+                       }
+                       if ((pte & PTE1_V) && (pte & PTE1_H)) {
+                               if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) {
+                                       // page found
+                                       if (ppc_read_physical_word(pteg_addr+4, pte)) {
+                                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                                       PPC_MMU_ERR("read physical in address translate failed\n");
+                                                       return PPC_MMU_EXC;
+                                               }
+                                               return PPC_MMU_FATAL;
+                                       }
+                                       // check accessmode
+                                       int key;
+                                       if (gCPU.msr & MSR_PR) {
+                                               key = (sr & SR_Kp) ? 4 : 0;
+                                       } else {
+                                               key = (sr & SR_Ks) ? 4 : 0;
+                                       }
+                                       if (!ppc_pte_protection[((flags&PPC_MMU_WRITE)?8:0) + key + PTE2_PP(pte)]) {
+                                               if (!(flags & PPC_MMU_NO_EXC)) {
+                                                       if (flags & PPC_MMU_CODE) {
+                                                               PPC_MMU_WARN("correct impl? code + read protection\n");
+                                                               ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PROT, addr);
+                                                               return PPC_MMU_EXC;
+                                                       } else {
+                                                               if (flags & PPC_MMU_WRITE) {
+                                                                       ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT | PPC_EXC_DSISR_STORE, addr);
+                                                               } else {
+                                                                       ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT, addr);
+                                                               }
+                                                               return PPC_MMU_EXC;
+                                                       }
+                                               }
+                                               return PPC_MMU_FATAL;
+                                       }
+                                       // ok..
+                                       result = PTE2_RPN(pte) | offset;
+                                       
+                                       // update access bits
+                                       if (flags & PPC_MMU_WRITE) {
+                                               pte |= PTE2_C | PTE2_R;
+                                       } else {
+                                               pte |= PTE2_R;
+                                       }
+                                       ppc_write_physical_word(pteg_addr+4, pte);
+//                                     PPC_MMU_WARN("hash function 2 used!\n");
+//                                     gSinglestep = true;
+                                       return PPC_MMU_OK;
+                               }
+                       }
+                       pteg_addr+=8;
+               }
+       }
+       // page fault
+       if (!(flags & PPC_MMU_NO_EXC)) {
+               if (flags & PPC_MMU_CODE) {
+                       ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PAGE);
+               } else {
+                       if (flags & PPC_MMU_WRITE) {
+                               ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE, addr);
+                       } else {
+                               ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PAGE, addr);
+                       }
+               }
+               return PPC_MMU_EXC;
+       }
+       return PPC_MMU_FATAL;
+}
+
+void ppc_mmu_tlb_invalidate()
+{
+       gCPU.effective_code_page = 0xffffffff;
+}
+
+/*
+pagetable:
+min. 2^10 (64k) PTEGs
+PTEG = 64byte
+The page table can be any size 2^n where 16 <= n <= 25.
+
+A PTEG contains eight
+PTEs of eight bytes each; therefore, each PTEG is 64 bytes long.
+*/
+
+bool FASTCALL ppc_mmu_set_sdr1(uint32 newval, bool quiesce)
+{
+       /* if (newval == gCPU.sdr1)*/ quiesce = false;
+       PPC_MMU_TRACE("new pagetable: sdr1 = 0x%08x\n", newval);
+       uint32 htabmask = SDR1_HTABMASK(newval);
+       uint32 x = 1;
+       uint32 xx = 0;
+       int n = 0;
+       while ((htabmask & x) && (n < 9)) {
+               n++;
+               xx|=x;
+               x<<=1;
+       }
+       if (htabmask & ~xx) {
+               PPC_MMU_TRACE("new pagetable: broken htabmask (%05x)\n", htabmask);
+               return false;
+       }
+       uint32 htaborg = SDR1_HTABORG(newval);
+       if (htaborg & xx) {
+               PPC_MMU_TRACE("new pagetable: broken htaborg (%05x)\n", htaborg);
+               return false;
+       }
+       gCPU.pagetable_base = htaborg<<16;
+       gCPU.sdr1 = newval;
+       gCPU.pagetable_hashmask = ((xx<<10)|0x3ff);
+       PPC_MMU_TRACE("new pagetable: sdr1 accepted\n");
+       PPC_MMU_TRACE("number of pages: 2^%d pagetable_start: 0x%08x size: 2^%d\n", n+13, gCPU.pagetable_base, n+16);
+#if 0
+       if (quiesce) {
+               prom_quiesce();
+       }
+#endif
+       return true;
+}
+
+bool FASTCALL ppc_mmu_page_create(uint32 ea, uint32 pa)
+{
+       uint32 sr = gCPU.sr[EA_SR(ea)];
+       uint32 page_index = EA_PageIndex(ea);  // 16 bit
+       uint32 VSID = SR_VSID(sr);             // 24 bit
+       uint32 api = EA_API(ea);               //  6 bit (part of page_index)
+       uint32 hash1 = (VSID ^ page_index);
+       uint32 pte, pte2;
+       uint32 h = 0;
+       for (int j=0; j<2; j++) {
+               uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
+               for (int i=0; i<8; i++) {
+                       if (ppc_read_physical_word(pteg_addr, pte)) {
+                               PPC_MMU_ERR("read physical in address translate failed\n");
+                               return false;
+                       }
+                       if (!(pte & PTE1_V)) {
+                               // free pagetable entry found
+                               pte = PTE1_V | (VSID << 7) | h | api;
+                               pte2 = (PA_RPN(pa) << 12) | 0;
+                               if (ppc_write_physical_word(pteg_addr, pte)
+                                || ppc_write_physical_word(pteg_addr+4, pte2)) {
+                                       return false;
+                               } else {
+                                       // ok
+                                       return true;
+                               }
+                       }
+                       pteg_addr+=8;
+               }
+               hash1 = ~hash1;
+               h = PTE1_H;
+       }
+       return false;
+}
+
+inline bool FASTCALL ppc_mmu_page_free(uint32 ea)
+{
+       return true;
+}
+
+extern bool uae_ppc_direct_physical_memory_handle(uint32, byte *&ptr);
+
+inline int FASTCALL ppc_direct_physical_memory_handle(uint32 addr, byte *&ptr)
+{
+       if (uae_ppc_direct_physical_memory_handle(addr, ptr))
+               return PPC_MMU_OK;
+       return PPC_MMU_FATAL;
+}
+
+int FASTCALL ppc_direct_effective_memory_handle(uint32 addr, byte *&ptr)
+{
+       uint32 ea;
+       int r;
+       if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, ea)))) {
+               return ppc_direct_physical_memory_handle(ea, ptr);
+       }
+       return r;
+}
+
+int FASTCALL ppc_direct_effective_memory_handle_code(uint32 addr, byte *&ptr)
+{
+       uint32 ea;
+       int r;
+       if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, ea)))) {
+               return ppc_direct_physical_memory_handle(ea, ptr);
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_read_physical_qword(uint32 addr, Vector_t &result)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               VECT_D(result,0) = ppc_dword_from_BE(*((uint64*)(gMemory+addr)));
+               VECT_D(result,1) = ppc_dword_from_BE(*((uint64*)(gMemory+addr+8)));
+               return PPC_MMU_OK;
+       }
+#endif
+       return io_mem_read128(addr, (uint128 *)&result);
+}
+
+inline int FASTCALL ppc_read_physical_dword(uint32 addr, uint64 &result)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               result = ppc_dword_from_BE(*((uint64*)(gMemory+addr)));
+               return PPC_MMU_OK;
+       }
+#endif
+       int ret = io_mem_read64(addr, result);
+       //result = ppc_bswap_dword(result);
+       return ret;
+}
+
+inline int FASTCALL ppc_read_physical_word(uint32 addr, uint32 &result)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               result = ppc_word_from_BE(*((uint32*)(gMemory+addr)));
+               return PPC_MMU_OK;
+       }
+#endif
+       int ret = io_mem_read(addr, result, 4);
+       //result = ppc_bswap_word(result);
+       return ret;
+}
+
+inline int FASTCALL ppc_read_physical_half(uint32 addr, uint16 &result)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               result = ppc_half_from_BE(*((uint16*)(gMemory+addr)));
+               return PPC_MMU_OK;
+       }
+#endif
+       uint32 r;
+       int ret = io_mem_read(addr, r, 2);
+       //result = ppc_bswap_half(r);
+       result = r;
+       return ret;
+}
+
+inline int FASTCALL ppc_read_physical_byte(uint32 addr, uint8 &result)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               result = gMemory[addr];
+               return PPC_MMU_OK;
+       }
+#endif
+       uint32 r;
+       int ret = io_mem_read(addr, r, 1);
+       result = r;
+       return ret;
+}
+
+inline int FASTCALL ppc_read_effective_code(uint32 addr, uint32 &result)
+{
+       if (addr & 3) {
+               // EXC..bla
+               return PPC_MMU_FATAL;
+       }
+       uint32 p;
+       int r;
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, p)))) {
+               return ppc_read_physical_word(p, result);
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_read_effective_qword(uint32 addr, Vector_t &result)
+{
+       uint32 p;
+       int r;
+
+       addr &= ~0x0f;
+
+       if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
+               return ppc_read_physical_qword(p, result);
+       }
+
+       return r;
+}
+
+inline int FASTCALL ppc_read_effective_dword(uint32 addr, uint64 &result)
+{
+       uint32 p;
+       int r;
+       if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
+               if (EA_Offset(addr) > 4088) {
+                       // read overlaps two pages.. tricky
+                       byte *r1, *r2;
+                       byte b[14];
+                       ppc_effective_to_physical((addr & ~0xfff)+4089, PPC_MMU_READ, p);
+                       if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
+                       if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
+                       memmove(&b[0], r1, 7);
+                       memmove(&b[7], r2, 7);
+                       memmove(&result, &b[EA_Offset(addr)-4089], 8);
+                       result = ppc_dword_from_BE(result);
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_read_physical_dword(p, result);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_read_effective_word(uint32 addr, uint32 &result)
+{
+       uint32 p;
+       int r;
+       if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
+               if (EA_Offset(addr) > 4092) {
+                       // read overlaps two pages.. tricky
+                       byte *r1, *r2;
+                       byte b[6];
+                       ppc_effective_to_physical((addr & ~0xfff)+4093, PPC_MMU_READ, p);
+                       if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
+                       if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
+                       memmove(&b[0], r1, 3);
+                       memmove(&b[3], r2, 3);
+                       memmove(&result, &b[EA_Offset(addr)-4093], 4);
+                       result = ppc_word_from_BE(result);
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_read_physical_word(p, result);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_read_effective_half(uint32 addr, uint16 &result)
+{
+       uint32 p;
+       int r;
+       if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, p)))) {
+               if (EA_Offset(addr) > 4094) {
+                       // read overlaps two pages.. tricky
+                       byte b1, b2;
+                       ppc_effective_to_physical((addr & ~0xfff)+4095, PPC_MMU_READ, p);
+                       if ((r = ppc_read_physical_byte(p, b1))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
+                       if ((r = ppc_read_physical_byte(p, b2))) return r;
+                       result = (b1<<8)|b2;
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_read_physical_half(p, result);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_read_effective_byte(uint32 addr, uint8 &result)
+{
+       uint32 p;
+       int r;
+       if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, p)))) {
+               return ppc_read_physical_byte(p, result);
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_write_physical_qword(uint32 addr, Vector_t data)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               *((uint64*)(gMemory+addr)) = ppc_dword_to_BE(VECT_D(data,0));
+               *((uint64*)(gMemory+addr+8)) = ppc_dword_to_BE(VECT_D(data,1));
+               return PPC_MMU_OK;
+       }
+#endif
+       if (io_mem_write128(addr, (uint128 *)&data) == IO_MEM_ACCESS_OK) {
+               return PPC_MMU_OK;
+       } else {
+               return PPC_MMU_FATAL;
+       }
+}
+
+inline int FASTCALL ppc_write_physical_dword(uint32 addr, uint64 data)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               *((uint64*)(gMemory+addr)) = ppc_dword_to_BE(data);
+               return PPC_MMU_OK;
+       }
+#endif
+//     if (io_mem_write64(addr, ppc_bswap_dword(data)) == IO_MEM_ACCESS_OK) {
+       if (io_mem_write64(addr, data) == IO_MEM_ACCESS_OK) {
+                       return PPC_MMU_OK;
+       } else {
+               return PPC_MMU_FATAL;
+       }
+}
+
+inline int FASTCALL ppc_write_physical_word(uint32 addr, uint32 data)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               *((uint32*)(gMemory+addr)) = ppc_word_to_BE(data);
+               return PPC_MMU_OK;
+       }
+#endif
+       //return io_mem_write(addr, ppc_bswap_word(data), 4);
+       return io_mem_write(addr, data, 4);
+}
+
+inline int FASTCALL ppc_write_physical_half(uint32 addr, uint16 data)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               *((uint16*)(gMemory+addr)) = ppc_half_to_BE(data);
+               return PPC_MMU_OK;
+       }
+#endif
+       //return io_mem_write(addr, ppc_bswap_half(data), 2);
+       return io_mem_write(addr, data, 2);
+}
+
+inline int FASTCALL ppc_write_physical_byte(uint32 addr, uint8 data)
+{
+#if 0
+       if (addr < gMemorySize) {
+               // big endian
+               gMemory[addr] = data;
+               return PPC_MMU_OK;
+       }
+#endif
+       return io_mem_write(addr, data, 1);
+}
+
+inline int FASTCALL ppc_write_effective_qword(uint32 addr, Vector_t data)
+{
+       uint32 p;
+       int r;
+
+       addr &= ~0x0f;
+
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
+               return ppc_write_physical_qword(p, data);
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_write_effective_dword(uint32 addr, uint64 data)
+{
+       uint32 p;
+       int r;
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
+               if (EA_Offset(addr) > 4088) {
+                       // write overlaps two pages.. tricky
+                       byte *r1, *r2;
+                       byte b[14];
+                       ppc_effective_to_physical((addr & ~0xfff)+4089, PPC_MMU_WRITE, p);
+                       if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
+                       if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
+                       data = ppc_dword_to_BE(data);
+                       memmove(&b[0], r1, 7);
+                       memmove(&b[7], r2, 7);
+                       memmove(&b[EA_Offset(addr)-4089], &data, 8);
+                       memmove(r1, &b[0], 7);
+                       memmove(r2, &b[7], 7);
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_write_physical_dword(p, data);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_write_effective_word(uint32 addr, uint32 data)
+{
+       uint32 p;
+       int r;
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
+               if (EA_Offset(addr) > 4092) {
+                       // write overlaps two pages.. tricky
+                       byte *r1, *r2;
+                       byte b[6];
+                       ppc_effective_to_physical((addr & ~0xfff)+4093, PPC_MMU_WRITE, p);
+                       if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
+                       if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
+                       data = ppc_word_to_BE(data);
+                       memmove(&b[0], r1, 3);
+                       memmove(&b[3], r2, 3);
+                       memmove(&b[EA_Offset(addr)-4093], &data, 4);
+                       memmove(r1, &b[0], 3);
+                       memmove(r2, &b[3], 3);
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_write_physical_word(p, data);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_write_effective_half(uint32 addr, uint16 data)
+{
+       uint32 p;
+       int r;
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
+               if (EA_Offset(addr) > 4094) {
+                       // write overlaps two pages.. tricky
+                       ppc_effective_to_physical((addr & ~0xfff)+4095, PPC_MMU_WRITE, p);
+                       if ((r = ppc_write_physical_byte(p, data>>8))) return r;
+                       if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
+                       if ((r = ppc_write_physical_byte(p, data))) return r;
+                       return PPC_MMU_OK;
+               } else {
+                       return ppc_write_physical_half(p, data);
+               }
+       }
+       return r;
+}
+
+inline int FASTCALL ppc_write_effective_byte(uint32 addr, uint8 data)
+{
+       uint32 p;
+       int r;
+       if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
+               return ppc_write_physical_byte(p, data);
+       }
+       return r;
+}
+
+bool FASTCALL ppc_init_physical_memory(uint size)
+{
+#if 0
+       if (size < 64*1024*1024) {
+               PPC_MMU_ERR("Main memory size must >= 64MB!\n");
+       }
+       gMemory = (byte*)malloc(size);
+       gMemorySize = size;
+       return gMemory != NULL;
+#else
+       return NULL;
+#endif
+}
+
+uint32  ppc_get_memory_size()
+{
+       return 0; //return gMemorySize;
+}
+
+/***************************************************************************
+ *     DMA Interface
+ */
+
+bool   ppc_dma_write(uint32 dest, const void *src, uint32 size)
+{
+#if 0
+       if (dest > gMemorySize || (dest+size) > gMemorySize) return false;
+#endif 
+       byte *ptr;
+       ppc_direct_physical_memory_handle(dest, ptr);
+       
+       memcpy(ptr, src, size);
+       return true;
+}
+
+bool   ppc_dma_read(void *dest, uint32 src, uint32 size)
+{
+#if 0
+       if (src > gMemorySize || (src + size) > gMemorySize) return false;
+#endif 
+       byte *ptr;
+       ppc_direct_physical_memory_handle(src, ptr);
+       
+       memcpy(dest, ptr, size);
+       return true;
+}
+
+bool   ppc_dma_set(uint32 dest, int c, uint32 size)
+{
+#if 0
+       if (dest > gMemorySize || (dest+size) > gMemorySize) return false;
+#endif 
+       byte *ptr;
+       ppc_direct_physical_memory_handle(dest, ptr);
+       
+       memset(ptr, c, size);
+       return true;
+}
+
+/***************************************************************************
+ *     MMU Opcodes
+ */
+
+#include "ppc_dec.h"
+
+/*
+ *     dcbz            Data Cache Clear to Zero
+ *     .464
+ */
+void ppc_opc_dcbz()
+{
+       //PPC_L1_CACHE_LINE_SIZE
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       // assert rD=0
+       uint32 a = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
+       // BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+       ppc_write_effective_dword(a, 0)
+       || ppc_write_effective_dword(a+8, 0)
+       || ppc_write_effective_dword(a+16, 0)
+       || ppc_write_effective_dword(a+24, 0);
+}
+
+/*
+ *     lbz             Load Byte and Zero
+ *     .521
+ */
+void ppc_opc_lbz()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint8 r;
+       int ret = ppc_read_effective_byte((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lbzu            Load Byte and Zero with Update
+ *     .522
+ */
+void ppc_opc_lbzu()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       // FIXME: check rA!=0 && rA!=rD
+       uint8 r;
+       int ret = ppc_read_effective_byte(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+               gCPU.gpr[rD] = r;
+       }       
+}
+/*
+ *     lbzux           Load Byte and Zero with Update Indexed
+ *     .523
+ */
+void ppc_opc_lbzux()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       // FIXME: check rA!=0 && rA!=rD
+       uint8 r;
+       int ret = ppc_read_effective_byte(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lbzx            Load Byte and Zero Indexed
+ *     .524
+ */
+void ppc_opc_lbzx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint8 r;
+       int ret = ppc_read_effective_byte((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lfd             Load Floating-Point Double
+ *     .530
+ */
+void ppc_opc_lfd()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
+       uint64 r;
+       int ret = ppc_read_effective_dword((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.fpr[frD] = r;
+       }       
+}
+/*
+ *     lfdu            Load Floating-Point Double with Update
+ *     .531
+ */
+void ppc_opc_lfdu()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
+       // FIXME: check rA!=0
+       uint64 r;
+       int ret = ppc_read_effective_dword(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.fpr[frD] = r;
+               gCPU.gpr[rA] += imm;
+       }       
+}
+/*
+ *     lfdux           Load Floating-Point Double with Update Indexed
+ *     .532
+ */
+void ppc_opc_lfdux()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
+       // FIXME: check rA!=0
+       uint64 r;
+       int ret = ppc_read_effective_dword(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               gCPU.fpr[frD] = r;
+       }       
+}
+/*
+ *     lfdx            Load Floating-Point Double Indexed
+ *     .533
+ */
+void ppc_opc_lfdx()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
+       uint64 r;
+       int ret = ppc_read_effective_dword((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.fpr[frD] = r;
+       }       
+}
+/*
+ *     lfs             Load Floating-Point Single
+ *     .534
+ */
+void ppc_opc_lfs()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               ppc_single s;
+               ppc_double d;
+               ppc_fpu_unpack_single(s, r);
+               ppc_fpu_single_to_double(s, d);
+               ppc_fpu_pack_double(d, gCPU.fpr[frD]);
+       }       
+}
+/*
+ *     lfsu            Load Floating-Point Single with Update
+ *     .535
+ */
+void ppc_opc_lfsu()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
+       // FIXME: check rA!=0
+       uint32 r;
+       int ret = ppc_read_effective_word(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               ppc_single s;
+               ppc_double d;
+               ppc_fpu_unpack_single(s, r);
+               ppc_fpu_single_to_double(s, d);
+               ppc_fpu_pack_double(d, gCPU.fpr[frD]);
+               gCPU.gpr[rA] += imm;
+       }       
+}
+/*
+ *     lfsux           Load Floating-Point Single with Update Indexed
+ *     .536
+ */
+void ppc_opc_lfsux()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
+       // FIXME: check rA!=0
+       uint32 r;
+       int ret = ppc_read_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               ppc_single s;
+               ppc_double d;
+               ppc_fpu_unpack_single(s, r);
+               ppc_fpu_single_to_double(s, d);
+               ppc_fpu_pack_double(d, gCPU.fpr[frD]);
+       }       
+}
+/*
+ *     lfsx            Load Floating-Point Single Indexed
+ *     .537
+ */
+void ppc_opc_lfsx()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               ppc_single s;
+               ppc_double d;
+               ppc_fpu_unpack_single(s, r);
+               ppc_fpu_single_to_double(s, d);
+               ppc_fpu_pack_double(d, gCPU.fpr[frD]);
+       }       
+}
+/*
+ *     lha             Load Half Word Algebraic
+ *     .538
+ */
+void ppc_opc_lha()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint16 r;
+       int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
+       }
+}
+/*
+ *     lhau            Load Half Word Algebraic with Update
+ *     .539
+ */
+void ppc_opc_lhau()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint16 r;
+       // FIXME: rA != 0
+       int ret = ppc_read_effective_half(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+               gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
+       }
+}
+/*
+ *     lhaux           Load Half Word Algebraic with Update Indexed
+ *     .540
+ */
+void ppc_opc_lhaux()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint16 r;
+       // FIXME: rA != 0
+       int ret = ppc_read_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
+       }
+}
+/*
+ *     lhax            Load Half Word Algebraic Indexed
+ *     .541
+ */
+void ppc_opc_lhax()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint16 r;
+       // FIXME: rA != 0
+       int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = (r&0x8000) ? (r|0xffff0000):r;
+       }
+}
+/*
+ *     lhbrx           Load Half Word Byte-Reverse Indexed
+ *     .542
+ */
+void ppc_opc_lhbrx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint16 r;
+       int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = ppc_bswap_half(r);
+       }
+}
+/*
+ *     lhz             Load Half Word and Zero
+ *     .543
+ */
+void ppc_opc_lhz()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint16 r;
+       int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lhzu            Load Half Word and Zero with Update
+ *     .544
+ */
+void ppc_opc_lhzu()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint16 r;
+       // FIXME: rA!=0
+       int ret = ppc_read_effective_half(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     lhzux           Load Half Word and Zero with Update Indexed
+ *     .545
+ */
+void ppc_opc_lhzux()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint16 r;
+       // FIXME: rA != 0
+       int ret = ppc_read_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lhzx            Load Half Word and Zero Indexed
+ *     .546
+ */
+void ppc_opc_lhzx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint16 r;
+       int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lmw             Load Multiple Word
+ *     .547
+ */
+void ppc_opc_lmw()
+{
+       int rD, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint32 ea = (rA ? gCPU.gpr[rA] : 0) + imm;
+       while (rD <= 31) {
+               if (ppc_read_effective_word(ea, gCPU.gpr[rD])) {
+                       return;
+               }
+               rD++;
+               ea += 4;
+       }
+}
+/*
+ *     lswi            Load String Word Immediate
+ *     .548
+ */
+void ppc_opc_lswi()
+{
+       int rA, rD, NB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, NB);
+       if (NB==0) NB=32;
+       uint32 ea = rA ? gCPU.gpr[rA] : 0;
+       uint32 r = 0;
+       int i = 4;
+       uint8 v;
+       while (NB > 0) {
+               if (!i) {
+                       i = 4;
+                       gCPU.gpr[rD] = r;
+                       rD++;
+                       rD%=32;
+                       r = 0;
+               }
+               if (ppc_read_effective_byte(ea, v)) {
+                       return;
+               }
+               r<<=8;
+               r|=v;
+               ea++;
+               i--;
+               NB--;
+       }
+       while (i) { r<<=8; i--; }
+       gCPU.gpr[rD] = r;
+}
+/*
+ *     lswx            Load String Word Indexed
+ *     .550
+ */
+void ppc_opc_lswx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       int NB = XER_n(gCPU.xer);
+       uint32 ea = gCPU.gpr[rB] + (rA ? gCPU.gpr[rA] : 0);
+
+       uint32 r = 0;
+       int i = 4;
+       uint8 v;
+       while (NB > 0) {
+               if (!i) {
+                       i = 4;
+                       gCPU.gpr[rD] = r;
+                       rD++;
+                       rD%=32;
+                       r = 0;
+               }
+               if (ppc_read_effective_byte(ea, v)) {
+                       return;
+               }
+               r<<=8;
+               r|=v;
+               ea++;
+               i--;
+               NB--;
+       }
+       while (i) { r<<=8; i--; }
+       gCPU.gpr[rD] = r;
+}
+/*
+ *     lwarx           Load Word and Reserve Indexed
+ *     .553
+ */
+void ppc_opc_lwarx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+               gCPU.reserve = r;
+               gCPU.have_reservation = 1;
+       }
+}
+/*
+ *     lwbrx           Load Word Byte-Reverse Indexed
+ *     .556
+ */
+void ppc_opc_lwbrx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = ppc_bswap_word(r);
+       }
+}
+/*
+ *     lwz             Load Word and Zero
+ *     .557
+ */
+void ppc_opc_lwz()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }       
+}
+/*
+ *     lbzu            Load Word and Zero with Update
+ *     .558
+ */
+void ppc_opc_lwzu()
+{
+       int rA, rD;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
+       // FIXME: check rA!=0 && rA!=rD
+       uint32 r;
+       int ret = ppc_read_effective_word(gCPU.gpr[rA]+imm, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+               gCPU.gpr[rD] = r;
+       }       
+}
+/*
+ *     lwzux           Load Word and Zero with Update Indexed
+ *     .559
+ */
+void ppc_opc_lwzux()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       // FIXME: check rA!=0 && rA!=rD
+       uint32 r;
+       int ret = ppc_read_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+               gCPU.gpr[rD] = r;
+       }
+}
+/*
+ *     lwzx            Load Word and Zero Indexed
+ *     .560
+ */
+void ppc_opc_lwzx()
+{
+       int rA, rD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       uint32 r;
+       int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rD] = r;
+       }
+}
+
+/*      lvx         Load Vector Indexed
+ *      v.127
+ */
+void ppc_opc_lvx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       Vector_t r;
+
+       int ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
+
+       int ret = ppc_read_effective_qword(ea, r);
+       if (ret == PPC_MMU_OK) {
+               gCPU.vr[vrD] = r;
+       }
+}
+
+/*      lvxl       Load Vector Index LRU
+ *      v.128
+ */
+void ppc_opc_lvxl()
+{
+       ppc_opc_lvx();
+       /* This instruction should hint to the cache that the value won't be
+        *   needed again in memory anytime soon.  We don't emulate the cache,
+        *   so this is effectively exactly the same as lvx.
+        */
+}
+
+/*      lvebx     Load Vector Element Byte Indexed
+ *      v.119
+ */
+void ppc_opc_lvebx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       uint32 ea;
+       uint8 r;
+       ea = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
+       int ret = ppc_read_effective_byte(ea, r);
+       if (ret == PPC_MMU_OK) {
+               VECT_B(gCPU.vr[vrD], ea & 0xf) = r;
+       }
+}
+
+/*      lvehx     Load Vector Element Half Word Indexed
+ *      v.121
+ */
+void ppc_opc_lvehx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       uint32 ea;
+       uint16 r;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~1;
+       int ret = ppc_read_effective_half(ea, r);
+       if (ret == PPC_MMU_OK) {
+               VECT_H(gCPU.vr[vrD], (ea & 0xf) >> 1) = r;
+       }
+}
+
+/*      lvewx     Load Vector Element Word Indexed
+ *      v.122
+ */
+void ppc_opc_lvewx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       uint32 ea;
+       uint32 r;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~3;
+       int ret = ppc_read_effective_word(ea, r);
+       if (ret == PPC_MMU_OK) {
+               VECT_W(gCPU.vr[vrD], (ea & 0xf) >> 2) = r;
+       }
+}
+
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+static byte lvsl_helper[] = {
+       0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
+       0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+       0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
+       0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
+};
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+static byte lvsl_helper[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+       0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+};
+#else
+#error Endianess not supported!
+#endif
+
+/*
+ *      lvsl       Load Vector for Shift Left
+ *      v.123
+ */
+void ppc_opc_lvsl()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       uint32 ea;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+       memmove(&gCPU.vr[vrD], lvsl_helper+0x10-(ea & 0xf), 16);
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+       memmove(&gCPU.vr[vrD], lvsl_helper+(ea & 0xf), 16);
+#else
+#error Endianess not supported!
+#endif
+}
+
+/*
+ *      lvsr       Load Vector for Shift Right
+ *      v.125
+ */
+void ppc_opc_lvsr()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrD, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
+       uint32 ea;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+       memmove(&gCPU.vr[vrD], lvsl_helper+(ea & 0xf), 16);
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+       memmove(&gCPU.vr[vrD], lvsl_helper+0x10-(ea & 0xf), 16);
+#else
+#error Endianess not supported!
+#endif
+}
+
+/*
+ *      dst         Data Stream Touch
+ *      v.115
+ */
+void ppc_opc_dst()
+{
+       VECTOR_DEBUG;
+       /* Since we are not emulating the cache, this is a nop */
+}
+
+/*
+ *     stb             Store Byte
+ *     .632
+ */
+void ppc_opc_stb()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       ppc_write_effective_byte((rA?gCPU.gpr[rA]:0)+imm, (uint8)gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stbu            Store Byte with Update
+ *     .633
+ */
+void ppc_opc_stbu()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_byte(gCPU.gpr[rA]+imm, (uint8)gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     stbux           Store Byte with Update Indexed
+ *     .634
+ */
+void ppc_opc_stbux()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_byte(gCPU.gpr[rA]+gCPU.gpr[rB], (uint8)gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+       }
+}
+/*
+ *     stbx            Store Byte Indexed
+ *     .635
+ */
+void ppc_opc_stbx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       ppc_write_effective_byte((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint8)gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stfd            Store Floating-Point Double
+ *     .642
+ */
+void ppc_opc_stfd()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
+       ppc_write_effective_dword((rA?gCPU.gpr[rA]:0)+imm, gCPU.fpr[frS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stfdu           Store Floating-Point Double with Update
+ *     .643
+ */
+void ppc_opc_stfdu()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_dword(gCPU.gpr[rA]+imm, gCPU.fpr[frS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     stfd            Store Floating-Point Double with Update Indexed
+ *     .644
+ */
+void ppc_opc_stfdux()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_dword(gCPU.gpr[rA]+gCPU.gpr[rB], gCPU.fpr[frS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+       }
+}
+/*
+ *     stfdx           Store Floating-Point Double Indexed
+ *     .645
+ */
+void ppc_opc_stfdx()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
+       ppc_write_effective_dword((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.fpr[frS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stfiwx          Store Floating-Point as Integer Word Indexed
+ *     .646
+ */
+void ppc_opc_stfiwx()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint32)gCPU.fpr[frS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stfs            Store Floating-Point Single
+ *     .647
+ */
+void ppc_opc_stfs()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
+       uint32 s;
+       ppc_double d;
+       ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
+       ppc_fpu_pack_single(d, s);
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+imm, s) != PPC_MMU_FATAL;
+}
+/*
+ *     stfsu           Store Floating-Point Single with Update
+ *     .648
+ */
+void ppc_opc_stfsu()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
+       // FIXME: check rA!=0
+       uint32 s;
+       ppc_double d;
+       ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
+       ppc_fpu_pack_single(d, s);
+       int ret = ppc_write_effective_word(gCPU.gpr[rA]+imm, s);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     stfsux          Store Floating-Point Single with Update Indexed
+ *     .649
+ */
+void ppc_opc_stfsux()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
+       // FIXME: check rA!=0
+       uint32 s;
+       ppc_double d;
+       ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
+       ppc_fpu_pack_single(d, s);
+       int ret = ppc_write_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], s);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+       }
+}
+/*
+ *     stfsx           Store Floating-Point Single Indexed
+ *     .650
+ */
+void ppc_opc_stfsx()
+{
+       if ((gCPU.msr & MSR_FP) == 0) {
+               ppc_exception(PPC_EXC_NO_FPU);
+               return;
+       }
+       int rA, frS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
+       uint32 s;
+       ppc_double d;
+       ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
+       ppc_fpu_pack_single(d, s);
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], s) != PPC_MMU_FATAL;
+}
+/*
+ *     sth             Store Half Word
+ *     .651
+ */
+void ppc_opc_sth()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+imm, (uint16)gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+/*
+ *     sthbrx          Store Half Word Byte-Reverse Indexed
+ *     .652
+ */
+void ppc_opc_sthbrx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], ppc_bswap_half(gCPU.gpr[rS])) != PPC_MMU_FATAL;
+}
+/*
+ *     sthu            Store Half Word with Update
+ *     .653
+ */
+void ppc_opc_sthu()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_half(gCPU.gpr[rA]+imm, (uint16)gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     sthux           Store Half Word with Update Indexed
+ *     .654
+ */
+void ppc_opc_sthux()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], (uint16)gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+       }
+}
+/*
+ *     sthx            Store Half Word Indexed
+ *     .655
+ */
+void ppc_opc_sthx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint16)gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stmw            Store Multiple Word
+ *     .656
+ */
+void ppc_opc_stmw()
+{
+       int rS, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       uint32 ea = (rA ? gCPU.gpr[rA] : 0) + imm;
+       while (rS <= 31) {
+               if (ppc_write_effective_word(ea, gCPU.gpr[rS])) {
+                       return;
+               }
+               rS++;
+               ea += 4;
+       }
+}
+/*
+ *     stswi           Store String Word Immediate
+ *     .657
+ */
+void ppc_opc_stswi()
+{
+       int rA, rS, NB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, NB);
+       if (NB==0) NB=32;
+       uint32 ea = rA ? gCPU.gpr[rA] : 0;
+       uint32 r = 0;
+       int i = 0;
+       
+       while (NB > 0) {
+               if (!i) {
+                       r = gCPU.gpr[rS];
+                       rS++;
+                       rS%=32;
+                       i = 4;
+               }
+               if (ppc_write_effective_byte(ea, (r>>24))) {
+                       return;
+               }
+               r<<=8;
+               ea++;
+               i--;
+               NB--;
+       }
+}
+/*
+ *     stswx           Store String Word Indexed
+ *     .658
+ */
+void ppc_opc_stswx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       int NB = XER_n(gCPU.xer);
+       uint32 ea = gCPU.gpr[rB] + (rA ? gCPU.gpr[rA] : 0);
+       uint32 r = 0;
+       int i = 0;
+       
+       while (NB > 0) {
+               if (!i) {
+                       r = gCPU.gpr[rS];
+                       rS++;
+                       rS%=32;
+                       i = 4;
+               }
+               if (ppc_write_effective_byte(ea, (r>>24))) {
+                       return;
+               }
+               r<<=8;
+               ea++;
+               i--;
+               NB--;
+       }
+}
+/*
+ *     stw             Store Word
+ *     .659
+ */
+void ppc_opc_stw()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+imm, gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+/*
+ *     stwbrx          Store Word Byte-Reverse Indexed
+ *     .660
+ */
+void ppc_opc_stwbrx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: doppelt gemoppelt
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], ppc_bswap_word(gCPU.gpr[rS])) != PPC_MMU_FATAL;
+}
+/*
+ *     stwcx.          Store Word Conditional Indexed
+ *     .661
+ */
+void ppc_opc_stwcx_()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       gCPU.cr &= 0x0fffffff;
+       if (gCPU.have_reservation) {
+               gCPU.have_reservation = false;
+               uint32 v;
+               if (ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], v)) {
+                       return;
+               }
+               if (v==gCPU.reserve) {
+                       if (ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.gpr[rS])) {
+                               return;
+                       }
+                       gCPU.cr |= CR_CR0_EQ;
+               }
+               if (gCPU.xer & XER_SO) {
+                       gCPU.cr |= CR_CR0_SO;
+               }
+       }
+}
+/*
+ *     stwu            Store Word with Update
+ *     .663
+ */
+void ppc_opc_stwu()
+{
+       int rA, rS;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_word(gCPU.gpr[rA]+imm, gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += imm;
+       }
+}
+/*
+ *     stwux           Store Word with Update Indexed
+ *     .664
+ */
+void ppc_opc_stwux()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rA!=0
+       int ret = ppc_write_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], gCPU.gpr[rS]);
+       if (ret == PPC_MMU_OK) {
+               gCPU.gpr[rA] += gCPU.gpr[rB];
+       }
+}
+/*
+ *     stwx            Store Word Indexed
+ *     .665
+ */
+void ppc_opc_stwx()
+{
+       int rA, rS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.gpr[rS]) != PPC_MMU_FATAL;
+}
+
+/*      stvx       Store Vector Indexed
+ *      v.134
+ */
+void ppc_opc_stvx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
+
+       int ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
+
+       ppc_write_effective_qword(ea, gCPU.vr[vrS]) != PPC_MMU_FATAL;
+}
+
+/*      stvxl     Store Vector Indexed LRU
+ *      v.135
+ */
+void ppc_opc_stvxl()
+{
+       ppc_opc_stvx();
+       /* This instruction should hint to the cache that the value won't be
+        *   needed again in memory anytime soon.  We don't emulate the cache,
+        *   so this is effectively exactly the same as lvx.
+        */
+}
+
+/*      stvebx   Store Vector Element Byte Indexed
+ *      v.131
+ */
+void ppc_opc_stvebx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
+       uint32 ea;
+       ea = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
+       ppc_write_effective_byte(ea, VECT_B(gCPU.vr[vrS], ea & 0xf));
+}
+
+/*      stvehx   Store Vector Element Half Word Indexed
+ *      v.132
+ */
+void ppc_opc_stvehx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
+       uint32 ea;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~1;
+       ppc_write_effective_half(ea, VECT_H(gCPU.vr[vrS], (ea & 0xf) >> 1));
+}
+
+/*      stvewx   Store Vector Element Word Indexed
+ *      v.133
+ */
+void ppc_opc_stvewx()
+{
+#ifndef __VEC_EXC_OFF__
+       if ((gCPU.msr & MSR_VEC) == 0) {
+               ppc_exception(PPC_EXC_NO_VEC);
+               return;
+       }
+#endif
+       VECTOR_DEBUG;
+       int rA, vrS, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
+       uint32 ea;
+       ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~3;
+       ppc_write_effective_word(ea, VECT_W(gCPU.vr[vrS], (ea & 0xf) >> 2));
+}
+
+/*      dstst     Data Stream Touch for Store
+ *      v.117
+ */
+void ppc_opc_dstst()
+{
+       VECTOR_DEBUG;
+       /* Since we are not emulating the cache, this is a nop */
+}
+
+/*      dss         Data Stream Stop
+ *      v.114
+ */
+void ppc_opc_dss()
+{
+       VECTOR_DEBUG;
+       /* Since we are not emulating the cache, this is a nop */
+}
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_mmu.h b/ppc/pearpc/cpu/cpu_generic/ppc_mmu.h
new file mode 100644 (file)
index 0000000..7cf8a73
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *     PearPC
+ *     ppc_mmu.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *     Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_MMU_H__
+#define __PPC_MMU_H__
+
+#include "system/types.h"
+
+extern byte *gMemory;
+extern uint32 gMemorySize;
+
+#define PPC_MMU_READ  1
+#define PPC_MMU_WRITE 2
+#define PPC_MMU_CODE  4
+#define PPC_MMU_SV    8
+#define PPC_MMU_NO_EXC 16
+
+#define PPC_MMU_OK 0
+#define PPC_MMU_EXC 1
+#define PPC_MMU_FATAL 2
+
+int FASTCALL ppc_effective_to_physical(uint32 addr, int flags, uint32 &result);
+bool FASTCALL ppc_mmu_set_sdr1(uint32 newval, bool quiesce);
+void ppc_mmu_tlb_invalidate();
+
+int FASTCALL ppc_read_physical_dword(uint32 addr, uint64 &result);
+int FASTCALL ppc_read_physical_word(uint32 addr, uint32 &result);
+int FASTCALL ppc_read_physical_half(uint32 addr, uint16 &result);
+int FASTCALL ppc_read_physical_byte(uint32 addr, uint8 &result);
+int FASTCALL ppc_read_effective_code(uint32 addr, uint32 &result);
+int FASTCALL ppc_read_effective_dword(uint32 addr, uint64 &result);
+int FASTCALL ppc_read_effective_word(uint32 addr, uint32 &result);
+int FASTCALL ppc_read_effective_half(uint32 addr, uint16 &result);
+int FASTCALL ppc_read_effective_byte(uint32 addr, uint8 &result);
+
+int FASTCALL ppc_write_physical_dword(uint32 addr, uint64 data);
+int FASTCALL ppc_write_physical_word(uint32 addr, uint32 data);
+int FASTCALL ppc_write_physical_half(uint32 addr, uint16 data);
+int FASTCALL ppc_write_physical_byte(uint32 addr, uint8 data);
+
+int FASTCALL ppc_write_effective_dword(uint32 addr, uint64 data);
+int FASTCALL ppc_write_effective_word(uint32 addr, uint32 data);
+int FASTCALL ppc_write_effective_half(uint32 addr, uint16 data);
+int FASTCALL ppc_write_effective_byte(uint32 addr, uint8 data);
+
+int FASTCALL ppc_direct_physical_memory_handle(uint32 addr, byte *&ptr);
+int FASTCALL ppc_direct_effective_memory_handle(uint32 addr, byte *&ptr);
+int FASTCALL ppc_direct_effective_memory_handle_code(uint32 addr, byte *&ptr);
+bool FASTCALL ppc_mmu_page_create(uint32 ea, uint32 pa);
+bool FASTCALL ppc_mmu_page_free(uint32 ea);
+bool FASTCALL ppc_init_physical_memory(uint size);
+
+/*
+pte: (page table entry)
+1st word:
+0     V    Valid
+1-24  VSID Virtual Segment ID
+25    H    Hash function
+26-31 API  Abbreviated page index
+2nd word:
+0-19  RPN  Physical page number
+20-22 res
+23    R    Referenced bit
+24    C    Changed bit
+25-28 WIMG Memory/cache control bits
+29    res
+30-31 PP   Page protection bits
+*/
+
+/*
+ *     MMU Opcodes
+ */
+void ppc_opc_dcbz();
+
+void ppc_opc_lbz();
+void ppc_opc_lbzu();
+void ppc_opc_lbzux();
+void ppc_opc_lbzx();
+void ppc_opc_lfd();
+void ppc_opc_lfdu();
+void ppc_opc_lfdux();
+void ppc_opc_lfdx();
+void ppc_opc_lfs();
+void ppc_opc_lfsu();
+void ppc_opc_lfsux();
+void ppc_opc_lfsx();
+void ppc_opc_lha();
+void ppc_opc_lhau();
+void ppc_opc_lhaux();
+void ppc_opc_lhax();
+void ppc_opc_lhbrx();
+void ppc_opc_lhz();
+void ppc_opc_lhzu();
+void ppc_opc_lhzux();
+void ppc_opc_lhzx();
+void ppc_opc_lmw();
+void ppc_opc_lswi();
+void ppc_opc_lswx();
+void ppc_opc_lwarx();
+void ppc_opc_lwbrx();
+void ppc_opc_lwz();
+void ppc_opc_lwzu();
+void ppc_opc_lwzux();
+void ppc_opc_lwzx();
+void ppc_opc_lvx();             /* for altivec support */
+void ppc_opc_lvxl();
+void ppc_opc_lvebx();
+void ppc_opc_lvehx();
+void ppc_opc_lvewx();
+void ppc_opc_lvsl();
+void ppc_opc_lvsr();
+void ppc_opc_dst();
+
+void ppc_opc_stb();
+void ppc_opc_stbu();
+void ppc_opc_stbux();
+void ppc_opc_stbx();
+void ppc_opc_stfd();
+void ppc_opc_stfdu();
+void ppc_opc_stfdux();
+void ppc_opc_stfdx();
+void ppc_opc_stfiwx();
+void ppc_opc_stfs();
+void ppc_opc_stfsu();
+void ppc_opc_stfsux();
+void ppc_opc_stfsx();
+void ppc_opc_sth();
+void ppc_opc_sthbrx();
+void ppc_opc_sthu();
+void ppc_opc_sthux();
+void ppc_opc_sthx();
+void ppc_opc_stmw();
+void ppc_opc_stswi();
+void ppc_opc_stswx();
+void ppc_opc_stw();
+void ppc_opc_stwbrx();
+void ppc_opc_stwcx_();
+void ppc_opc_stwu();
+void ppc_opc_stwux();
+void ppc_opc_stwx();
+void ppc_opc_stvx();            /* for altivec support */
+void ppc_opc_stvxl();
+void ppc_opc_stvebx();
+void ppc_opc_stvehx();
+void ppc_opc_stvewx();
+void ppc_opc_dstst();
+void ppc_opc_dss();
+
+#endif
+
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_opc.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_opc.cpp
new file mode 100644 (file)
index 0000000..68ce1b3
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ *     PearPC
+ *     ppc_opc.cc
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *     Copyright (C) 2004 Dainel Foesch (dfoesch@cs.nmsu.edu)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "debug/tracers.h"
+#include "cpu/debug.h"
+//#include "io/pic/pic.h"
+#include "info.h"
+#include "ppc_cpu.h"
+#include "ppc_exc.h"
+#include "ppc_mmu.h"
+#include "ppc_opc.h"
+#include "ppc_dec.h"
+
+extern void ppc_doze(void);
+
+void ppc_set_msr(uint32 newmsr)
+{
+/*     if ((newmsr & MSR_EE) && !(gCPU.msr & MSR_EE)) {
+               if (pic_check_interrupt()) {
+                       gCPU.exception_pending = true;
+                       gCPU.ext_exception = true;
+               }
+       }*/
+       ppc_mmu_tlb_invalidate();
+#ifndef PPC_CPU_ENABLE_SINGLESTEP
+       if (newmsr & MSR_SE) {
+               SINGLESTEP("");
+               PPC_CPU_WARN("MSR[SE] (singlestep enable) set, but compiled w/o SE support.\n");
+       }
+#else 
+       gCPU.singlestep_ignore = true;
+#endif
+       if (newmsr & PPC_CPU_UNSUPPORTED_MSR_BITS) {
+               PPC_CPU_ERR("unsupported bits in MSR set: %08x @%08x\n", newmsr & PPC_CPU_UNSUPPORTED_MSR_BITS, gCPU.pc);
+       }
+       if (newmsr & MSR_POW) {
+               ppc_doze();
+               // doze();
+               newmsr &= ~MSR_POW;
+       }
+       gCPU.msr = newmsr;
+       
+}
+
+/*
+ *     bx              Branch
+ *     .435
+ */
+void ppc_opc_bx()
+{
+       uint32 li;
+       PPC_OPC_TEMPL_I(gCPU.current_opc, li);
+       if (!(gCPU.current_opc & PPC_OPC_AA)) {
+               li += gCPU.pc;
+       }
+       if (gCPU.current_opc & PPC_OPC_LK) {
+               gCPU.lr = gCPU.pc + 4;
+       }
+       gCPU.npc = li;
+}
+
+/*
+ *     bcx             Branch Conditional
+ *     .436
+ */
+void ppc_opc_bcx()
+{
+       uint32 BO, BI, BD;
+       PPC_OPC_TEMPL_B(gCPU.current_opc, BO, BI, BD);
+       if (!(BO & 4)) {
+               gCPU.ctr--;
+       }
+       bool bo2 = (BO & 2);
+       bool bo8 = (BO & 8); // branch condition true
+       bool cr = (gCPU.cr & (1<<(31-BI)));
+       if (((BO & 4) || ((gCPU.ctr!=0) ^ bo2))
+       && ((BO & 16) || (!(cr ^ bo8)))) {
+               if (!(gCPU.current_opc & PPC_OPC_AA)) {
+                       BD += gCPU.pc;
+               }
+               if (gCPU.current_opc & PPC_OPC_LK) {
+                       gCPU.lr = gCPU.pc + 4;
+               }
+               gCPU.npc = BD;
+       }
+}
+
+/*
+ *     bcctrx          Branch Conditional to Count Register
+ *     .438
+ */
+void ppc_opc_bcctrx()
+{
+       uint32 BO, BI, BD;
+       PPC_OPC_TEMPL_XL(gCPU.current_opc, BO, BI, BD);
+       PPC_OPC_ASSERT(BD==0);
+       PPC_OPC_ASSERT(!(BO & 2));     
+       bool bo8 = (BO & 8);
+       bool cr = (gCPU.cr & (1<<(31-BI)));
+       if ((BO & 16) || (!(cr ^ bo8))) {
+               if (gCPU.current_opc & PPC_OPC_LK) {
+                       gCPU.lr = gCPU.pc + 4;
+               }
+               gCPU.npc = gCPU.ctr & 0xfffffffc;
+       }
+}
+/*
+ *     bclrx           Branch Conditional to Link Register
+ *     .440
+ */
+void ppc_opc_bclrx()
+{
+       uint32 BO, BI, BD;
+       PPC_OPC_TEMPL_XL(gCPU.current_opc, BO, BI, BD);
+       PPC_OPC_ASSERT(BD==0);
+       if (!(BO & 4)) {
+               gCPU.ctr--;
+       }
+       bool bo2 = (BO & 2);
+       bool bo8 = (BO & 8);
+       bool cr = (gCPU.cr & (1<<(31-BI)));
+       if (((BO & 4) || ((gCPU.ctr!=0) ^ bo2))
+       && ((BO & 16) || (!(cr ^ bo8)))) {
+               BD = gCPU.lr & 0xfffffffc;
+               if (gCPU.current_opc & PPC_OPC_LK) {
+                       gCPU.lr = gCPU.pc + 4;
+               }
+               gCPU.npc = BD;
+       }
+}
+
+/*
+ *     dcbf            Data Cache Block Flush
+ *     .458
+ */
+void ppc_opc_dcbf()
+{
+       // NO-OP
+}
+/*
+ *     dcbi            Data Cache Block Invalidate
+ *     .460
+ */
+void ppc_opc_dcbi()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       // FIXME: check addr
+}
+/*
+ *     dcbst           Data Cache Block Store
+ *     .461
+ */
+void ppc_opc_dcbst()
+{
+       // NO-OP
+}
+/*
+ *     dcbt            Data Cache Block Touch
+ *     .462
+ */
+void ppc_opc_dcbt()
+{
+       // NO-OP
+}
+/*
+ *     dcbtst          Data Cache Block Touch for Store
+ *     .463
+ */
+void ppc_opc_dcbtst()
+{
+       // NO-OP
+}
+/*
+ *     eciwx           External Control In Word Indexed
+ *     .474
+ */
+void ppc_opc_eciwx()
+{
+       PPC_OPC_ERR("eciwx unimplemented.\n");
+}
+/*
+ *     ecowx           External Control Out Word Indexed
+ *     .476
+ */
+void ppc_opc_ecowx()
+{
+       PPC_OPC_ERR("ecowx unimplemented.\n");
+}
+/*
+ *     eieio           Enforce In-Order Execution of I/O
+ *     .478
+ */
+void ppc_opc_eieio()
+{
+       // NO-OP
+}
+
+/*
+ *     icbi            Instruction Cache Block Invalidate
+ *     .519
+ */
+void ppc_opc_icbi()
+{
+       // NO-OP
+}
+
+/*
+ *     isync           Instruction Synchronize
+ *     .520
+ */
+void ppc_opc_isync()
+{
+       // NO-OP
+}
+
+static uint32 ppc_cmp_and_mask[8] = {
+       0xfffffff0,
+       0xffffff0f,
+       0xfffff0ff,
+       0xffff0fff,
+       0xfff0ffff,
+       0xff0fffff,
+       0xf0ffffff,
+       0x0fffffff,
+};
+/*
+ *     mcrf            Move Condition Register Field
+ *     .561
+ */
+void ppc_opc_mcrf()
+{
+       uint32 crD, crS, bla;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crD, crS, bla);
+       // FIXME: bla == 0
+       crD>>=2;
+       crS>>=2;
+       crD = 7-crD;
+       crS = 7-crS;
+       uint32 c = (gCPU.cr>>(crS*4)) & 0xf;
+       gCPU.cr &= ppc_cmp_and_mask[crD];
+       gCPU.cr |= c<<(crD*4);
+}
+/*
+ *     mcrfs           Move to Condition Register from FPSCR
+ *     .562
+ */
+void ppc_opc_mcrfs()
+{
+       PPC_OPC_ERR("mcrfs unimplemented.\n");
+}
+/*
+ *     mcrxr           Move to Condition Register from XER
+ *     .563
+ */
+void ppc_opc_mcrxr()
+{
+       PPC_OPC_ERR("mcrxr unimplemented.\n");
+}
+/*
+ *     mfcr            Move from Condition Register
+ *     .564
+ */
+void ppc_opc_mfcr()
+{
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT(rA==0 && rB==0);
+       gCPU.gpr[rD] = gCPU.cr;
+}
+/*
+ *     mffs            Move from FPSCR
+ *     .565
+ */
+void ppc_opc_mffsx()
+{
+       int frD, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
+       PPC_OPC_ASSERT(rA==0 && rB==0);
+       gCPU.fpr[frD] = gCPU.fpscr;
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_OPC_ERR("mffs. unimplemented.\n");
+       }
+}
+/*
+ *     mfmsr           Move from Machine State Register
+ *     .566
+ */
+void ppc_opc_mfmsr()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       PPC_OPC_ASSERT((rA == 0) && (rB == 0));
+       gCPU.gpr[rD] = gCPU.msr;
+}
+/*
+ *     mfspr           Move from Special-Purpose Register
+ *     .567
+ */
+void ppc_opc_mfspr()
+{
+       int rD, spr1, spr2;
+       PPC_OPC_TEMPL_XO(gCPU.current_opc, rD, spr1, spr2);
+       switch (spr2) {
+       case 0:
+               switch (spr1) {
+               case 1: gCPU.gpr[rD] = gCPU.xer; return;
+               case 8: gCPU.gpr[rD] = gCPU.lr; return;
+               case 9: gCPU.gpr[rD] = gCPU.ctr; return;
+               }
+       case 8: // altivec made this spr unpriviledged
+               if (spr1 == 0) {
+                       gCPU.gpr[rD] = gCPU.vrsave; 
+                       return;
+               }
+       }
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       switch (spr2) {
+       case 0:
+               switch (spr1) {
+               case 18: gCPU.gpr[rD] = gCPU.dsisr; return;
+               case 19: gCPU.gpr[rD] = gCPU.dar; return;
+               case 22: {
+                       gCPU.dec = gCPU.pdec / TB_TO_PTB_FACTOR;
+                       gCPU.gpr[rD] = gCPU.dec;
+                       return;
+               }
+               case 25: gCPU.gpr[rD] = gCPU.sdr1; return;
+               case 26: gCPU.gpr[rD] = gCPU.srr[0]; return;
+               case 27: gCPU.gpr[rD] = gCPU.srr[1]; return;
+               }
+               break;
+       case 8:
+               switch (spr1) {
+               case 12: {
+                       gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR;
+                       gCPU.gpr[rD] = gCPU.tb;
+                       return;
+               }
+               case 13: {
+                       gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR;
+                       gCPU.gpr[rD] = gCPU.tb >> 32;
+                       return;
+               }
+               case 16: gCPU.gpr[rD] = gCPU.sprg[0]; return;
+               case 17: gCPU.gpr[rD] = gCPU.sprg[1]; return;
+               case 18: gCPU.gpr[rD] = gCPU.sprg[2]; return;
+               case 19: gCPU.gpr[rD] = gCPU.sprg[3]; return;
+               case 26: gCPU.gpr[rD] = gCPU.ear; return;
+               case 31: gCPU.gpr[rD] = gCPU.pvr; return;
+               }
+               break;
+       case 16:
+               switch (spr1) {
+               case 16: gCPU.gpr[rD] = gCPU.ibatu[0]; return;
+               case 17: gCPU.gpr[rD] = gCPU.ibatl[0]; return;
+               case 18: gCPU.gpr[rD] = gCPU.ibatu[1]; return;
+               case 19: gCPU.gpr[rD] = gCPU.ibatl[1]; return;
+               case 20: gCPU.gpr[rD] = gCPU.ibatu[2]; return;
+               case 21: gCPU.gpr[rD] = gCPU.ibatl[2]; return;
+               case 22: gCPU.gpr[rD] = gCPU.ibatu[3]; return;
+               case 23: gCPU.gpr[rD] = gCPU.ibatl[3]; return;
+               case 24: gCPU.gpr[rD] = gCPU.dbatu[0]; return;
+               case 25: gCPU.gpr[rD] = gCPU.dbatl[0]; return;
+               case 26: gCPU.gpr[rD] = gCPU.dbatu[1]; return;
+               case 27: gCPU.gpr[rD] = gCPU.dbatl[1]; return;
+               case 28: gCPU.gpr[rD] = gCPU.dbatu[2]; return;
+               case 29: gCPU.gpr[rD] = gCPU.dbatl[2]; return;
+               case 30: gCPU.gpr[rD] = gCPU.dbatu[3]; return;
+               case 31: gCPU.gpr[rD] = gCPU.dbatl[3]; return;
+               }
+               break;
+       case 29:
+               switch (spr1) {
+               case 16:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 17:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 18:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 24:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 25:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 26:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 28:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 29:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 30:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               }
+       case 31:
+               switch (spr1) {
+               case 16:
+//                     PPC_OPC_WARN("read from spr %d:%d (HID0) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = gCPU.hid[0];
+                       return;
+               case 17:
+                       //PPC_OPC_WARN("read from spr %d:%d (HID1) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = gCPU.hid[1];
+                       return;
+               case 18:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 21:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 22:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 23:
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 25:
+                       PPC_OPC_WARN("read from spr %d:%d (L2CR) not supported! (from %08x)\n", spr1, spr2, gCPU.pc);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 27:
+                       PPC_OPC_WARN("read from spr %d:%d (ICTC) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 28:
+//                     PPC_OPC_WARN("read from spr %d:%d (THRM1) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 29:
+//                     PPC_OPC_WARN("read from spr %d:%d (THRM2) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 30:
+//                     PPC_OPC_WARN("read from spr %d:%d (THRM3) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               case 31:
+//                     PPC_OPC_WARN("read from spr %d:%d (???) not supported!\n", spr1, spr2);
+                       gCPU.gpr[rD] = 0;
+                       return;
+               }
+       }
+       ht_printf("unknown mfspr: %i:%i\n", spr1, spr2);
+       SINGLESTEP("invalid mfspr\n");
+}
+/*
+ *     mfsr            Move from Segment Register
+ *     .570
+ */
+void ppc_opc_mfsr()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rD, SR, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, SR, rB);
+       // FIXME: check insn
+       gCPU.gpr[rD] = gCPU.sr[SR & 0xf];
+}
+/*
+ *     mfsrin          Move from Segment Register Indirect
+ *     .572
+ */
+void ppc_opc_mfsrin()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rD, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
+       // FIXME: check insn
+       gCPU.gpr[rD] = gCPU.sr[gCPU.gpr[rB] >> 28];
+}
+/*
+ *     mftb            Move from Time Base
+ *     .574
+ */
+void ppc_opc_mftb()
+{
+       int rD, spr1, spr2;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rD, spr1, spr2);
+       switch (spr2) {
+       case 8:
+               switch (spr1) {
+               case 12: {
+                       gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR;
+                       gCPU.gpr[rD] = gCPU.tb;
+                       return;
+               }
+               case 13: {
+                       gCPU.tb = gCPU.ptb / TB_TO_PTB_FACTOR;
+                       gCPU.gpr[rD] = gCPU.tb >> 32;
+                       return;
+               }
+               }
+               break;
+       }
+       SINGLESTEP("unknown mftb\n");
+}
+/*
+ *     mtcrf           Move to Condition Register Fields
+ *     .576
+ */
+void ppc_opc_mtcrf()
+{
+       
+       int rS;
+       uint32 crm;
+       uint32 CRM;
+       PPC_OPC_TEMPL_XFX(gCPU.current_opc, rS, crm);
+       CRM = ((crm&0x80)?0xf0000000:0)|((crm&0x40)?0x0f000000:0)|((crm&0x20)?0x00f00000:0)|((crm&0x10)?0x000f0000:0)|
+             ((crm&0x08)?0x0000f000:0)|((crm&0x04)?0x00000f00:0)|((crm&0x02)?0x000000f0:0)|((crm&0x01)?0x0000000f:0);
+       gCPU.cr = (gCPU.gpr[rS] & CRM) | (gCPU.cr & ~CRM);
+}
+/*
+ *     mtfsb0x         Move to FPSCR Bit 0
+ *     .577
+ */
+void ppc_opc_mtfsb0x()
+{
+       int crbD, n1, n2;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crbD, n1, n2);
+       if (crbD != 1 && crbD != 2) {
+               gCPU.fpscr &= ~(1<<(31-crbD));
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_OPC_ERR("mtfsb0. unimplemented.\n");
+       }
+}
+/*
+ *     mtfsb1x         Move to FPSCR Bit 1
+ *     .578
+ */
+void ppc_opc_mtfsb1x()
+{
+       int crbD, n1, n2;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crbD, n1, n2);
+       if (crbD != 1 && crbD != 2) {
+               gCPU.fpscr |= 1<<(31-crbD);
+       }
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_OPC_ERR("mtfsb1. unimplemented.\n");
+       }
+}
+/*
+ *     mtfsfx          Move to FPSCR Fields
+ *     .579
+ */
+void ppc_opc_mtfsfx()
+{
+       int frB;
+       uint32 fm, FM;
+       PPC_OPC_TEMPL_XFL(gCPU.current_opc, frB, fm);
+       FM = ((fm&0x80)?0xf0000000:0)|((fm&0x40)?0x0f000000:0)|((fm&0x20)?0x00f00000:0)|((fm&0x10)?0x000f0000:0)|
+            ((fm&0x08)?0x0000f000:0)|((fm&0x04)?0x00000f00:0)|((fm&0x02)?0x000000f0:0)|((fm&0x01)?0x0000000f:0);
+       gCPU.fpscr = (gCPU.fpr[frB] & FM) | (gCPU.fpscr & ~FM);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_OPC_ERR("mtfsf. unimplemented.\n");
+       }
+}
+/*
+ *     mtfsfix         Move to FPSCR Field Immediate
+ *     .580
+ */
+void ppc_opc_mtfsfix()
+{
+       int crfD, n1;
+       uint32 imm;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, crfD, n1, imm);
+       crfD >>= 2;
+       imm >>= 1;
+       crfD = 7-crfD;
+       gCPU.fpscr &= ppc_cmp_and_mask[crfD];
+       gCPU.fpscr |= imm<<(crfD*4);
+       if (gCPU.current_opc & PPC_OPC_Rc) {
+               // update cr1 flags
+               PPC_OPC_ERR("mtfsfi. unimplemented.\n");
+       }
+}
+/*
+ *     mtmsr           Move to Machine State Register
+ *     .581
+ */
+void ppc_opc_mtmsr()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       PPC_OPC_ASSERT((rA == 0) && (rB == 0));
+       ppc_set_msr(gCPU.gpr[rS]);
+}
+/*
+ *     mtspr           Move to Special-Purpose Register
+ *     .584
+ */
+void ppc_opc_mtspr()
+{
+       int rS, spr1, spr2;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, spr1, spr2);
+       switch (spr2) {
+       case 0:
+               switch (spr1) {
+               case 1: gCPU.xer = gCPU.gpr[rS]; return;
+               case 8: gCPU.lr = gCPU.gpr[rS]; return;
+               case 9: gCPU.ctr = gCPU.gpr[rS]; return;
+               }
+       case 8: //altivec makes this register unpriviledged
+               if (spr1 == 0) {
+                       gCPU.vrsave = gCPU.gpr[rS]; 
+                       return;
+               }
+       }
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       switch (spr2) {
+       case 0:
+               switch (spr1) {
+/*             case 18: gCPU.gpr[rD] = gCPU.dsisr; return;
+               case 19: gCPU.gpr[rD] = gCPU.dar; return;*/
+               case 22: {
+                       gCPU.dec = gCPU.gpr[rS];
+                       gCPU.pdec = gCPU.dec;
+                       gCPU.pdec *= TB_TO_PTB_FACTOR;
+                       return;
+               }
+               case 25: 
+                       if (!ppc_mmu_set_sdr1(gCPU.gpr[rS], true)) {
+                               PPC_OPC_ERR("cannot set sdr1\n");
+                       }
+                       return;
+               case 26: gCPU.srr[0] = gCPU.gpr[rS]; return;
+               case 27: gCPU.srr[1] = gCPU.gpr[rS]; return;
+               }
+               break;
+       case 8:
+               switch (spr1) {
+               case 16: gCPU.sprg[0] = gCPU.gpr[rS]; return;
+               case 17: gCPU.sprg[1] = gCPU.gpr[rS]; return;
+               case 18: gCPU.sprg[2] = gCPU.gpr[rS]; return;
+               case 19: gCPU.sprg[3] = gCPU.gpr[rS]; return;
+               case 26: gCPU.ear = gCPU.gpr[rS]; return;
+               case 28: gCPU.tb = (gCPU.tb & 0xffffffff00000000) | gCPU.gpr[rS]; return;
+               case 29: gCPU.tb = (gCPU.tb & 0x00000000ffffffff) | ((uint64)gCPU.gpr[rS] << 32); return;
+               }
+               break;
+       case 16:
+               switch (spr1) {
+               case 16:
+                       gCPU.ibatu[0] = gCPU.gpr[rS];
+                       gCPU.ibat_bl17[0] = ~(BATU_BL(gCPU.ibatu[0])<<17);
+                       return;
+               case 17:
+                       gCPU.ibatl[0] = gCPU.gpr[rS];
+                       return;
+               case 18:
+                       gCPU.ibatu[1] = gCPU.gpr[rS];
+                       gCPU.ibat_bl17[1] = ~(BATU_BL(gCPU.ibatu[1])<<17);
+                       return;
+               case 19:
+                       gCPU.ibatl[1] = gCPU.gpr[rS];
+                       return;
+               case 20:
+                       gCPU.ibatu[2] = gCPU.gpr[rS];
+                       gCPU.ibat_bl17[2] = ~(BATU_BL(gCPU.ibatu[2])<<17);
+                       return;
+               case 21:
+                       gCPU.ibatl[2] = gCPU.gpr[rS];
+                       return;
+               case 22:
+                       gCPU.ibatu[3] = gCPU.gpr[rS];
+                       gCPU.ibat_bl17[3] = ~(BATU_BL(gCPU.ibatu[3])<<17);
+                       return;
+               case 23:
+                       gCPU.ibatl[3] = gCPU.gpr[rS];
+                       return;
+               case 24:
+                       gCPU.dbatu[0] = gCPU.gpr[rS];
+                       gCPU.dbat_bl17[0] = ~(BATU_BL(gCPU.dbatu[0])<<17);
+                       return;
+               case 25:
+                       gCPU.dbatl[0] = gCPU.gpr[rS];
+                       return;
+               case 26:
+                       gCPU.dbatu[1] = gCPU.gpr[rS];
+                       gCPU.dbat_bl17[1] = ~(BATU_BL(gCPU.dbatu[1])<<17);
+                       return;
+               case 27:
+                       gCPU.dbatl[1] = gCPU.gpr[rS];
+                       return;
+               case 28:
+                       gCPU.dbatu[2] = gCPU.gpr[rS];
+                       gCPU.dbat_bl17[2] = ~(BATU_BL(gCPU.dbatu[2])<<17);
+                       return;
+               case 29:
+                       gCPU.dbatl[2] = gCPU.gpr[rS];
+                       return;
+               case 30:
+                       gCPU.dbatu[3] = gCPU.gpr[rS];
+                       gCPU.dbat_bl17[3] = ~(BATU_BL(gCPU.dbatu[3])<<17);
+                       return;
+               case 31:
+                       gCPU.dbatl[3] = gCPU.gpr[rS];
+                       return;
+               }
+               break;
+       case 29:
+               switch(spr1) {
+               case 17: return;
+               case 24: return;
+               case 25: return;
+               case 26: return;
+               }
+       case 31:
+               switch (spr1) {
+               case 16:
+//                     PPC_OPC_WARN("write(%08x) to spr %d:%d (HID0) not supported! @%08x\n", gCPU.gpr[rS], spr1, spr2, gCPU.pc);
+                       gCPU.hid[0] = gCPU.gpr[rS];
+                       return;
+               case 17: return;
+               case 18:
+                       PPC_OPC_ERR("write(%08x) to spr %d:%d (IABR) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 21:
+                       PPC_OPC_ERR("write(%08x) to spr %d:%d (DABR) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 24:
+                       PPC_OPC_WARN("write(%08x) to spr %d:%d (?) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 27:
+                       PPC_OPC_WARN("write(%08x) to spr %d:%d (ICTC) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 28:
+//                     PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM1) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 29:
+//                     PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM2) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 30:
+//                     PPC_OPC_WARN("write(%08x) to spr %d:%d (THRM3) not supported!\n", gCPU.gpr[rS], spr1, spr2);
+                       return;
+               case 31: return;
+               }
+       }
+       ht_printf("unknown mtspr: %i:%i\n", spr1, spr2);
+       SINGLESTEP("unknown mtspr\n");
+}
+/*
+ *     mtsr            Move to Segment Register
+ *     .587
+ */
+void ppc_opc_mtsr()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, SR, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, SR, rB);
+       // FIXME: check insn
+       gCPU.sr[SR & 0xf] = gCPU.gpr[rS];
+}
+/*
+ *     mtsrin          Move to Segment Register Indirect
+ *     .591
+ */
+void ppc_opc_mtsrin()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check insn
+       gCPU.sr[gCPU.gpr[rB] >> 28] = gCPU.gpr[rS];
+}
+
+/*
+ *     rfi             Return from Interrupt
+ *     .607
+ */
+void ppc_opc_rfi()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       ppc_set_msr(gCPU.srr[1] & MSR_RFI_SAVE_MASK);
+       gCPU.npc = gCPU.srr[0] & 0xfffffffc;
+}
+
+/*
+ *     sc              System Call
+ *     .621
+ */
+#if 0
+#include "io/graphic/gcard.h"
+#endif
+void ppc_opc_sc()
+{
+#if 0
+       if (gCPU.gpr[3] == 0x113724fa && gCPU.gpr[4] == 0x77810f9b) {
+               gcard_osi(0);
+               return;
+       }
+#endif
+       ppc_exception(PPC_EXC_SC);
+}
+
+extern void uae_ppc_sync(void);
+/*
+ *     sync            Synchronize
+ *     .672
+ */
+void ppc_opc_sync()
+{
+       // NO-OP
+       uae_ppc_sync();
+}
+
+/*
+ *     tlbie           Translation Lookaside Buffer Invalidate Entry
+ *     .676
+ */
+void ppc_opc_tlbia()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rS.. for 0
+       ppc_mmu_tlb_invalidate();
+}
+
+/*
+ *     tlbie           Translation Lookaside Buffer Invalidate All
+ *     .676
+ */
+void ppc_opc_tlbie()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rS.. for 0     
+       ppc_mmu_tlb_invalidate();
+}
+
+/*
+ *     tlbsync         Translation Lookaside Buffer Syncronize
+ *     .677
+ */
+void ppc_opc_tlbsync()
+{
+       if (gCPU.msr & MSR_PR) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_PRIV);
+               return;
+       }
+       int rS, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
+       // FIXME: check rS.. for 0     
+       ppc_mmu_tlb_invalidate();
+}
+
+/*
+ *     tw              Trap Word
+ *     .678
+ */
+void ppc_opc_tw()
+{
+       int TO, rA, rB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, TO, rA, rB);
+       uint32 a = gCPU.gpr[rA];
+       uint32 b = gCPU.gpr[rB];
+       if (((TO & 16) && ((sint32)a < (sint32)b)) 
+       || ((TO & 8) && ((sint32)a > (sint32)b)) 
+       || ((TO & 4) && (a == b)) 
+       || ((TO & 2) && (a < b)) 
+       || ((TO & 1) && (a > b))) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_TRAP);
+       }
+}
+
+/*
+ *     twi             Trap Word Immediate
+ *     .679
+ */
+void ppc_opc_twi()
+{
+       int TO, rA;
+       uint32 imm;
+       PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, TO, rA, imm);
+       uint32 a = gCPU.gpr[rA];
+       if (((TO & 16) && ((sint32)a < (sint32)imm)) 
+       || ((TO & 8) && ((sint32)a > (sint32)imm)) 
+       || ((TO & 4) && (a == imm)) 
+       || ((TO & 2) && (a < imm)) 
+       || ((TO & 1) && (a > imm))) {
+               ppc_exception(PPC_EXC_PROGRAM, PPC_EXC_PROGRAM_TRAP);
+       }
+}
+
+/*     dcba            Data Cache Block Allocate
+ *     .???
+ */
+void ppc_opc_dcba()
+{
+       /* NO-OP */
+}
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_opc.h b/ppc/pearpc/cpu/cpu_generic/ppc_opc.h
new file mode 100644 (file)
index 0000000..5c26192
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *     PearPC
+ *     ppc_opc.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_OPC_H__
+#define __PPC_OPC_H__
+
+#include "system/types.h"
+
+static inline void ppc_update_cr0(uint32 r)
+{
+       gCPU.cr &= 0x0fffffff;
+       if (!r) {
+               gCPU.cr |= CR_CR0_EQ;
+       } else if (r & 0x80000000) {
+               gCPU.cr |= CR_CR0_LT;
+       } else {
+               gCPU.cr |= CR_CR0_GT;
+       }
+       if (gCPU.xer & XER_SO) gCPU.cr |= CR_CR0_SO;
+}
+
+void ppc_opc_bx();
+void ppc_opc_bcx();
+void ppc_opc_bcctrx();
+void ppc_opc_bclrx();
+
+void ppc_opc_dcba();
+void ppc_opc_dcbf();
+void ppc_opc_dcbi();
+void ppc_opc_dcbst();
+void ppc_opc_dcbt();
+void ppc_opc_dcbtst();
+
+void ppc_opc_eciwx();
+void ppc_opc_ecowx();
+void ppc_opc_eieio();
+
+void ppc_opc_icbi();
+void ppc_opc_isync();
+
+void ppc_opc_mcrf();
+void ppc_opc_mcrfs();
+void ppc_opc_mcrxr();
+void ppc_opc_mfcr();
+void ppc_opc_mffsx();
+void ppc_opc_mfmsr();
+void ppc_opc_mfspr();
+void ppc_opc_mfsr();
+void ppc_opc_mfsrin();
+void ppc_opc_mftb();
+void ppc_opc_mtcrf();
+void ppc_opc_mtfsb0x();
+void ppc_opc_mtfsb1x();
+void ppc_opc_mtfsfx();
+void ppc_opc_mtfsfix();
+void ppc_opc_mtmsr();
+void ppc_opc_mtspr();
+void ppc_opc_mtsr();
+void ppc_opc_mtsrin();
+
+void ppc_opc_rfi();
+void ppc_opc_sc();
+void ppc_opc_sync();
+void ppc_opc_tlbia();
+void ppc_opc_tlbie();
+void ppc_opc_tlbsync();
+void ppc_opc_tw();
+void ppc_opc_twi();
+
+
+#endif
+
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_tools.h b/ppc/pearpc/cpu/cpu_generic/ppc_tools.h
new file mode 100644 (file)
index 0000000..c9212d5
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *     PearPC
+ *     ppc_tools.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __PPC_TOOLS_H__
+#define __PPC_TOOLS_H__
+
+#include "system/types.h"
+
+static inline FUNCTION_CONST bool ppc_carry_3(uint32 a, uint32 b, uint32 c)
+{
+       if ((a+b) < a) {
+               return true;
+       }
+       if ((a+b+c) < c) {
+               return true;
+       }
+       return false;
+}
+
+static inline FUNCTION_CONST uint32 ppc_word_rotl(uint32 data, int n)
+{
+       n &= 0x1f;
+       return (data << n) | (data >> (32-n));
+}
+
+#endif
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_vec.cpp b/ppc/pearpc/cpu/cpu_generic/ppc_vec.cpp
new file mode 100644 (file)
index 0000000..ede83b2
--- /dev/null
@@ -0,0 +1,3206 @@
+/*
+ *     PearPC
+ *     ppc_vec.cc
+ *
+ *     Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nsmu.edu)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*     Pages marked: v.???
+ *     From: IBM PowerPC MicroProcessor Family: Altivec(tm) Technology...
+ *             Programming Environments Manual
+ */
+
+#include <math.h>
+
+/*
+ *     FIXME: put somewhere appropriate
+ */
+#ifndef HAS_LOG2
+#define log2(x) log(x)/log((float)2)
+#endif /* HAS_LOG2 */ 
+
+#ifndef HAS_EXP2
+#define exp2(x)        pow(2, x)
+#endif /* HAS_EXP2 */
+
+#include "debug/tracers.h"
+#include "ppc_cpu.h"
+#include "ppc_dec.h"
+#include "ppc_fpu.h"
+#include "ppc_vec.h"
+
+#define        SIGN32 0x80000000
+
+/*     PACK_PIXEL      Packs a uint32 pixel to uint16 pixel
+ *     v.219
+ */
+static inline uint16 PACK_PIXEL(uint32 clr)
+{
+       return  (((clr & 0x000000f8) >> 3) | \
+                ((clr & 0x0000f800) >> 6) | \
+                ((clr & 0x01f80000) >> 9));
+}
+
+/*     UNPACK_PIXEL    Unpacks a uint16 pixel to uint32 pixel
+ *     v.276 & v.279
+ */
+static inline uint32 UNPACK_PIXEL(uint16 clr)
+{
+       return  (((uint32)(clr & 0x001f)) | \
+                ((uint32)(clr & 0x03E0) << 3) | \
+                ((uint32)(clr & 0x7c00) << 6) | \
+                (((clr) & 0x8000) ? 0xff000000 : 0));
+}
+
+static inline uint8 SATURATE_UB(uint16 val)
+{
+       if (val & 0xff00) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0xff;
+       }
+       return val;
+}
+static inline uint8 SATURATE_0B(uint16 val)
+{
+       if (val & 0xff00) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0;
+       }
+       return val;
+}
+
+static inline uint16 SATURATE_UH(uint32 val)
+{
+       if (val & 0xffff0000) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0xffff;
+       }
+       return val;
+}
+
+static inline uint16 SATURATE_0H(uint32 val)
+{
+       if (val & 0xffff0000) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0;
+       }
+       return val;
+}
+
+static inline sint8 SATURATE_SB(sint16 val)
+{
+       if (val > 127) {                        // 0x7F
+               gCPU.vscr |= VSCR_SAT;
+               return 127;
+       } else if (val < -128) {                // 0x80
+               gCPU.vscr |= VSCR_SAT;
+               return -128;
+       }
+       return val;
+}
+
+static inline uint8 SATURATE_USB(sint16 val)
+{
+       if (val > 0xff) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0xff;
+       } else if (val < 0) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0;
+       }
+       return (uint8)val;
+}
+
+static inline sint16 SATURATE_SH(sint32 val)
+{
+       if (val > 32767) {                      // 0x7fff
+               gCPU.vscr |= VSCR_SAT;
+               return 32767;
+       } else if (val < -32768) {              // 0x8000
+               gCPU.vscr |= VSCR_SAT;
+               return -32768;
+       }
+       return val;
+}
+
+static inline uint16 SATURATE_USH(sint32 val)
+{
+       if (val > 0xffff) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0xffff;
+       } else if (val < 0) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0;
+       }
+       return (uint16)val;
+}
+
+static inline sint32 SATURATE_UW(sint64 val)
+{
+       if (val > 0xffffffffLL) {
+               gCPU.vscr |= VSCR_SAT;
+               return 0xffffffffLL;
+       }
+       return val;
+}
+
+static inline sint32 SATURATE_SW(sint64 val)
+{
+       if (val > 2147483647LL) {                       // 0x7fffffff
+               gCPU.vscr |= VSCR_SAT;
+               return 2147483647LL;
+       } else if (val < -2147483648LL) {               // 0x80000000
+               gCPU.vscr |= VSCR_SAT;
+               return -2147483648LL;
+       }
+       return val;
+}
+
+/*     vperm           Vector Permutation
+ *     v.218
+ */
+void ppc_opc_vperm()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB, vrC;
+       int sel;
+       Vector_t r;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+       for (int i=0; i<16; i++) {
+               sel = gCPU.vr[vrC].b[i];
+               if (sel & 0x10)
+                       r.b[i] = VECT_B(gCPU.vr[vrB], sel & 0xf);
+               else
+                       r.b[i] = VECT_B(gCPU.vr[vrA], sel & 0xf);
+       }
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vsel            Vector Select
+ *     v.238
+ */
+void ppc_opc_vsel()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       uint64 mask, val;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       mask = gCPU.vr[vrC].d[0];
+       val = gCPU.vr[vrB].d[0] & mask;
+       val |= gCPU.vr[vrA].d[0] & ~mask;
+       gCPU.vr[vrD].d[0] = val;
+
+       mask = gCPU.vr[vrC].d[1];
+       val = gCPU.vr[vrB].d[1] & mask;
+       val |= gCPU.vr[vrA].d[1] & ~mask;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vsrb            Vector Shift Right Byte
+ *     v.256
+ */
+void ppc_opc_vsrb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<16; i++) {
+               gCPU.vr[vrD].b[i] = gCPU.vr[vrA].b[i] >> (gCPU.vr[vrB].b[i] & 0x7);
+       }
+}
+
+/*     vsrh            Vector Shift Right Half Word
+ *     v.257
+ */
+void ppc_opc_vsrh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<8; i++) {
+               gCPU.vr[vrD].h[i] = gCPU.vr[vrA].h[i] >> (gCPU.vr[vrB].h[i] & 0xf);
+       }
+}
+
+/*     vsrw            Vector Shift Right Word
+ *     v.259
+ */
+void ppc_opc_vsrw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<4; i++) {
+               gCPU.vr[vrD].w[i] = gCPU.vr[vrA].w[i] >> (gCPU.vr[vrB].w[i] & 0x1f);
+       }
+}
+
+/*     vsrab           Vector Shift Right Arithmetic Byte
+ *     v.253
+ */
+void ppc_opc_vsrab()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<16; i++) {
+               gCPU.vr[vrD].sb[i] = gCPU.vr[vrA].sb[i] >> (gCPU.vr[vrB].b[i] & 0x7);
+       }
+}
+
+/*     vsrah           Vector Shift Right Arithmetic Half Word
+ *     v.254
+ */
+void ppc_opc_vsrah()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<8; i++) {
+               gCPU.vr[vrD].sh[i] = gCPU.vr[vrA].sh[i] >> (gCPU.vr[vrB].h[i] & 0xf);
+       }
+}
+
+/*     vsraw           Vector Shift Right Arithmetic Word
+ *     v.255
+ */
+void ppc_opc_vsraw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<4; i++) {
+               gCPU.vr[vrD].sw[i] = gCPU.vr[vrA].sw[i] >> (gCPU.vr[vrB].w[i] & 0x1f);
+       }
+}
+
+/*     vslb            Vector Shift Left Byte
+ *     v.240
+ */
+void ppc_opc_vslb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<16; i++) {
+               gCPU.vr[vrD].b[i] = gCPU.vr[vrA].b[i] << (gCPU.vr[vrB].b[i] & 0x7);
+       }
+}
+
+/*     vslh            Vector Shift Left Half Word
+ *     v.242
+ */
+void ppc_opc_vslh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<8; i++) {
+               gCPU.vr[vrD].h[i] = gCPU.vr[vrA].h[i] << (gCPU.vr[vrB].h[i] & 0xf);
+       }
+}
+
+/*     vslw            Vector Shift Left Word
+ *     v.244
+ */
+void ppc_opc_vslw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       for (int i=0; i<4; i++) {
+               gCPU.vr[vrD].w[i] = gCPU.vr[vrA].w[i] << (gCPU.vr[vrB].w[i] & 0x1f);
+       }
+}
+
+/*     vsr             Vector Shift Right
+ *     v.251
+ */
+void ppc_opc_vsr()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       int shift;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       /* Specs say that the low-order 3 bits of all byte elements in vB
+        *   must be the same, or the result is undefined.  So we can just
+        *   use the same low-order 3 bits for all of our shifts.
+        */
+       shift = gCPU.vr[vrB].w[0] & 0x7;
+
+       r.d[0] = gCPU.vr[vrA].d[0] >> shift;
+       r.d[1] = gCPU.vr[vrA].d[1] >> shift;
+
+       VECT_D(r, 1) |= VECT_D(gCPU.vr[vrA], 0) << (64 - shift);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vsro            Vector Shift Right Octet
+ *     v.258
+ */
+void ppc_opc_vsro()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       int shift, i;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       shift = (gCPU.vr[vrB].w[0] >> 3) & 0xf;
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+       for (i=0; i<(16-shift); i++) {
+               r.b[i] = gCPU.vr[vrA].b[i+shift];
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = 0;
+       }
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+       for (i=0; i<shift; i++) {
+               r.b[i] = 0;
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = gCPU.vr[vrA].b[i-shift];
+       }
+#else
+#error Endianess not supported!
+#endif
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vsl             Vector Shift Left
+ *     v.239
+ */
+void ppc_opc_vsl()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       int shift;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       /* Specs say that the low-order 3 bits of all byte elements in vB
+        *   must be the same, or the result is undefined.  So we can just
+        *   use the same low-order 3 bits for all of our shifts.
+        */
+       shift = gCPU.vr[vrB].w[0] & 0x7;
+
+       r.d[0] = gCPU.vr[vrA].d[0] << shift;
+       r.d[1] = gCPU.vr[vrA].d[1] << shift;
+
+       VECT_D(r, 0) |= VECT_D(gCPU.vr[vrA], 1) >> (64 - shift);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vslo            Vector Shift Left Octet
+ *     v.243
+ */
+void ppc_opc_vslo()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       int shift, i;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       shift = (gCPU.vr[vrB].w[0] >> 3) & 0xf;
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+       for (i=0; i<shift; i++) {
+               r.b[i] = 0;
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = gCPU.vr[vrA].b[i-shift];
+       }
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+       for (i=0; i<(16-shift); i++) {
+               r.b[i] = gCPU.vr[vrA].b[i+shift];
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = 0;
+       }
+#else
+#error Endianess not supported!
+#endif
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vsldoi          Vector Shift Left Double by Octet Immediate
+ *     v.241
+ */
+void ppc_opc_vsldoi()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB, shift, ashift;
+       int i;
+       Vector_t r;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, shift);
+
+       shift &= 0xf;
+       ashift = 16 - shift;
+
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+       for (i=0; i<shift; i++) {
+               r.b[i] = gCPU.vr[vrB].b[i+ashift];
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = gCPU.vr[vrA].b[i-shift];
+       }
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+       for (i=0; i<ashift; i++) {
+               r.b[i] = gCPU.vr[vrA].b[i+shift];
+       }
+
+       for (; i<16; i++) {
+               r.b[i] = gCPU.vr[vrB].b[i-ashift];
+       }
+#else
+#error Endianess not supported!
+#endif
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vrlb            Vector Rotate Left Byte
+ *     v.234
+ */
+void ppc_opc_vrlb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, shift;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               shift = (gCPU.vr[vrB].b[i] & 0x7);
+
+               r.b[i] = gCPU.vr[vrA].b[i] << shift;
+               r.b[i] |= gCPU.vr[vrA].b[i] >> (8 - shift);
+       }
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vrlh            Vector Rotate Left Half Word
+ *     v.235
+ */
+void ppc_opc_vrlh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, shift;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               shift = (gCPU.vr[vrB].h[i] & 0xf);
+
+               r.h[i] = gCPU.vr[vrA].h[i] << shift;
+               r.h[i] |= gCPU.vr[vrA].h[i] >> (16 - shift);
+       }
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vrlw            Vector Rotate Left Word
+ *     v.236
+ */
+void ppc_opc_vrlw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, shift;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               shift = (gCPU.vr[vrB].w[i] & 0x1F);
+
+               r.w[i] = gCPU.vr[vrA].w[i] << shift;
+               r.w[i] |= gCPU.vr[vrA].w[i] >> (32 - shift);
+       }
+
+       gCPU.vr[vrD] = r;
+}
+
+/* With the merges, I just don't see any point in risking that a compiler
+ *   might generate actual alu code to calculate anything when it's
+ *   compile-time known.  Plus, it's easier to validate it like this.
+ */
+
+/*     vmrghb          Vector Merge High Byte
+ *     v.195
+ */
+void ppc_opc_vmrghb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = VECT_B(gCPU.vr[vrA], 0);
+       VECT_B(r, 1) = VECT_B(gCPU.vr[vrB], 0);
+       VECT_B(r, 2) = VECT_B(gCPU.vr[vrA], 1);
+       VECT_B(r, 3) = VECT_B(gCPU.vr[vrB], 1);
+       VECT_B(r, 4) = VECT_B(gCPU.vr[vrA], 2);
+       VECT_B(r, 5) = VECT_B(gCPU.vr[vrB], 2);
+       VECT_B(r, 6) = VECT_B(gCPU.vr[vrA], 3);
+       VECT_B(r, 7) = VECT_B(gCPU.vr[vrB], 3);
+       VECT_B(r, 8) = VECT_B(gCPU.vr[vrA], 4);
+       VECT_B(r, 9) = VECT_B(gCPU.vr[vrB], 4);
+       VECT_B(r,10) = VECT_B(gCPU.vr[vrA], 5);
+       VECT_B(r,11) = VECT_B(gCPU.vr[vrB], 5);
+       VECT_B(r,12) = VECT_B(gCPU.vr[vrA], 6);
+       VECT_B(r,13) = VECT_B(gCPU.vr[vrB], 6);
+       VECT_B(r,14) = VECT_B(gCPU.vr[vrA], 7);
+       VECT_B(r,15) = VECT_B(gCPU.vr[vrB], 7);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vmrghh          Vector Merge High Half Word
+ *     v.196
+ */
+void ppc_opc_vmrghh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = VECT_H(gCPU.vr[vrA], 0);
+       VECT_H(r, 1) = VECT_H(gCPU.vr[vrB], 0);
+       VECT_H(r, 2) = VECT_H(gCPU.vr[vrA], 1);
+       VECT_H(r, 3) = VECT_H(gCPU.vr[vrB], 1);
+       VECT_H(r, 4) = VECT_H(gCPU.vr[vrA], 2);
+       VECT_H(r, 5) = VECT_H(gCPU.vr[vrB], 2);
+       VECT_H(r, 6) = VECT_H(gCPU.vr[vrA], 3);
+       VECT_H(r, 7) = VECT_H(gCPU.vr[vrB], 3);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vmrghw          Vector Merge High Word
+ *     v.197
+ */
+void ppc_opc_vmrghw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_W(r, 0) = VECT_W(gCPU.vr[vrA], 0);
+       VECT_W(r, 1) = VECT_W(gCPU.vr[vrB], 0);
+       VECT_W(r, 2) = VECT_W(gCPU.vr[vrA], 1);
+       VECT_W(r, 3) = VECT_W(gCPU.vr[vrB], 1);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vmrglb          Vector Merge Low Byte
+ *     v.198
+ */
+void ppc_opc_vmrglb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = VECT_B(gCPU.vr[vrA], 8);
+       VECT_B(r, 1) = VECT_B(gCPU.vr[vrB], 8);
+       VECT_B(r, 2) = VECT_B(gCPU.vr[vrA], 9);
+       VECT_B(r, 3) = VECT_B(gCPU.vr[vrB], 9);
+       VECT_B(r, 4) = VECT_B(gCPU.vr[vrA],10);
+       VECT_B(r, 5) = VECT_B(gCPU.vr[vrB],10);
+       VECT_B(r, 6) = VECT_B(gCPU.vr[vrA],11);
+       VECT_B(r, 7) = VECT_B(gCPU.vr[vrB],11);
+       VECT_B(r, 8) = VECT_B(gCPU.vr[vrA],12);
+       VECT_B(r, 9) = VECT_B(gCPU.vr[vrB],12);
+       VECT_B(r,10) = VECT_B(gCPU.vr[vrA],13);
+       VECT_B(r,11) = VECT_B(gCPU.vr[vrB],13);
+       VECT_B(r,12) = VECT_B(gCPU.vr[vrA],14);
+       VECT_B(r,13) = VECT_B(gCPU.vr[vrB],14);
+       VECT_B(r,14) = VECT_B(gCPU.vr[vrA],15);
+       VECT_B(r,15) = VECT_B(gCPU.vr[vrB],15);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vmrglh          Vector Merge Low Half Word
+ *     v.199
+ */
+void ppc_opc_vmrglh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = VECT_H(gCPU.vr[vrA], 4);
+       VECT_H(r, 1) = VECT_H(gCPU.vr[vrB], 4);
+       VECT_H(r, 2) = VECT_H(gCPU.vr[vrA], 5);
+       VECT_H(r, 3) = VECT_H(gCPU.vr[vrB], 5);
+       VECT_H(r, 4) = VECT_H(gCPU.vr[vrA], 6);
+       VECT_H(r, 5) = VECT_H(gCPU.vr[vrB], 6);
+       VECT_H(r, 6) = VECT_H(gCPU.vr[vrA], 7);
+       VECT_H(r, 7) = VECT_H(gCPU.vr[vrB], 7);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vmrglw          Vector Merge Low Word
+ *     v.200
+ */
+void ppc_opc_vmrglw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_W(r, 0) = VECT_W(gCPU.vr[vrA], 2);
+       VECT_W(r, 1) = VECT_W(gCPU.vr[vrB], 2);
+       VECT_W(r, 2) = VECT_W(gCPU.vr[vrA], 3);
+       VECT_W(r, 3) = VECT_W(gCPU.vr[vrB], 3);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vspltb          Vector Splat Byte
+ *     v.245
+ */
+void ppc_opc_vspltb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       /* The documentation doesn't stipulate what a value higher than 0xf
+        *   will do.  Thus, this is by default an undefined value.  We
+        *   are thus doing this the fastest way that won't crash us.
+        */
+       val = VECT_B(gCPU.vr[vrB], uimm & 0xf);
+       val |= (val << 8);
+       val |= (val << 16);
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vsplth          Vector Splat Half Word
+ *     v.246
+ */
+void ppc_opc_vsplth()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       /* The documentation doesn't stipulate what a value higher than 0x7
+        *   will do.  Thus, this is by default an undefined value.  We
+        *   are thus doing this the fastest way that won't crash us.
+        */
+       val = VECT_H(gCPU.vr[vrB], uimm & 0x7);
+       val |= (val << 16);
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vspltw          Vector Splat Word
+ *     v.250
+ */
+void ppc_opc_vspltw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       /* The documentation doesn't stipulate what a value higher than 0x3
+        *   will do.  Thus, this is by default an undefined value.  We
+        *   are thus doing this the fastest way that won't crash us.
+        */
+       val = VECT_W(gCPU.vr[vrB], uimm & 0x3);
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vspltisb        Vector Splat Immediate Signed Byte
+ *     v.247
+ */
+void ppc_opc_vspltisb()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrB;
+       uint32 simm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, simm, vrB);
+       PPC_OPC_ASSERT(vrB==0);
+
+       val = (simm & 0x10) ? (simm | 0xE0) : simm;
+       val |= (val << 8);
+       val |= (val << 16);
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vspltish        Vector Splat Immediate Signed Half Word
+ *     v.248
+ */
+void ppc_opc_vspltish()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrB;
+       uint32 simm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, simm, vrB);
+       PPC_OPC_ASSERT(vrB==0);
+
+       val = (simm & 0x10) ? (simm | 0xFFE0) : simm;
+       val |= (val << 16);
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     vspltisw        Vector Splat Immediate Signed Word
+ *     v.249
+ */
+void ppc_opc_vspltisw()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrB;
+       uint32 simm;
+       uint64 val;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, simm, vrB);
+       PPC_OPC_ASSERT(vrB==0);
+
+       val = (simm & 0x10) ? (simm | 0xFFFFFFE0) : simm;
+       val |= (val << 32);
+
+       gCPU.vr[vrD].d[0] = val;
+       gCPU.vr[vrD].d[1] = val;
+}
+
+/*     mfvscr          Move from Vector Status and Control Register
+ *     v.129
+ */
+void ppc_opc_mfvscr()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+       PPC_OPC_ASSERT(vrB==0);
+
+       VECT_W(gCPU.vr[vrD], 3) = gCPU.vscr;
+       VECT_W(gCPU.vr[vrD], 2) = 0;
+       VECT_D(gCPU.vr[vrD], 0) = 0;
+}
+
+/*     mtvscr          Move to Vector Status and Control Register
+ *     v.130
+ */
+void ppc_opc_mtvscr()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+       PPC_OPC_ASSERT(vrD==0);
+
+       gCPU.vscr = VECT_W(gCPU.vr[vrB], 3);
+}
+
+/*     vpkuhum         Vector Pack Unsigned Half Word Unsigned Modulo
+ *     v.224
+ */
+void ppc_opc_vpkuhum()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = VECT_B(gCPU.vr[vrA], 1);
+       VECT_B(r, 1) = VECT_B(gCPU.vr[vrA], 3);
+       VECT_B(r, 2) = VECT_B(gCPU.vr[vrA], 5);
+       VECT_B(r, 3) = VECT_B(gCPU.vr[vrA], 7);
+       VECT_B(r, 4) = VECT_B(gCPU.vr[vrA], 9);
+       VECT_B(r, 5) = VECT_B(gCPU.vr[vrA],11);
+       VECT_B(r, 6) = VECT_B(gCPU.vr[vrA],13);
+       VECT_B(r, 7) = VECT_B(gCPU.vr[vrA],15);
+
+       VECT_B(r, 8) = VECT_B(gCPU.vr[vrB], 1);
+       VECT_B(r, 9) = VECT_B(gCPU.vr[vrB], 3);
+       VECT_B(r,10) = VECT_B(gCPU.vr[vrB], 5);
+       VECT_B(r,11) = VECT_B(gCPU.vr[vrB], 7);
+       VECT_B(r,12) = VECT_B(gCPU.vr[vrB], 9);
+       VECT_B(r,13) = VECT_B(gCPU.vr[vrB],11);
+       VECT_B(r,14) = VECT_B(gCPU.vr[vrB],13);
+       VECT_B(r,15) = VECT_B(gCPU.vr[vrB],15);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkuwum         Vector Pack Unsigned Word Unsigned Modulo
+ *     v.226
+ */
+void ppc_opc_vpkuwum()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = VECT_H(gCPU.vr[vrA], 1);
+       VECT_H(r, 1) = VECT_H(gCPU.vr[vrA], 3);
+       VECT_H(r, 2) = VECT_H(gCPU.vr[vrA], 5);
+       VECT_H(r, 3) = VECT_H(gCPU.vr[vrA], 7);
+
+       VECT_H(r, 4) = VECT_H(gCPU.vr[vrB], 1);
+       VECT_H(r, 5) = VECT_H(gCPU.vr[vrB], 3);
+       VECT_H(r, 6) = VECT_H(gCPU.vr[vrB], 5);
+       VECT_H(r, 7) = VECT_H(gCPU.vr[vrB], 7);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkpx           Vector Pack Pixel32
+ *     v.219
+ */
+void ppc_opc_vpkpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = PACK_PIXEL(VECT_W(gCPU.vr[vrA], 0));
+       VECT_H(r, 1) = PACK_PIXEL(VECT_W(gCPU.vr[vrA], 1));
+       VECT_H(r, 2) = PACK_PIXEL(VECT_W(gCPU.vr[vrA], 2));
+       VECT_H(r, 3) = PACK_PIXEL(VECT_W(gCPU.vr[vrA], 3));
+
+       VECT_H(r, 4) = PACK_PIXEL(VECT_W(gCPU.vr[vrB], 0));
+       VECT_H(r, 5) = PACK_PIXEL(VECT_W(gCPU.vr[vrB], 1));
+       VECT_H(r, 6) = PACK_PIXEL(VECT_W(gCPU.vr[vrB], 2));
+       VECT_H(r, 7) = PACK_PIXEL(VECT_W(gCPU.vr[vrB], 3));
+
+       gCPU.vr[vrD] = r;
+}
+
+
+/*     vpkuhus         Vector Pack Unsigned Half Word Unsigned Saturate
+ *     v.225
+ */
+void ppc_opc_vpkuhus()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 0));
+       VECT_B(r, 1) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 1));
+       VECT_B(r, 2) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 2));
+       VECT_B(r, 3) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 3));
+       VECT_B(r, 4) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 4));
+       VECT_B(r, 5) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 5));
+       VECT_B(r, 6) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 6));
+       VECT_B(r, 7) = SATURATE_UB(VECT_H(gCPU.vr[vrA], 7));
+
+       VECT_B(r, 8) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 0));
+       VECT_B(r, 9) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 1));
+       VECT_B(r,10) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 2));
+       VECT_B(r,11) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 3));
+       VECT_B(r,12) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 4));
+       VECT_B(r,13) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 5));
+       VECT_B(r,14) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 6));
+       VECT_B(r,15) = SATURATE_UB(VECT_H(gCPU.vr[vrB], 7));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkshss         Vector Pack Signed Half Word Signed Saturate
+ *     v.220
+ */
+void ppc_opc_vpkshss()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 0));
+       VECT_B(r, 1) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 1));
+       VECT_B(r, 2) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 2));
+       VECT_B(r, 3) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 3));
+       VECT_B(r, 4) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 4));
+       VECT_B(r, 5) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 5));
+       VECT_B(r, 6) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 6));
+       VECT_B(r, 7) = SATURATE_SB(VECT_H(gCPU.vr[vrA], 7));
+
+       VECT_B(r, 8) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 0));
+       VECT_B(r, 9) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 1));
+       VECT_B(r,10) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 2));
+       VECT_B(r,11) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 3));
+       VECT_B(r,12) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 4));
+       VECT_B(r,13) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 5));
+       VECT_B(r,14) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 6));
+       VECT_B(r,15) = SATURATE_SB(VECT_H(gCPU.vr[vrB], 7));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkuwus         Vector Pack Unsigned Word Unsigned Saturate
+ *     v.227
+ */
+void ppc_opc_vpkuwus()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = SATURATE_UH(VECT_W(gCPU.vr[vrA], 0));
+       VECT_H(r, 1) = SATURATE_UH(VECT_W(gCPU.vr[vrA], 1));
+       VECT_H(r, 2) = SATURATE_UH(VECT_W(gCPU.vr[vrA], 2));
+       VECT_H(r, 3) = SATURATE_UH(VECT_W(gCPU.vr[vrA], 3));
+
+       VECT_H(r, 4) = SATURATE_UH(VECT_W(gCPU.vr[vrB], 0));
+       VECT_H(r, 5) = SATURATE_UH(VECT_W(gCPU.vr[vrB], 1));
+       VECT_H(r, 6) = SATURATE_UH(VECT_W(gCPU.vr[vrB], 2));
+       VECT_H(r, 7) = SATURATE_UH(VECT_W(gCPU.vr[vrB], 3));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkswss         Vector Pack Signed Word Signed Saturate
+ *     v.222
+ */
+void ppc_opc_vpkswss()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = SATURATE_SH(VECT_W(gCPU.vr[vrA], 0));
+       VECT_H(r, 1) = SATURATE_SH(VECT_W(gCPU.vr[vrA], 1));
+       VECT_H(r, 2) = SATURATE_SH(VECT_W(gCPU.vr[vrA], 2));
+       VECT_H(r, 3) = SATURATE_SH(VECT_W(gCPU.vr[vrA], 3));
+
+       VECT_H(r, 4) = SATURATE_SH(VECT_W(gCPU.vr[vrB], 0));
+       VECT_H(r, 5) = SATURATE_SH(VECT_W(gCPU.vr[vrB], 1));
+       VECT_H(r, 6) = SATURATE_SH(VECT_W(gCPU.vr[vrB], 2));
+       VECT_H(r, 7) = SATURATE_SH(VECT_W(gCPU.vr[vrB], 3));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkshus         Vector Pack Signed Half Word Unsigned Saturate
+ *     v.221
+ */
+void ppc_opc_vpkshus()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_B(r, 0) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 0));
+       VECT_B(r, 1) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 1));
+       VECT_B(r, 2) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 2));
+       VECT_B(r, 3) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 3));
+       VECT_B(r, 4) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 4));
+       VECT_B(r, 5) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 5));
+       VECT_B(r, 6) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 6));
+       VECT_B(r, 7) = SATURATE_USB(VECT_H(gCPU.vr[vrA], 7));
+
+       VECT_B(r, 8) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 0));
+       VECT_B(r, 9) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 1));
+       VECT_B(r,10) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 2));
+       VECT_B(r,11) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 3));
+       VECT_B(r,12) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 4));
+       VECT_B(r,13) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 5));
+       VECT_B(r,14) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 6));
+       VECT_B(r,15) = SATURATE_USB(VECT_H(gCPU.vr[vrB], 7));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vpkswus         Vector Pack Signed Word Unsigned Saturate
+ *     v.223
+ */
+void ppc_opc_vpkswus()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       VECT_H(r, 0) = SATURATE_USH(VECT_W(gCPU.vr[vrA], 0));
+       VECT_H(r, 1) = SATURATE_USH(VECT_W(gCPU.vr[vrA], 1));
+       VECT_H(r, 2) = SATURATE_USH(VECT_W(gCPU.vr[vrA], 2));
+       VECT_H(r, 3) = SATURATE_USH(VECT_W(gCPU.vr[vrA], 3));
+
+       VECT_H(r, 4) = SATURATE_USH(VECT_W(gCPU.vr[vrB], 0));
+       VECT_H(r, 5) = SATURATE_USH(VECT_W(gCPU.vr[vrB], 1));
+       VECT_H(r, 6) = SATURATE_USH(VECT_W(gCPU.vr[vrB], 2));
+       VECT_H(r, 7) = SATURATE_USH(VECT_W(gCPU.vr[vrB], 3));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupkhsb         Vector Unpack High Signed Byte
+ *     v.277
+ */
+void ppc_opc_vupkhsb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_SH(r, 0) = VECT_SB(gCPU.vr[vrB], 0);
+       VECT_SH(r, 1) = VECT_SB(gCPU.vr[vrB], 1);
+       VECT_SH(r, 2) = VECT_SB(gCPU.vr[vrB], 2);
+       VECT_SH(r, 3) = VECT_SB(gCPU.vr[vrB], 3);
+       VECT_SH(r, 4) = VECT_SB(gCPU.vr[vrB], 4);
+       VECT_SH(r, 5) = VECT_SB(gCPU.vr[vrB], 5);
+       VECT_SH(r, 6) = VECT_SB(gCPU.vr[vrB], 6);
+       VECT_SH(r, 7) = VECT_SB(gCPU.vr[vrB], 7);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupkhpx         Vector Unpack High Pixel32
+ *     v.279
+ */
+void ppc_opc_vupkhpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_W(r, 0) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 0));
+       VECT_W(r, 1) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 1));
+       VECT_W(r, 2) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 2));
+       VECT_W(r, 3) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 3));
+       
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupkhsh         Vector Unpack High Signed Half Word
+ *     v.278
+ */
+void ppc_opc_vupkhsh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_SW(r, 0) = VECT_SH(gCPU.vr[vrB], 0);
+       VECT_SW(r, 1) = VECT_SH(gCPU.vr[vrB], 1);
+       VECT_SW(r, 2) = VECT_SH(gCPU.vr[vrB], 2);
+       VECT_SW(r, 3) = VECT_SH(gCPU.vr[vrB], 3);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupklsb         Vector Unpack Low Signed Byte
+ *     v.280
+ */
+void ppc_opc_vupklsb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_SH(r, 0) = VECT_SB(gCPU.vr[vrB], 8);
+       VECT_SH(r, 1) = VECT_SB(gCPU.vr[vrB], 9);
+       VECT_SH(r, 2) = VECT_SB(gCPU.vr[vrB],10);
+       VECT_SH(r, 3) = VECT_SB(gCPU.vr[vrB],11);
+       VECT_SH(r, 4) = VECT_SB(gCPU.vr[vrB],12);
+       VECT_SH(r, 5) = VECT_SB(gCPU.vr[vrB],13);
+       VECT_SH(r, 6) = VECT_SB(gCPU.vr[vrB],14);
+       VECT_SH(r, 7) = VECT_SB(gCPU.vr[vrB],15);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupklpx         Vector Unpack Low Pixel32
+ *     v.279
+ */
+void ppc_opc_vupklpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_W(r, 0) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 4));
+       VECT_W(r, 1) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 5));
+       VECT_W(r, 2) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 6));
+       VECT_W(r, 3) = UNPACK_PIXEL(VECT_H(gCPU.vr[vrB], 7));
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vupklsh         Vector Unpack Low Signed Half Word
+ *     v.281
+ */
+void ppc_opc_vupklsh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       Vector_t r;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       VECT_SW(r, 0) = VECT_SH(gCPU.vr[vrB], 4);
+       VECT_SW(r, 1) = VECT_SH(gCPU.vr[vrB], 5);
+       VECT_SW(r, 2) = VECT_SH(gCPU.vr[vrB], 6);
+       VECT_SW(r, 3) = VECT_SH(gCPU.vr[vrB], 7);
+
+       gCPU.vr[vrD] = r;
+}
+
+/*     vaddubm         Vector Add Unsigned Byte Modulo
+ *     v.141
+ */
+void ppc_opc_vaddubm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].b[i] + gCPU.vr[vrB].b[i];
+               gCPU.vr[vrD].b[i] = res;
+       }
+}
+
+/*     vadduhm         Vector Add Unsigned Half Word Modulo
+ *     v.143
+ */
+void ppc_opc_vadduhm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].h[i] + gCPU.vr[vrB].h[i];
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vadduwm         Vector Add Unsigned Word Modulo
+ *     v.145
+ */
+void ppc_opc_vadduwm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] + gCPU.vr[vrB].w[i];
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vaddfp          Vector Add Float Point
+ *     v.137
+ */
+void ppc_opc_vaddfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       float res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = gCPU.vr[vrA].f[i] + gCPU.vr[vrB].f[i];
+               gCPU.vr[vrD].f[i] = res;
+       }
+}
+
+/*     vaddcuw         Vector Add Carryout Unsigned Word
+ *     v.136
+ */
+void ppc_opc_vaddcuw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] + gCPU.vr[vrB].w[i];
+               gCPU.vr[vrD].w[i] = (res < gCPU.vr[vrA].w[i]) ? 1 : 0;
+       }
+}
+
+/*     vaddubs         Vector Add Unsigned Byte Saturate
+ *     v.142
+ */
+void ppc_opc_vaddubs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (uint16)gCPU.vr[vrA].b[i] + (uint16)gCPU.vr[vrB].b[i];
+               gCPU.vr[vrD].b[i] = SATURATE_UB(res);
+       }
+}
+
+/*     vaddsbs         Vector Add Signed Byte Saturate
+ *     v.138
+ */
+void ppc_opc_vaddsbs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (sint16)gCPU.vr[vrA].sb[i] + (sint16)gCPU.vr[vrB].sb[i];
+               gCPU.vr[vrD].b[i] = SATURATE_SB(res);
+       }
+}
+
+/*     vadduhs         Vector Add Unsigned Half Word Saturate
+ *     v.144
+ */
+void ppc_opc_vadduhs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (uint32)gCPU.vr[vrA].h[i] + (uint32)gCPU.vr[vrB].h[i];
+               gCPU.vr[vrD].h[i] = SATURATE_UH(res);
+       }
+}
+
+/*     vaddshs         Vector Add Signed Half Word Saturate
+ *     v.139
+ */
+void ppc_opc_vaddshs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (sint32)gCPU.vr[vrA].sh[i] + (sint32)gCPU.vr[vrB].sh[i];
+               gCPU.vr[vrD].h[i] = SATURATE_SH(res);
+       }
+}
+
+/*     vadduws         Vector Add Unsigned Word Saturate
+ *     v.146
+ */
+void ppc_opc_vadduws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] + gCPU.vr[vrB].w[i];
+
+               // We do this to prevent us from having to do 64-bit math
+               if (res < gCPU.vr[vrA].w[i]) {
+                       res = 0xFFFFFFFF;
+                       gCPU.vscr |= VSCR_SAT;
+               }
+
+       /*      64-bit math             |       32-bit hack
+        *      ------------------------+-------------------------------------
+        *      add, addc       (a+b)   |       add             (a+b)
+        *      sub, subb       (r>ub)  |       sub             (r<a)
+        */
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vaddsws         Vector Add Signed Word Saturate
+ *     v.140
+ */
+void ppc_opc_vaddsws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] + gCPU.vr[vrB].w[i];
+
+               // We do this to prevent us from having to do 64-bit math
+               if (((gCPU.vr[vrA].w[i] ^ gCPU.vr[vrB].w[i]) & SIGN32) == 0) {
+                       // the signs of both operands are the same
+
+                       if (((res ^ gCPU.vr[vrA].w[i]) & SIGN32) != 0) {
+                               // sign of result != sign of operands
+
+                               // if res is negative, should have been positive
+                               res = (res & SIGN32) ? (SIGN32 - 1) : SIGN32;
+                               gCPU.vscr |= VSCR_SAT;
+                       }
+               }
+
+       /*      64-bit math             |       32-bit hack
+        *      ------------------------+-------------------------------------
+        *      add, addc       (a+b)   |       add             (a+b)
+        *      sub, subb       (r>ub)  |       xor, and        (sign == sign)
+        *      sub, subb       (r<lb)  |       xor, and        (sign != sign)
+        *                              |       and             (which)
+        */
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vsububm         Vector Subtract Unsigned Byte Modulo
+ *     v.265
+ */
+void ppc_opc_vsububm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].b[i] - gCPU.vr[vrB].b[i];
+               gCPU.vr[vrD].b[i] = res;
+       }
+}
+
+/*     vsubuhm         Vector Subtract Unsigned Half Word Modulo
+ *     v.267
+ */
+void ppc_opc_vsubuhm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].h[i] - gCPU.vr[vrB].h[i];
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vsubuwm         Vector Subtract Unsigned Word Modulo
+ *     v.269
+ */
+void ppc_opc_vsubuwm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] - gCPU.vr[vrB].w[i];
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vsubfp          Vector Subtract Float Point
+ *     v.261
+ */
+void ppc_opc_vsubfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       float res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = gCPU.vr[vrA].f[i] - gCPU.vr[vrB].f[i];
+               gCPU.vr[vrD].f[i] = res;
+       }
+}
+
+/*     vsubcuw         Vector Subtract Carryout Unsigned Word
+ *     v.260
+ */
+void ppc_opc_vsubcuw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] - gCPU.vr[vrB].w[i];
+               gCPU.vr[vrD].w[i] = (res <= gCPU.vr[vrA].w[i]) ? 1 : 0;
+       }
+}
+
+/*     vsububs         Vector Subtract Unsigned Byte Saturate
+ *     v.266
+ */
+void ppc_opc_vsububs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (uint16)gCPU.vr[vrA].b[i] - (uint16)gCPU.vr[vrB].b[i];
+
+               gCPU.vr[vrD].b[i] = SATURATE_0B(res);
+       }
+}
+
+/*     vsubsbs         Vector Subtract Signed Byte Saturate
+ *     v.262
+ */
+void ppc_opc_vsubsbs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (sint16)gCPU.vr[vrA].sb[i] - (sint16)gCPU.vr[vrB].sb[i];
+
+               gCPU.vr[vrD].sb[i] = SATURATE_SB(res);
+       }
+}
+
+/*     vsubuhs         Vector Subtract Unsigned Half Word Saturate
+ *     v.268
+ */
+void ppc_opc_vsubuhs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (uint32)gCPU.vr[vrA].h[i] - (uint32)gCPU.vr[vrB].h[i];
+
+               gCPU.vr[vrD].h[i] = SATURATE_0H(res);
+       }
+}
+
+/*     vsubshs         Vector Subtract Signed Half Word Saturate
+ *     v.263
+ */
+void ppc_opc_vsubshs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (sint32)gCPU.vr[vrA].sh[i] - (sint32)gCPU.vr[vrB].sh[i];
+
+               gCPU.vr[vrD].sh[i] = SATURATE_SH(res);
+       }
+}
+
+/*     vsubuws         Vector Subtract Unsigned Word Saturate
+ *     v.270
+ */
+void ppc_opc_vsubuws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i] - gCPU.vr[vrB].w[i];
+
+               // We do this to prevent us from having to do 64-bit math
+               if (res > gCPU.vr[vrA].w[i]) {
+                       res = 0;
+                       gCPU.vscr |= VSCR_SAT;
+               }
+
+       /*      64-bit math             |       32-bit hack
+        *      ------------------------+-------------------------------------
+        *      sub, subb       (a+b)   |       sub             (a+b)
+        *      sub, subb       (r>ub)  |       sub             (r<a)
+        */
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vsubsws         Vector Subtract Signed Word Saturate
+ *     v.264
+ */
+void ppc_opc_vsubsws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res, tmp;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               tmp = -gCPU.vr[vrB].w[i];
+               res = gCPU.vr[vrA].w[i] + tmp;
+
+               // We do this to prevent us from having to do 64-bit math
+               if (((gCPU.vr[vrA].w[i] ^ tmp) & SIGN32) == 0) {
+                       // the signs of both operands are the same
+
+                       if (((res ^ tmp) & SIGN32) != 0) {
+                               // sign of result != sign of operands
+
+                               // if res is negative, should have been positive
+                               res = (res & SIGN32) ? (SIGN32 - 1) : SIGN32;
+                               gCPU.vscr |= VSCR_SAT;
+                       }
+               }
+
+       /*      64-bit math             |       32-bit hack
+        *      ------------------------+-------------------------------------
+        *      sub, subc       (a+b)   |       neg, add        (a-b)
+        *      sub, subb       (r>ub)  |       xor, and        (sign == sign)
+        *      sub, subb       (r<lb)  |       xor, and        (sign != sign)
+        *                              |       and             (which)
+        */
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vmuleub         Vector Multiply Even Unsigned Byte
+ *     v.209
+ */
+void ppc_opc_vmuleub()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (uint16)gCPU.vr[vrA].b[VECT_EVEN(i)] *
+                        (uint16)gCPU.vr[vrB].b[VECT_EVEN(i)];
+
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vmulesb         Vector Multiply Even Signed Byte
+ *     v.207
+ */
+void ppc_opc_vmulesb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (sint16)gCPU.vr[vrA].sb[VECT_EVEN(i)] *
+                        (sint16)gCPU.vr[vrB].sb[VECT_EVEN(i)];
+
+               gCPU.vr[vrD].sh[i] = res;
+       }
+}
+
+/*     vmuleuh         Vector Multiply Even Unsigned Half Word
+ *     v.210
+ */
+void ppc_opc_vmuleuh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (uint32)gCPU.vr[vrA].h[VECT_EVEN(i)] *
+                        (uint32)gCPU.vr[vrB].h[VECT_EVEN(i)];
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vmulesh         Vector Multiply Even Signed Half Word
+ *     v.208
+ */
+void ppc_opc_vmulesh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (sint32)gCPU.vr[vrA].sh[VECT_EVEN(i)] *
+                        (sint32)gCPU.vr[vrB].sh[VECT_EVEN(i)];
+
+               gCPU.vr[vrD].sw[i] = res;
+       }
+}
+
+/*     vmuloub         Vector Multiply Odd Unsigned Byte
+ *     v.213
+ */
+void ppc_opc_vmuloub()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (uint16)gCPU.vr[vrA].b[VECT_ODD(i)] *
+                        (uint16)gCPU.vr[vrB].b[VECT_ODD(i)];
+
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vmulosb         Vector Multiply Odd Signed Byte
+ *     v.211
+ */
+void ppc_opc_vmulosb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (sint16)gCPU.vr[vrA].sb[VECT_ODD(i)] *
+                        (sint16)gCPU.vr[vrB].sb[VECT_ODD(i)];
+
+               gCPU.vr[vrD].sh[i] = res;
+       }
+}
+
+/*     vmulouh         Vector Multiply Odd Unsigned Half Word
+ *     v.214
+ */
+void ppc_opc_vmulouh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (uint32)gCPU.vr[vrA].h[VECT_ODD(i)] *
+                        (uint32)gCPU.vr[vrB].h[VECT_ODD(i)];
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vmulosh         Vector Multiply Odd Signed Half Word
+ *     v.212
+ */
+void ppc_opc_vmulosh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (sint32)gCPU.vr[vrA].sh[VECT_ODD(i)] *
+                        (sint32)gCPU.vr[vrB].sh[VECT_ODD(i)];
+
+               gCPU.vr[vrD].sw[i] = res;
+       }
+}
+
+/*     vmaddfp         Vector Multiply Add Floating Point
+ *     v.177
+ */
+void ppc_opc_vmaddfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       double res;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = (double)gCPU.vr[vrA].f[i] * (double)gCPU.vr[vrC].f[i];
+
+               res = (double)gCPU.vr[vrB].f[i] + res;
+
+               gCPU.vr[vrD].f[i] = (float)res;
+       }
+}
+
+/*     vmhaddshs       Vector Multiply High and Add Signed Half Word Saturate
+ *     v.185
+ */
+void ppc_opc_vmhaddshs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       sint32 prod;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<8; i++) {
+               prod = (sint32)gCPU.vr[vrA].sh[i] * (sint32)gCPU.vr[vrB].sh[i];
+
+               prod = (prod >> 15) + (sint32)gCPU.vr[vrC].sh[i];
+
+               gCPU.vr[vrD].sh[i] = SATURATE_SH(prod);
+       }
+}
+
+/*     vmladduhm       Vector Multiply Low and Add Unsigned Half Word Modulo
+ *     v.194
+ */
+void ppc_opc_vmladduhm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       uint32 prod;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<8; i++) {
+               prod = (uint32)gCPU.vr[vrA].h[i] * (uint32)gCPU.vr[vrB].h[i];
+
+               prod = prod + (uint32)gCPU.vr[vrC].h[i];
+
+               gCPU.vr[vrD].h[i] = prod;
+       }
+}
+
+/*     vmhraddshs      Vector Multiply High Round and Add Signed Half Word Saturate
+ *     v.186
+ */
+void ppc_opc_vmhraddshs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       sint32 prod;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<8; i++) {
+               prod = (sint32)gCPU.vr[vrA].sh[i] * (sint32)gCPU.vr[vrB].sh[i];
+
+               prod += 0x4000;
+               prod = (prod >> 15) + (sint32)gCPU.vr[vrC].sh[i];
+
+               gCPU.vr[vrD].sh[i] = SATURATE_SH(prod);
+       }
+}
+
+/*     vmsumubm        Vector Multiply Sum Unsigned Byte Modulo
+ *     v.204
+ */
+void ppc_opc_vmsumubm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       uint32 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].w[i];
+
+               temp += (uint16)gCPU.vr[vrA].b[i<<2] *
+                       (uint16)gCPU.vr[vrB].b[i<<2];
+
+               temp += (uint16)gCPU.vr[vrA].b[(i<<2)+1] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+1];
+
+               temp += (uint16)gCPU.vr[vrA].b[(i<<2)+2] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+2];
+
+               temp += (uint16)gCPU.vr[vrA].b[(i<<2)+3] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+3];
+
+               gCPU.vr[vrD].w[i] = temp;
+       }
+}
+
+/*     vmsumuhm        Vector Multiply Sum Unsigned Half Word Modulo
+ *     v.205
+ */
+void ppc_opc_vmsumuhm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       uint32 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].w[i];
+
+               temp += (uint32)gCPU.vr[vrA].h[i<<1] *
+                       (uint32)gCPU.vr[vrB].h[i<<1];
+               temp += (uint32)gCPU.vr[vrA].h[(i<<1)+1] *
+                       (uint32)gCPU.vr[vrB].h[(i<<1)+1];
+
+               gCPU.vr[vrD].w[i] = temp;
+       }
+}
+
+/*     vmsummbm        Vector Multiply Sum Mixed-Sign Byte Modulo
+ *     v.201
+ */
+void ppc_opc_vmsummbm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       sint32 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].sw[i];
+
+               temp += (sint16)gCPU.vr[vrA].sb[i<<2] *
+                       (uint16)gCPU.vr[vrB].b[i<<2];
+               temp += (sint16)gCPU.vr[vrA].sb[(i<<2)+1] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+1];
+               temp += (sint16)gCPU.vr[vrA].sb[(i<<2)+2] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+2];
+               temp += (sint16)gCPU.vr[vrA].sb[(i<<2)+3] *
+                       (uint16)gCPU.vr[vrB].b[(i<<2)+3];
+
+               gCPU.vr[vrD].sw[i] = temp;
+       }
+}
+
+/*     vmsumshm        Vector Multiply Sum Signed Half Word Modulo
+ *     v.202
+ */
+void ppc_opc_vmsumshm()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       sint32 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].sw[i];
+
+               temp += (sint32)gCPU.vr[vrA].sh[i<<1] *
+                       (sint32)gCPU.vr[vrB].sh[i<<1];
+               temp += (sint32)gCPU.vr[vrA].sh[(i<<1)+1] *
+                       (sint32)gCPU.vr[vrB].sh[(i<<1)+1];
+
+               gCPU.vr[vrD].sw[i] = temp;
+       }
+}
+
+/*     vmsumuhs        Vector Multiply Sum Unsigned Half Word Saturate
+ *     v.206
+ */
+void ppc_opc_vmsumuhs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       uint64 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       /* For this, there's no way to get around 64-bit math.  If we use
+        *   the hacks used before, then we have to do it so often, that
+        *   we'll outpace the 64-bit math in execution time.
+        */
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].w[i];
+
+               temp += (uint32)gCPU.vr[vrA].h[i<<1] *
+                       (uint32)gCPU.vr[vrB].h[i<<1];
+
+               temp += (uint32)gCPU.vr[vrA].h[(i<<1)+1] *
+                       (uint32)gCPU.vr[vrB].h[(i<<1)+1];
+
+               gCPU.vr[vrD].w[i] = SATURATE_UW(temp);
+       }
+}
+
+/*     vmsumshs        Vector Multiply Sum Signed Half Word Saturate
+ *     v.203
+ */
+void ppc_opc_vmsumshs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       sint64 temp;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       /* For this, there's no way to get around 64-bit math.  If we use
+        *   the hacks used before, then we have to do it so often, that
+        *   we'll outpace the 64-bit math in execution time.
+        */
+
+       for (int i=0; i<4; i++) {
+               temp = gCPU.vr[vrC].sw[i];
+
+               temp += (sint32)gCPU.vr[vrA].sh[i<<1] *
+                       (sint32)gCPU.vr[vrB].sh[i<<1];
+               temp += (sint32)gCPU.vr[vrA].sh[(i<<1)+1] *
+                       (sint32)gCPU.vr[vrB].sh[(i<<1)+1];
+
+               gCPU.vr[vrD].sw[i] = SATURATE_SW(temp);
+       }
+}
+
+/*     vsum4ubs        Vector Sum Across Partial (1/4) Unsigned Byte Saturate
+ *     v.275
+ */
+void ppc_opc_vsum4ubs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       /* For this, there's no way to get around 64-bit math.  If we use
+        *   the hacks used before, then we have to do it so often, that
+        *   we'll outpace the 64-bit math in execution time.
+        */
+
+       for (int i=0; i<4; i++) {
+               res = (uint64)gCPU.vr[vrB].w[i];
+
+               res += (uint64)gCPU.vr[vrA].b[(i<<2)];
+               res += (uint64)gCPU.vr[vrA].b[(i<<2)+1];
+               res += (uint64)gCPU.vr[vrA].b[(i<<2)+2];
+               res += (uint64)gCPU.vr[vrA].b[(i<<2)+3];
+
+               gCPU.vr[vrD].w[i] = SATURATE_UW(res);
+       }
+}
+
+/*     vsum4sbs        Vector Sum Across Partial (1/4) Signed Byte Saturate
+ *     v.273
+ */
+void ppc_opc_vsum4sbs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (sint64)gCPU.vr[vrB].sw[i];
+
+               res += (sint64)gCPU.vr[vrA].sb[(i<<2)];
+               res += (sint64)gCPU.vr[vrA].sb[(i<<2)+1];
+               res += (sint64)gCPU.vr[vrA].sb[(i<<2)+2];
+               res += (sint64)gCPU.vr[vrA].sb[(i<<2)+3];
+
+               gCPU.vr[vrD].sw[i] = SATURATE_SW(res);
+       }
+}
+
+/*     vsum4shs        Vector Sum Across Partial (1/4) Signed Half Word Saturate
+ *     v.274
+ */
+void ppc_opc_vsum4shs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (sint64)gCPU.vr[vrB].sw[i];
+
+               res += (sint64)gCPU.vr[vrA].sh[(i<<1)];
+               res += (sint64)gCPU.vr[vrA].sh[(i<<1)+1];
+
+               gCPU.vr[vrD].sw[i] = SATURATE_SW(res);
+       }
+}
+
+/*     vsum2sws        Vector Sum Across Partial (1/2) Signed Word Saturate
+ *     v.272
+ */
+void ppc_opc_vsum2sws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       res = (sint64)gCPU.vr[vrA].sw[0] + (sint64)gCPU.vr[vrA].sw[1];
+       res += (sint64)gCPU.vr[vrB].sw[VECT_ODD(0)];
+
+       gCPU.vr[vrD].w[VECT_ODD(0)] = SATURATE_SW(res);
+       gCPU.vr[vrD].w[VECT_EVEN(0)] = 0;
+
+       res = (sint64)gCPU.vr[vrA].sw[2] + (sint64)gCPU.vr[vrA].sw[3];
+       res += (sint64)gCPU.vr[vrB].sw[VECT_ODD(1)];
+
+       gCPU.vr[vrD].w[VECT_ODD(1)] = SATURATE_SW(res);
+       gCPU.vr[vrD].w[VECT_EVEN(1)] = 0;
+}
+
+/*     vsumsws         Vector Sum Across Signed Word Saturate
+ *     v.271
+ */
+void ppc_opc_vsumsws()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       res = (sint64)gCPU.vr[vrA].sw[0] + (sint64)gCPU.vr[vrA].sw[1];
+       res += (sint64)gCPU.vr[vrA].sw[2] + (sint64)gCPU.vr[vrA].sw[3];
+
+       res += (sint64)VECT_W(gCPU.vr[vrB], 3);
+
+       VECT_W(gCPU.vr[vrD], 3) = SATURATE_SW(res);
+       VECT_W(gCPU.vr[vrD], 2) = 0;
+       VECT_W(gCPU.vr[vrD], 1) = 0;
+       VECT_W(gCPU.vr[vrD], 0) = 0;
+}
+
+/*     vnmsubfp        Vector Negative Multiply-Subtract Floating Point
+ *     v.215
+ */
+void ppc_opc_vnmsubfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB, vrC;
+       double res;
+       PPC_OPC_TEMPL_A(gCPU.current_opc, vrD, vrA, vrB, vrC);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = (double)gCPU.vr[vrA].f[i] * (double)gCPU.vr[vrC].f[i];
+
+               res = (double)gCPU.vr[vrB].f[i] - res;
+
+               gCPU.vr[vrD].f[i] = (float)res;
+       }
+}
+
+/*     vavgub          Vector Average Unsigned Byte
+ *     v.152
+ */
+void ppc_opc_vavgub()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (uint16)gCPU.vr[vrA].b[i] +
+                       (uint16)gCPU.vr[vrB].b[i] + 1;
+
+               gCPU.vr[vrD].b[i] = (res >> 1);
+       }
+}
+
+/*     vavguh          Vector Average Unsigned Half Word
+ *     v.153
+ */
+void ppc_opc_vavguh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (uint32)gCPU.vr[vrA].h[i] +
+                       (uint32)gCPU.vr[vrB].h[i] + 1;
+
+               gCPU.vr[vrD].h[i] = (res >> 1);
+       }
+}
+
+/*     vavguw          Vector Average Unsigned Word
+ *     v.154
+ */
+void ppc_opc_vavguw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (uint64)gCPU.vr[vrA].w[i] +
+                       (uint64)gCPU.vr[vrB].w[i] + 1;
+
+               gCPU.vr[vrD].w[i] = (res >> 1);
+       }
+}
+
+/*     vavgsb          Vector Average Signed Byte
+ *     v.149
+ */
+void ppc_opc_vavgsb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = (sint16)gCPU.vr[vrA].sb[i] +
+                       (sint16)gCPU.vr[vrB].sb[i] + 1;
+
+               gCPU.vr[vrD].sb[i] = (res >> 1);
+       }
+}
+
+/*     vavgsh          Vector Average Signed Half Word
+ *     v.150
+ */
+void ppc_opc_vavgsh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = (sint32)gCPU.vr[vrA].sh[i] +
+                       (sint32)gCPU.vr[vrB].sh[i] + 1;
+
+               gCPU.vr[vrD].sh[i] = (res >> 1);
+       }
+}
+
+/*     vavgsw          Vector Average Signed Word
+ *     v.151
+ */
+void ppc_opc_vavgsw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint64 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = (sint64)gCPU.vr[vrA].sw[i] +
+                       (sint64)gCPU.vr[vrB].sw[i] + 1;
+
+               gCPU.vr[vrD].sw[i] = (res >> 1);
+       }
+}
+
+/*     vmaxub          Vector Maximum Unsigned Byte
+ *     v.182
+ */
+void ppc_opc_vmaxub()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].b[i];
+
+               if (res < gCPU.vr[vrB].b[i])
+                       res = gCPU.vr[vrB].b[i];
+
+               gCPU.vr[vrD].b[i] = res;
+       }
+}
+
+/*     vmaxuh          Vector Maximum Unsigned Half Word
+ *     v.183
+ */
+void ppc_opc_vmaxuh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].h[i];
+
+               if (res < gCPU.vr[vrB].h[i])
+                       res = gCPU.vr[vrB].h[i];
+
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vmaxuw          Vector Maximum Unsigned Word
+ *     v.184
+ */
+void ppc_opc_vmaxuw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i];
+
+               if (res < gCPU.vr[vrB].w[i])
+                       res = gCPU.vr[vrB].w[i];
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vmaxsb          Vector Maximum Signed Byte
+ *     v.179
+ */
+void ppc_opc_vmaxsb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].sb[i];
+
+               if (res < gCPU.vr[vrB].sb[i])
+                       res = gCPU.vr[vrB].sb[i];
+
+               gCPU.vr[vrD].sb[i] = res;
+       }
+}
+
+/*     vmaxsh          Vector Maximum Signed Half Word
+ *     v.180
+ */
+void ppc_opc_vmaxsh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].sh[i];
+
+               if (res < gCPU.vr[vrB].sh[i])
+                       res = gCPU.vr[vrB].sh[i];
+
+               gCPU.vr[vrD].sh[i] = res;
+       }
+}
+
+/*     vmaxsw          Vector Maximum Signed Word
+ *     v.181
+ */
+void ppc_opc_vmaxsw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].sw[i];
+
+               if (res < gCPU.vr[vrB].sw[i])
+                       res = gCPU.vr[vrB].sw[i];
+
+               gCPU.vr[vrD].sw[i] = res;
+       }
+}
+
+/*     vmaxfp          Vector Maximum Floating Point
+ *     v.178
+ */
+void ppc_opc_vmaxfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       float res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = gCPU.vr[vrA].f[i];
+
+               if (res < gCPU.vr[vrB].f[i])
+                       res = gCPU.vr[vrB].f[i];
+
+               gCPU.vr[vrD].f[i] = res;
+       }
+}
+
+/*     vminub          Vector Minimum Unsigned Byte
+ *     v.191
+ */
+void ppc_opc_vminub()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].b[i];
+
+               if (res > gCPU.vr[vrB].b[i])
+                       res = gCPU.vr[vrB].b[i];
+
+               gCPU.vr[vrD].b[i] = res;
+       }
+}
+
+/*     vminuh          Vector Minimum Unsigned Half Word
+ *     v.192
+ */
+void ppc_opc_vminuh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].h[i];
+
+               if (res > gCPU.vr[vrB].h[i])
+                       res = gCPU.vr[vrB].h[i];
+
+               gCPU.vr[vrD].h[i] = res;
+       }
+}
+
+/*     vminuw          Vector Minimum Unsigned Word
+ *     v.193
+ */
+void ppc_opc_vminuw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       uint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].w[i];
+
+               if (res > gCPU.vr[vrB].w[i])
+                       res = gCPU.vr[vrB].w[i];
+
+               gCPU.vr[vrD].w[i] = res;
+       }
+}
+
+/*     vminsb          Vector Minimum Signed Byte
+ *     v.188
+ */
+void ppc_opc_vminsb()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint8 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               res = gCPU.vr[vrA].sb[i];
+
+               if (res > gCPU.vr[vrB].sb[i])
+                       res = gCPU.vr[vrB].sb[i];
+
+               gCPU.vr[vrD].sb[i] = res;
+       }
+}
+
+/*     vminsh          Vector Minimum Signed Half Word
+ *     v.189
+ */
+void ppc_opc_vminsh()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint16 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               res = gCPU.vr[vrA].sh[i];
+
+               if (res > gCPU.vr[vrB].sh[i])
+                       res = gCPU.vr[vrB].sh[i];
+
+               gCPU.vr[vrD].sh[i] = res;
+       }
+}
+
+/*     vminsw          Vector Minimum Signed Word
+ *     v.190
+ */
+void ppc_opc_vminsw()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       sint32 res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               res = gCPU.vr[vrA].sw[i];
+
+               if (res > gCPU.vr[vrB].sw[i])
+                       res = gCPU.vr[vrB].sw[i];
+
+               gCPU.vr[vrD].sw[i] = res;
+       }
+}
+
+/*     vminfp          Vector Minimum Floating Point
+ *     v.187
+ */
+void ppc_opc_vminfp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       float res;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               res = gCPU.vr[vrA].f[i];
+
+               if (res > gCPU.vr[vrB].f[i])
+                       res = gCPU.vr[vrB].f[i];
+
+               gCPU.vr[vrD].f[i] = res;
+       }
+}
+
+/*     vrfin           Vector Round to Floating-Point Integer Nearest
+ *     v.231
+ */
+void ppc_opc_vrfin()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       /* Documentation doesn't dictate how this instruction should
+        *   round from a middle point.  With a test on a real G4, it was
+        *   found to be round to nearest, with bias to even if equidistant.
+        *
+        * This is covered by the function rint()
+        */
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = rintf(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vrfip           Vector Round to Floating-Point Integer toward Plus Infinity
+ *     v.232
+ */
+void ppc_opc_vrfip()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = ceilf(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vrfim           Vector Round to Floating-Point Integer toward Minus Infinity
+ *     v.230
+ */
+void ppc_opc_vrfim()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = floorf(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vrfiz   Vector Round to Floating-Point Integer toward Zero
+ *     v.233
+ */
+void ppc_opc_vrfiz()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = truncf(gCPU.vr[vrD].f[i]);
+       }
+}
+
+/*     vrefp           Vector Reciprocal Estimate Floating Point
+ *     v.228
+ */
+void ppc_opc_vrefp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       /* This emulation generates an exact value, instead of an estimate.
+        *   This is technically within specs, but some test-suites expect the
+        *   exact estimate value returned by G4s.  These anomolous failures
+        *   should be ignored.
+        */
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = 1 / gCPU.vr[vrB].f[i];
+       }
+}
+
+/*     vrsqrtefp       Vector Reciprocal Square Root Estimate Floating Point
+ *     v.237
+ */
+void ppc_opc_vrsqrtefp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       /* This emulation generates an exact value, instead of an estimate.
+        *   This is technically within specs, but some test-suites expect the
+        *   exact estimate value returned by G4s.  These anomolous failures
+        *   should be ignored.
+        */
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = 1 / sqrt(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vlogefp         Vector Log2 Estimate Floating Point
+ *     v.175
+ */
+void ppc_opc_vlogefp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       /* This emulation generates an exact value, instead of an estimate.
+        *   This is technically within specs, but some test-suites expect the
+        *   exact estimate value returned by G4s.  These anomolous failures
+        *   should be ignored.
+        */
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = log2(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vexptefp        Vector 2 Raised to the Exponent Estimate Floating Point
+ *     v.173
+ */
+void ppc_opc_vexptefp()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+       PPC_OPC_ASSERT(vrA==0);
+
+       /* This emulation generates an exact value, instead of an estimate.
+        *   This is technically within specs, but some test-suites expect the
+        *   exact estimate value returned by G4s.  These anomolous failures
+        *   should be ignored.
+        */
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = exp2(gCPU.vr[vrB].f[i]);
+       }
+}
+
+/*     vcfux           Vector Convert from Unsigned Fixed-Point Word
+ *     v.156
+ */
+void ppc_opc_vcfux()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = ((float)gCPU.vr[vrB].w[i]) / (1 << uimm);
+       }
+}
+
+/*     vcfsx           Vector Convert from Signed Fixed-Point Word
+ *     v.155
+ */
+void ppc_opc_vcfsx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               gCPU.vr[vrD].f[i] = ((float)gCPU.vr[vrB].sw[i]) / (1 << uimm);
+       }
+}
+
+/*     vctsxs          Vector Convert To Signed Fixed-Point Word Saturate
+ *     v.171
+ */
+void ppc_opc_vctsxs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 uimm;
+       float ftmp;
+       sint32 tmp;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               ftmp = gCPU.vr[vrB].f[i] * (float)(1 << uimm);
+               ftmp = truncf(ftmp);
+
+               tmp = (sint32)ftmp;
+
+               if (ftmp > 2147483647.0) {
+                       tmp = 2147483647;               // 0x7fffffff
+                       gCPU.vscr |= VSCR_SAT;
+               } else if (ftmp < -2147483648.0) {
+                       tmp = -2147483648LL;            // 0x80000000
+                       gCPU.vscr |= VSCR_SAT;
+               }
+
+               gCPU.vr[vrD].sw[i] = tmp;
+       }
+}
+
+/*     vctuxs          Vector Convert to Unsigned Fixed-Point Word Saturate
+ *     v.172
+ */
+void ppc_opc_vctuxs()
+{
+       VECTOR_DEBUG;
+       int vrD, vrB;
+       uint32 tmp, uimm;
+       float ftmp;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, uimm, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               ftmp = gCPU.vr[vrB].f[i] * (float)(1 << uimm);
+               ftmp = truncf(ftmp);
+
+               tmp = (uint32)ftmp;
+
+               if (ftmp > 4294967295.0) {
+                       tmp = 0xffffffff;
+                       gCPU.vscr |= VSCR_SAT;
+               } else if (ftmp < 0) {
+                       tmp = 0;
+                       gCPU.vscr |= VSCR_SAT;
+               }
+
+               gCPU.vr[vrD].w[i] = tmp;
+       }
+}
+
+/*     vand            Vector Logical AND
+ *     v.147
+ */
+void ppc_opc_vand()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       gCPU.vr[vrD].d[0] = gCPU.vr[vrA].d[0] & gCPU.vr[vrB].d[0];
+       gCPU.vr[vrD].d[1] = gCPU.vr[vrA].d[1] & gCPU.vr[vrB].d[1];
+}
+
+/*     vandc           Vector Logical AND with Complement
+ *     v.148
+ */
+void ppc_opc_vandc()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       gCPU.vr[vrD].d[0] = gCPU.vr[vrA].d[0] & ~gCPU.vr[vrB].d[0];
+       gCPU.vr[vrD].d[1] = gCPU.vr[vrA].d[1] & ~gCPU.vr[vrB].d[1];
+}
+
+/*     vor             Vector Logical OR
+ *     v.217
+ */
+void ppc_opc_vor()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       gCPU.vr[vrD].d[0] = gCPU.vr[vrA].d[0] | gCPU.vr[vrB].d[0];
+       gCPU.vr[vrD].d[1] = gCPU.vr[vrA].d[1] | gCPU.vr[vrB].d[1];
+}
+
+/*     vnor            Vector Logical NOR
+ *     v.216
+ */
+void ppc_opc_vnor()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       gCPU.vr[vrD].d[0] = ~(gCPU.vr[vrA].d[0] | gCPU.vr[vrB].d[0]);
+       gCPU.vr[vrD].d[1] = ~(gCPU.vr[vrA].d[1] | gCPU.vr[vrB].d[1]);
+}
+
+/*     vxor            Vector Logical XOR
+ *     v.282
+ */
+void ppc_opc_vxor()
+{
+       VECTOR_DEBUG_COMMON;
+       int vrD, vrA, vrB;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       gCPU.vr[vrD].d[0] = gCPU.vr[vrA].d[0] ^ gCPU.vr[vrB].d[0];
+       gCPU.vr[vrD].d[1] = gCPU.vr[vrA].d[1] ^ gCPU.vr[vrB].d[1];
+}
+
+#define CR_CR6         (0x00f0)
+#define CR_CR6_EQ      (1<<7)
+#define CR_CR6_NE_SOME (1<<6)
+#define CR_CR6_NE      (1<<5)
+#define CR_CR6_EQ_SOME (1<<4)
+
+/*     vcmpequbx       Vector Compare Equal-to Unsigned Byte
+ *     v.160
+ */
+void ppc_opc_vcmpequbx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               if (gCPU.vr[vrA].b[i] == gCPU.vr[vrB].b[i]) {
+                       gCPU.vr[vrD].b[i] = 0xff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].b[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpequhx       Vector Compare Equal-to Unsigned Half Word
+ *     v.161
+ */
+void ppc_opc_vcmpequhx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               if (gCPU.vr[vrA].h[i] == gCPU.vr[vrB].h[i]) {
+                       gCPU.vr[vrD].h[i] = 0xffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].h[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpequwx       Vector Compare Equal-to Unsigned Word
+ *     v.162
+ */
+void ppc_opc_vcmpequwx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               if (gCPU.vr[vrA].w[i] == gCPU.vr[vrB].w[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpeqfpx       Vector Compare Equal-to-Floating Point
+ *     v.159
+ */
+void ppc_opc_vcmpeqfpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               if (gCPU.vr[vrA].f[i] == gCPU.vr[vrB].f[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtubx       Vector Compare Greater-Than Unsigned Byte
+ *     v.168
+ */
+void ppc_opc_vcmpgtubx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               if (gCPU.vr[vrA].b[i] > gCPU.vr[vrB].b[i]) {
+                       gCPU.vr[vrD].b[i] = 0xff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].b[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtsbx       Vector Compare Greater-Than Signed Byte
+ *     v.165
+ */
+void ppc_opc_vcmpgtsbx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<16; i++) {
+               if (gCPU.vr[vrA].sb[i] > gCPU.vr[vrB].sb[i]) {
+                       gCPU.vr[vrD].b[i] = 0xff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].b[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtuhx       Vector Compare Greater-Than Unsigned Half Word
+ *     v.169
+ */
+void ppc_opc_vcmpgtuhx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               if (gCPU.vr[vrA].h[i] > gCPU.vr[vrB].h[i]) {
+                       gCPU.vr[vrD].h[i] = 0xffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].h[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtshx       Vector Compare Greater-Than Signed Half Word
+ *     v.166
+ */
+void ppc_opc_vcmpgtshx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<8; i++) {
+               if (gCPU.vr[vrA].sh[i] > gCPU.vr[vrB].sh[i]) {
+                       gCPU.vr[vrD].h[i] = 0xffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].h[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtuwx       Vector Compare Greater-Than Unsigned Word
+ *     v.170
+ */
+void ppc_opc_vcmpgtuwx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               if (gCPU.vr[vrA].w[i] > gCPU.vr[vrB].w[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtswx       Vector Compare Greater-Than Signed Word
+ *     v.167
+ */
+void ppc_opc_vcmpgtswx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) {
+               if (gCPU.vr[vrA].sw[i] > gCPU.vr[vrB].sw[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgtfpx       Vector Compare Greater-Than Floating-Point
+ *     v.164
+ */
+void ppc_opc_vcmpgtfpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               if (gCPU.vr[vrA].f[i] > gCPU.vr[vrB].f[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpgefpx       Vector Compare Greater-Than-or-Equal-to Floating Point
+ *     v.163
+ */
+void ppc_opc_vcmpgefpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int tf=CR_CR6_EQ | CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               if (gCPU.vr[vrA].f[i] >= gCPU.vr[vrB].f[i]) {
+                       gCPU.vr[vrD].w[i] = 0xffffffff;
+                       tf &= ~CR_CR6_NE;
+                       tf |= CR_CR6_EQ_SOME;
+               } else {
+                       gCPU.vr[vrD].w[i] = 0;
+                       tf &= ~CR_CR6_EQ;
+                       tf |= CR_CR6_NE_SOME;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= tf;
+       }
+}
+
+/*     vcmpbfpx        Vector Compare Bounds Floating Point
+ *     v.157
+ */
+void ppc_opc_vcmpbfpx()
+{
+       VECTOR_DEBUG;
+       int vrD, vrA, vrB;
+       int le, ge;
+       int ib=CR_CR6_NE;
+       PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, vrA, vrB);
+
+       for (int i=0; i<4; i++) { //FIXME: This might not comply with Java FP
+               le = (gCPU.vr[vrA].f[i] <= gCPU.vr[vrB].f[i]) ? 0 : 0x80000000;
+               ge = (gCPU.vr[vrA].f[i] >= -gCPU.vr[vrB].f[i]) ? 0 : 0x40000000;
+
+               gCPU.vr[vrD].w[i] = le | ge;
+               if (le | ge) {
+                       ib = 0;
+               }
+       }
+
+       if (PPC_OPC_VRc & gCPU.current_opc) {
+               gCPU.cr &= ~CR_CR6;
+               gCPU.cr |= ib;
+       }
+}
diff --git a/ppc/pearpc/cpu/cpu_generic/ppc_vec.h b/ppc/pearpc/cpu/cpu_generic/ppc_vec.h
new file mode 100644 (file)
index 0000000..9c9a08b
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *     PearPC
+ *     ppc_vec.h
+ *
+ *     Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef __PPC_VEC_H__
+#define __PPC_VEC_H__
+
+#define PPC_OPC_VRc    (1<<10)
+
+/* Rather than write each function to be endianless, we're writing these
+ *   defines to do an endianless access to elements of the vector.
+ *
+ * These are for ADDRESSED vector elements.  Usually, most vector operations
+ *   can be performed in either direction without care, so most of the
+ *   for-loops should not use these, as it will introduce unneeded code
+ *   for little-endian systems.
+ */
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+
+#define VECT_B(reg, index)     ((reg).b[15 - (index)])
+#define VECT_SB(reg, index)    ((reg).sb[15 - (index)])
+#define VECT_H(reg, index)     ((reg).h[7 - (index)])
+#define VECT_SH(reg, index)    ((reg).sh[7 - (index)])
+#define VECT_W(reg, index)     ((reg).w[3 - (index)])
+#define VECT_SW(reg, index)    ((reg).sw[3 - (index)])
+#define VECT_D(reg, index)     ((reg).d[1 - (index)])
+#define VECT_SD(reg, index)    ((reg).sd[1 - (index)])
+
+#define VECT_EVEN(index)       (((index) << 1) + 1)
+#define VECT_ODD(index)                (((index) << 1) + 0)
+
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+
+#define VECT_B(reg, index)     ((reg).b[(index)])
+#define VECT_SB(reg, index)    ((reg).sb[(index)])
+#define VECT_H(reg, index)     ((reg).h[(index)])
+#define VECT_SH(reg, index)    ((reg).sh[(index)])
+#define VECT_W(reg, index)     ((reg).w[(index)])
+#define VECT_SW(reg, index)    ((reg).sw[(index)])
+#define VECT_D(reg, index)     ((reg).d[(index)])
+#define VECT_SD(reg, index)    ((reg).sd[(index)])
+
+#define VECT_EVEN(index)       (((index) << 1) + 0)
+#define VECT_ODD(index)                (((index) << 1) + 1)
+
+#else
+#error Endianess not supported!
+#endif
+
+//#define VECTOR_DEBUG fprintf(stderr, "[PPC/VEC] %s\n", __FUNCTION__)
+#define VECTOR_DEBUG
+
+//#define VECTOR_DEBUG_COMMON  fprintf(stderr, "[PPC/VEC] %s\n", __FUNCTION__)
+#define VECTOR_DEBUG_COMMON
+
+/* Undefine this to turn of the MSR_VEC check for vector instructions. */
+//#define __VEC_EXC_OFF__
+
+#include "system/types.h"
+
+#include "tools/snprintf.h"
+
+void ppc_opc_vperm();
+void ppc_opc_vsel();
+void ppc_opc_vsrb();
+void ppc_opc_vsrh();
+void ppc_opc_vsrw();
+void ppc_opc_vsrab();
+void ppc_opc_vsrah();
+void ppc_opc_vsraw();
+void ppc_opc_vsr();
+void ppc_opc_vsro();
+void ppc_opc_vslb();
+void ppc_opc_vslh();
+void ppc_opc_vslw();
+void ppc_opc_vsl();
+void ppc_opc_vslo();
+void ppc_opc_vsldoi();
+void ppc_opc_vrlb();
+void ppc_opc_vrlh();
+void ppc_opc_vrlw();
+void ppc_opc_vmrghb();
+void ppc_opc_vmrghh();
+void ppc_opc_vmrghw();
+void ppc_opc_vmrglb();
+void ppc_opc_vmrglh();
+void ppc_opc_vmrglw();
+void ppc_opc_vspltb();
+void ppc_opc_vsplth();
+void ppc_opc_vspltw();
+void ppc_opc_vspltisb();
+void ppc_opc_vspltish();
+void ppc_opc_vspltisw();
+void ppc_opc_mfvscr();
+void ppc_opc_mtvscr();
+void ppc_opc_vpkuhum();
+void ppc_opc_vpkuwum();
+void ppc_opc_vpkpx();
+void ppc_opc_vpkuhus();
+void ppc_opc_vpkshss();
+void ppc_opc_vpkuwus();
+void ppc_opc_vpkswss();
+void ppc_opc_vpkuhus();
+void ppc_opc_vpkshus();
+void ppc_opc_vpkuwus();
+void ppc_opc_vpkswus();
+void ppc_opc_vupkhsb();
+void ppc_opc_vupkhpx();
+void ppc_opc_vupkhsh();
+void ppc_opc_vupklsb();
+void ppc_opc_vupklpx();
+void ppc_opc_vupklsh();
+void ppc_opc_vaddubm();
+void ppc_opc_vadduhm();
+void ppc_opc_vadduwm();
+void ppc_opc_vaddfp();
+void ppc_opc_vaddcuw();
+void ppc_opc_vaddubs();
+void ppc_opc_vaddsbs();
+void ppc_opc_vadduhs();
+void ppc_opc_vaddshs();
+void ppc_opc_vadduws();
+void ppc_opc_vaddsws();
+void ppc_opc_vsububm();
+void ppc_opc_vsubuhm();
+void ppc_opc_vsubuwm();
+void ppc_opc_vsubfp();
+void ppc_opc_vsubcuw();
+void ppc_opc_vsububs();
+void ppc_opc_vsubsbs();
+void ppc_opc_vsubuhs();
+void ppc_opc_vsubshs();
+void ppc_opc_vsubuws();
+void ppc_opc_vsubsws();
+void ppc_opc_vmuleub();
+void ppc_opc_vmulesb();
+void ppc_opc_vmuleuh();
+void ppc_opc_vmulesh();
+void ppc_opc_vmuloub();
+void ppc_opc_vmulosb();
+void ppc_opc_vmulouh();
+void ppc_opc_vmulosh();
+void ppc_opc_vmaddfp();
+void ppc_opc_vmhaddshs();
+void ppc_opc_vmladduhm();
+void ppc_opc_vmhraddshs();
+void ppc_opc_vmsumubm();
+void ppc_opc_vmsumuhm();
+void ppc_opc_vmsummbm();
+void ppc_opc_vmsumshm();
+void ppc_opc_vmsumuhs();
+void ppc_opc_vmsumshs();
+void ppc_opc_vsum4ubs();
+void ppc_opc_vsum4sbs();
+void ppc_opc_vsum4shs();
+void ppc_opc_vsum2sws();
+void ppc_opc_vsumsws();
+void ppc_opc_vnmsubfp();
+void ppc_opc_vavgub();
+void ppc_opc_vavgsb();
+void ppc_opc_vavguh();
+void ppc_opc_vavgsh();
+void ppc_opc_vavguw();
+void ppc_opc_vavgsw();
+void ppc_opc_vmaxub();
+void ppc_opc_vmaxsb();
+void ppc_opc_vmaxuh();
+void ppc_opc_vmaxsh();
+void ppc_opc_vmaxuw();
+void ppc_opc_vmaxsw();
+void ppc_opc_vmaxfp();
+void ppc_opc_vminub();
+void ppc_opc_vminsb();
+void ppc_opc_vminuh();
+void ppc_opc_vminsh();
+void ppc_opc_vminuw();
+void ppc_opc_vminsw();
+void ppc_opc_vminfp();
+void ppc_opc_vrfin();
+void ppc_opc_vrfip();
+void ppc_opc_vrfim();
+void ppc_opc_vrfiz();
+void ppc_opc_vrefp();
+void ppc_opc_vrsqrtefp();
+void ppc_opc_vlogefp();
+void ppc_opc_vexptefp();
+void ppc_opc_vcfux();
+void ppc_opc_vcfsx();
+void ppc_opc_vctsxs();
+void ppc_opc_vctuxs();
+void ppc_opc_vand();
+void ppc_opc_vandc();
+void ppc_opc_vor();
+void ppc_opc_vnor();
+void ppc_opc_vxor();
+void ppc_opc_vcmpequbx();
+void ppc_opc_vcmpequhx();
+void ppc_opc_vcmpequwx();
+void ppc_opc_vcmpeqfpx();
+void ppc_opc_vcmpgtubx();
+void ppc_opc_vcmpgtsbx();
+void ppc_opc_vcmpgtuhx();
+void ppc_opc_vcmpgtshx();
+void ppc_opc_vcmpgtuwx();
+void ppc_opc_vcmpgtswx();
+void ppc_opc_vcmpgtfpx();
+void ppc_opc_vcmpgefpx();
+void ppc_opc_vcmpbfpx();
+
+#endif
diff --git a/ppc/pearpc/cpu/debug.h b/ppc/pearpc/cpu/debug.h
new file mode 100644 (file)
index 0000000..11d8ca8
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *     PearPC
+ *     debug.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include "system/types.h"
+
+/*
+ *     Debugger Interface
+ */
+void ppc_set_singlestep_v(bool v, const char *file, int line, const char *infoformat, ...);
+void ppc_set_singlestep_nonverbose(bool v);
+
+#define SINGLESTEP(info)       ppc_set_singlestep_v(true, __FILE__, __LINE__, info)
+
+#endif
diff --git a/ppc/pearpc/cpu/mem.h b/ppc/pearpc/cpu/mem.h
new file mode 100644 (file)
index 0000000..36f05c5
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *     PearPC
+ *     mem.h
+ *
+ *     Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MEM_H__
+#define __MEM_H__
+
+#include "system/types.h"
+
+bool   ppc_init_physical_memory(uint size);
+
+uint32  ppc_get_memory_size();
+
+bool   ppc_dma_write(uint32 dest, const void *src, uint32 size);
+bool   ppc_dma_read(void *dest, uint32 src, uint32 size);
+bool   ppc_dma_set(uint32 dest, int c, uint32 size);
+
+void   ppc_cpu_map_framebuffer(uint32 pa, uint32 ea);
+
+/*
+ *     These functions will be removed once we switch to openbios.
+ */
+
+bool   DEPRECATED ppc_prom_set_sdr1(uint32 newval, bool quiesce);
+bool   DEPRECATED ppc_prom_effective_to_physical(uint32 &result, uint32 ea);
+bool   DEPRECATED ppc_prom_page_create(uint32 ea, uint32 pa);
+
+#endif
diff --git a/ppc/pearpc/info.h b/ppc/pearpc/info.h
new file mode 100644 (file)
index 0000000..b438571
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *     PearPC
+ *     info.h
+ *
+ *     Copyright (C) 2003-2005 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __INFO_H__
+#define __INFO_H__
+
+#define APPNAME "PearPC"
+#define APPVERSION "0.5"
+// this will show up in the win32 version resource:
+#define APPVERSION_IN_NUMBERS 0,0,5,0
+
+#define EMULATOR_MODEL "PowerPC ("APPNAME" "APPVERSION")"
+#define COPYRIGHT "(c) 2003-2011 Sebastian Biallas <sb@biallas.net>"
+
+//#define PPC_CPU_ENABLE_SINGLESTEP
+
+#endif
+
diff --git a/ppc/pearpc/io/io.h b/ppc/pearpc/io/io.h
new file mode 100644 (file)
index 0000000..202336e
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ *     PearPC
+ *     io.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __IO_IO_H__
+#define __IO_IO_H__
+
+#include "system/types.h"
+#include <stdlib.h>
+#include <string.h>
+#include "cpu/cpu.h"
+#include "cpu/debug.h"
+#include "cpu/mem.h"
+#include "io.h"
+//#include "io/graphic/gcard.h"
+//#include "io/pic/pic.h"
+//#include "io/pci/pci.h"
+//#include "io/cuda/cuda.h"
+//#include "io/nvram/nvram.h"
+#include "debug/tracers.h"
+
+#define IO_MEM_ACCESS_OK       0
+#define IO_MEM_ACCESS_EXC      1
+#define IO_MEM_ACCESS_FATAL    2
+
+extern bool uae_ppc_io_mem_write(uint32, uint32, int);
+extern bool uae_ppc_io_mem_read(uint32, uint32&, int);
+extern bool uae_ppc_io_mem_write64(uint32, uint64);
+extern bool uae_ppc_io_mem_read64(uint32, uint64&);
+
+static inline int io_mem_write(uint32 addr, uint32 data, int size)
+{
+       if (uae_ppc_io_mem_write(addr, data, size))
+               return IO_MEM_ACCESS_OK;
+#if 0
+       if (addr >= IO_GCARD_FRAMEBUFFER_PA_START && addr < IO_GCARD_FRAMEBUFFER_PA_END) {
+               gcard_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_PCI_PA_START && addr < IO_PCI_PA_END) {
+               pci_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_PIC_PA_START && addr < IO_PIC_PA_END) {
+               pic_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_CUDA_PA_START && addr < IO_CUDA_PA_END) {
+               cuda_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_NVRAM_PA_START && addr < IO_NVRAM_PA_END) {
+               nvram_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;                
+       }
+       // PCI and ISA must be checked at last
+       if (addr >= IO_PCI_DEVICE_PA_START && addr < IO_PCI_DEVICE_PA_END) {
+               pci_write_device(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_ISA_PA_START && addr < IO_ISA_PA_END) {
+               /*
+                * should raise exception here...
+                * but linux dont like this
+                */
+               isa_write(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+               /*if (isa_write(addr, data, size)) {
+                       return IO_MEM_ACCESS_OK;
+               } else {
+                       ppc_exception(PPC_EXC_MACHINE_CHECK);
+                       return IO_MEM_ACCESS_EXC;
+               }*/
+       }
+#endif
+       IO_CORE_WARN("no one is responsible for address %08x (write: %08x from %08x)\n", addr, data, ppc_cpu_get_pc(0));
+       SINGLESTEP("");
+       ppc_machine_check_exception();  
+       return IO_MEM_ACCESS_EXC;
+}
+
+static inline int io_mem_read(uint32 addr, uint32 &data, int size)
+{
+       if (uae_ppc_io_mem_read(addr, data, size))
+               return IO_MEM_ACCESS_OK;
+
+#if 0
+       if (addr >= IO_GCARD_FRAMEBUFFER_PA_START && addr < IO_GCARD_FRAMEBUFFER_PA_END) {
+               gcard_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_PCI_PA_START && addr < IO_PCI_PA_END) {
+               pci_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_PIC_PA_START && addr < IO_PIC_PA_END) {
+               pic_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_CUDA_PA_START && addr < IO_CUDA_PA_END) {
+               cuda_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_NVRAM_PA_START && addr < IO_NVRAM_PA_END) {
+               nvram_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;                
+       }
+       if (addr == 0xff000004) {
+               // wtf?
+               data = 1;
+               return IO_MEM_ACCESS_OK;
+       }
+       // PCI and ISA must be checked at last
+       if (addr >= IO_PCI_DEVICE_PA_START && addr < IO_PCI_DEVICE_PA_END) {
+               pci_read_device(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+       }
+       if (addr >= IO_ISA_PA_START && addr < IO_ISA_PA_END) {          
+               /*
+                * should raise exception here...
+                * but linux dont like this
+                */
+               isa_read(addr, data, size);
+               return IO_MEM_ACCESS_OK;
+               /*if (isa_read(addr, data, size)) {
+                       return IO_MEM_ACCESS_OK;
+               } else {
+                       ppc_exception(PPC_EXC_MACHINE_CHECK);
+                       return IO_MEM_ACCESS_EXC;
+               }*/
+       }
+#endif
+       IO_CORE_WARN("no one is responsible for address %08x (read from %08x)\n", addr, ppc_cpu_get_pc(0));
+       SINGLESTEP("");
+       ppc_machine_check_exception();
+       return IO_MEM_ACCESS_EXC;
+}
+
+static inline int io_mem_write64(uint32 addr, uint64 data)
+{
+       if (uae_ppc_io_mem_write64(addr, data))
+               return IO_MEM_ACCESS_OK;
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_write64(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (write64: %016q from %08x)\n", addr, &data, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+static inline int io_mem_read64(uint32 addr, uint64 &data)
+{
+       if (uae_ppc_io_mem_read64(addr, data))
+               return IO_MEM_ACCESS_OK;
+
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_read64(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (read64 from %08x)\n", addr, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+static inline int io_mem_write128(uint32 addr, uint128 *data)
+{
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_write128(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (write128: %016q%016q from %08x)\n", addr, data->h, data->l, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+static inline int io_mem_write128_native(uint32 addr, uint128 *data)
+{
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_write128_native(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (write128: %016q%016q from %08x)\n", addr, data->h, data->l, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+static inline int io_mem_read128(uint32 addr, uint128 *data)
+{
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_read128(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (read128 from %08x)\n", addr, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+static inline int io_mem_read128_native(uint32 addr, uint128 *data)
+{
+#if 0
+       if ((addr >= IO_GCARD_FRAMEBUFFER_PA_START) && (addr < (IO_GCARD_FRAMEBUFFER_PA_END))) {
+               gcard_read128_native(addr, data);
+               return IO_MEM_ACCESS_OK;
+       }
+#endif
+       IO_CORE_ERR("no one is responsible for address %08x (read128 from %08x)\n", addr, ppc_cpu_get_pc(0));
+       return IO_MEM_ACCESS_FATAL;
+}
+
+void io_init();
+void io_done();
+void io_init_config();
+
+#endif
diff --git a/ppc/pearpc/system/arch/generic/sysendian.h b/ppc/pearpc/system/arch/generic/sysendian.h
new file mode 100644 (file)
index 0000000..7ede7a6
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *     PearPC
+ *     sysendian.h
+ *
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+#define __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+
+#include "system/types.h"
+#include "config.h"
+
+static inline FUNCTION_CONST uint32 ppc_bswap_word(uint32 data)
+{
+       return (data>>24)|((data>>8)&0xff00)|((data<<8)&0xff0000)|(data<<24);
+}
+
+static inline FUNCTION_CONST uint64 ppc_bswap_dword(uint64 data)
+{
+       return (((uint64)ppc_bswap_word(data)) << 32) | (uint64)ppc_bswap_word(data >> 32);
+}
+
+static inline FUNCTION_CONST uint16 ppc_bswap_half(uint16 data)
+{
+       return (data<<8)|(data>>8);
+}
+
+#if HOST_ENDIANESS == HOST_ENDIANESS_LE
+
+/*
+ *             Little-endian machine
+ */
+
+#      define ppc_dword_from_BE(data)  (ppc_bswap_dword(data))
+#      define ppc_word_from_BE(data)   (ppc_bswap_word(data))
+#      define ppc_half_from_BE(data)   (ppc_bswap_half(data))
+
+#      define ppc_dword_from_LE(data)  ((uint64)(data))
+#      define ppc_word_from_LE(data)   ((uint32)(data))
+#      define ppc_half_from_LE(data)   ((uint16)(data))
+
+#      define ppc_dword_to_LE(data)    ppc_dword_from_LE(data)
+#      define ppc_word_to_LE(data)     ppc_word_from_LE(data)
+#      define ppc_half_to_LE(data)     ppc_half_from_LE(data)
+
+#      define ppc_dword_to_BE(data)    ppc_dword_from_BE(data)
+#      define ppc_word_to_BE(data)     ppc_word_from_BE(data)
+#      define ppc_half_to_BE(data)     ppc_half_from_BE(data)
+
+#elif HOST_ENDIANESS == HOST_ENDIANESS_BE
+
+/*
+ *             Big-endian machine
+ */
+#      define ppc_dword_from_BE(data)  ((uint64)(data))
+#      define ppc_word_from_BE(data)   ((uint32)(data))
+#      define ppc_half_from_BE(data)   ((uint16)(data))
+
+#      define ppc_dword_from_LE(data)  (ppc_bswap_dword(data))
+#      define ppc_word_from_LE(data)   (ppc_bswap_word(data))
+#      define ppc_half_from_LE(data)   (ppc_bswap_half(data))
+
+#      define ppc_dword_to_LE(data)    ppc_dword_from_LE(data)
+#      define ppc_word_to_LE(data)     ppc_word_from_LE(data)
+#      define ppc_half_to_LE(data)     ppc_half_from_LE(data)
+
+#      define ppc_dword_to_BE(data)    ppc_dword_from_BE(data)
+#      define ppc_word_to_BE(data)     ppc_word_from_BE(data)
+#      define ppc_half_to_BE(data)     ppc_half_from_BE(data)
+
+#else
+
+/*
+ *             Weird-endian machine
+ *     HOST_ENDIANESS is neither little- nor big-endian?
+ */
+#      error "What kind of a weird machine do you have? It's neither little- nor big-endian??? This is unsupported."
+
+#endif
+
+#endif
diff --git a/ppc/pearpc/system/arch/generic/sysfeatures.h b/ppc/pearpc/system/arch/generic/sysfeatures.h
new file mode 100644 (file)
index 0000000..0d96010
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *     PearPC
+ *     features.h - arch/generic variant
+ *
+ *     Copyright (C) 2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+#define __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+
+// PPC_FEATURE_PROVIDED_BY_ARCH
+#if !defined(PPC_VIDEO_CONVERT_ACCEL_FEATURE) || (PPC_VIDEO_CONVERT_ACCEL_FEATURE < PPC_FEATURE_PROVIDED_BY_ARCH)
+#      undef PPC_VIDEO_CONVERT_ACCEL_FEATURE
+#      define PPC_VIDEO_CONVERT_ACCEL_FEATURE PPC_FEATURE_PROVIDED_BY_ARCH
+#endif
+
+#endif
diff --git a/ppc/pearpc/system/arch/sysendian.h b/ppc/pearpc/system/arch/sysendian.h
new file mode 100644 (file)
index 0000000..2309adf
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *     PearPC
+ *     sysendian.h
+ *
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SYSENDIAN_H__
+#define __SYSTEM_ARCH_SYSENDIAN_H__
+
+#include "config.h"
+
+#include SYSTEM_ARCH_SPECIFIC_ENDIAN_DIR
+
+#endif
diff --git a/ppc/pearpc/system/arch/sysfeatures.h b/ppc/pearpc/system/arch/sysfeatures.h
new file mode 100644 (file)
index 0000000..7138daa
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *     PearPC
+ *     sysfeatures.h
+ *
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SYSFEATURES_H__
+#define __SYSTEM_ARCH_SYSFEATURES_H__
+
+#include "config.h"
+
+#include SYSTEM_ARCH_SPECIFIC_FEATURES_DIR
+
+#endif
diff --git a/ppc/pearpc/system/arch/x86/sysendian.h b/ppc/pearpc/system/arch/x86/sysendian.h
new file mode 100644 (file)
index 0000000..d19e6a6
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *     PearPC
+ *     sysendian.h
+ *
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+#define __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+
+#include "system/types.h"
+
+static inline FUNCTION_CONST uint32 ppc_bswap_word(uint32 data)
+{
+//     asm (
+//             "bswap %0": "=r" (data) : "0" (data)
+//     );
+       data = (data >> 24) | ((data >> 8) & 0x0000ff00) | ((data << 8) & 0x00ff0000) | (data << 24);
+       return data;
+}
+
+static inline FUNCTION_CONST uint16 ppc_bswap_half(uint16 data) 
+{
+//     asm (
+//             "xchgb %b0,%h0": "=q" (data): "0" (data)
+//     );
+       data = (data >> 8) | (data << 8);
+       return data;
+}
+
+static inline FUNCTION_CONST uint64 ppc_bswap_dword(uint64 data)
+{
+       return (((uint64)ppc_bswap_word(data)) << 32) | (uint64)ppc_bswap_word(data >> 32);
+}
+
+#      define ppc_dword_from_BE(data)  (ppc_bswap_dword(data))
+#      define ppc_word_from_BE(data)   (ppc_bswap_word(data))
+#      define ppc_half_from_BE(data)   (ppc_bswap_half(data))
+
+#      define ppc_dword_from_LE(data)  ((uint64)(data))
+#      define ppc_word_from_LE(data)   ((uint32)(data))
+#      define ppc_half_from_LE(data)   ((uint16)(data))
+
+#      define ppc_dword_to_LE(data)    ppc_dword_from_LE(data)
+#      define ppc_word_to_LE(data)     ppc_word_from_LE(data)
+#      define ppc_half_to_LE(data)     ppc_half_from_LE(data)
+
+#      define ppc_dword_to_BE(data)    ppc_dword_from_BE(data)
+#      define ppc_word_to_BE(data)     ppc_word_from_BE(data)
+#      define ppc_half_to_BE(data)     ppc_half_from_BE(data)
+
+#endif
diff --git a/ppc/pearpc/system/arch/x86/sysfeatures.h b/ppc/pearpc/system/arch/x86/sysfeatures.h
new file mode 100644 (file)
index 0000000..5830769
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *     PearPC
+ *     features.h - arch/x86 variant
+ *
+ *     Copyright (C) 2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+#define __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+
+// PPC_FEATURE_PROVIDED_BY_ARCH
+#if !defined(PPC_VIDEO_CONVERT_ACCEL_FEATURE) || (PPC_VIDEO_CONVERT_ACCEL_FEATURE < PPC_FEATURE_PROVIDED_BY_ARCH)
+#      undef PPC_VIDEO_CONVERT_ACCEL_FEATURE
+#      define PPC_VIDEO_CONVERT_ACCEL_FEATURE PPC_FEATURE_PROVIDED_BY_ARCH
+#endif
+
+#endif
diff --git a/ppc/pearpc/system/arch/x86/sysvaccel.cc b/ppc/pearpc/system/arch/x86/sysvaccel.cc
new file mode 100644 (file)
index 0000000..c1ee003
--- /dev/null
@@ -0,0 +1,124 @@
+/* 
+ *     HT Editor
+ *     sysvaccel.cc
+ *
+ *     Copyright (C) 2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "system/sysvaccel.h"
+
+#include "tools/snprintf.h"
+
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_2le555(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_2le565(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_4le888(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_2le555(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_2le565(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_4le888(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_convert_4be888_to_4le888(uint32 pixel, byte *input, byte *output);
+
+static inline void convertBaseColor(uint &b, uint fromBits, uint toBits)
+{
+       if (toBits > fromBits) {
+               b <<= toBits - fromBits;
+       } else {
+               b >>= fromBits - toBits;
+       }
+}
+
+static inline void genericConvertDisplay(
+       const DisplayCharacteristics &aSrcChar,
+       const DisplayCharacteristics &aDestChar,
+       const void *aSrcBuf,
+       void *aDestBuf,
+       int firstLine,
+       int lastLine)
+{
+       byte *src = (byte*)aSrcBuf + aSrcChar.bytesPerPixel * aSrcChar.width * firstLine;
+       byte *dest = (byte*)aDestBuf + aDestChar.bytesPerPixel * aDestChar.width * firstLine;
+       for (int y=firstLine; y <= lastLine; y++) {
+               for (int x=0; x < aSrcChar.width; x++) {
+                       uint r, g, b;
+                       uint p;
+                       switch (aSrcChar.bytesPerPixel) {
+                       case 2:
+                               p = (src[0] << 8) | src[1];
+                               break;
+                       case 4:
+                               p = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+                               break;
+                       default:
+                               ht_printf("internal error in %s:%d\n", __FILE__, __LINE__);
+                               exit(1);
+                       break;
+                       }
+                       r = (p >> aSrcChar.redShift) & ((1<<aSrcChar.redSize)-1);
+                       g = (p >> aSrcChar.greenShift) & ((1<<aSrcChar.greenSize)-1);
+                       b = (p >> aSrcChar.blueShift) & ((1<<aSrcChar.blueSize)-1);
+                       convertBaseColor(r, aSrcChar.redSize, aDestChar.redSize);
+                       convertBaseColor(g, aSrcChar.greenSize, aDestChar.greenSize);
+                       convertBaseColor(b, aSrcChar.blueSize, aDestChar.blueSize);
+                       p = (r << aDestChar.redShift) | (g << aDestChar.greenShift)
+                               | (b << aDestChar.blueShift);
+                       switch (aDestChar.bytesPerPixel) {
+                       case 2:
+                               dest[0] = p; dest[1] = p>>8;
+                               break;
+                       case 3:
+                               dest[0] = p; dest[1] = p>>8; dest[2] = p>>16;
+                               break;
+                       case 4:
+                               *(uint32*)dest = p;
+                               break;
+                       default:
+                               ht_printf("internal error in %s:%d\n", __FILE__, __LINE__);
+                               exit(1);
+                       }
+                       dest += aDestChar.bytesPerPixel;
+                       src += aSrcChar.bytesPerPixel;
+               }
+               dest += aDestChar.scanLineLength - aDestChar.width*aDestChar.bytesPerPixel;
+               src += aSrcChar.scanLineLength - aSrcChar.width*aSrcChar.bytesPerPixel;
+       }
+}
+
+void sys_convert_display(
+       const DisplayCharacteristics &aSrcChar,
+       const DisplayCharacteristics &aDestChar,
+       const void *aSrcBuf,
+       void *aDestBuf,
+       int firstLine,
+       int lastLine)
+{
+       byte *src = (byte*)aSrcBuf + aSrcChar.bytesPerPixel * aSrcChar.width * firstLine;
+       byte *dest = (byte*)aDestBuf + aDestChar.bytesPerPixel * aDestChar.width * firstLine;
+       uint32 pixel = (lastLine-firstLine+1) * aSrcChar.width;
+       if (aSrcChar.bytesPerPixel == 2 && aDestChar.bytesPerPixel == 2) {
+               if (aDestChar.redSize == 5 && aDestChar.greenSize == 6 && aDestChar.blueSize == 5) {
+                       x86_mmx_convert_2be555_to_2le565(pixel, src, dest);
+               } else if (aDestChar.redSize == 5 && aDestChar.greenSize == 5 && aDestChar.blueSize == 5) {
+                       x86_mmx_convert_2be555_to_2le555(pixel, src, dest);
+               } else {
+                       genericConvertDisplay(aSrcChar, aDestChar, aSrcBuf, aDestBuf, firstLine, lastLine);
+               }
+       } else if (aSrcChar.bytesPerPixel == 2 && aDestChar.bytesPerPixel == 4) {
+               x86_mmx_convert_2be555_to_4le888(pixel, src, dest);
+       } else if (aSrcChar.bytesPerPixel == 4 && aDestChar.bytesPerPixel == 4) {
+               x86_convert_4be888_to_4le888(pixel, src, dest);
+       } else {
+               genericConvertDisplay(aSrcChar, aDestChar, aSrcBuf, aDestBuf, firstLine, lastLine);
+       }
+}
diff --git a/ppc/pearpc/system/arch/x86/vaccel.S b/ppc/pearpc/system/arch/x86/vaccel.S
new file mode 100644 (file)
index 0000000..22c6814
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ *     PearPC
+ *     vaccel.S
+ *
+ *     Copyright (C) 2004-2006 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PREFIX
+#define PREFIX
+#endif
+
+#define EXPORT(sym) EXPORT2(PREFIX, sym)
+#define EXPORT2(p, sym) EXPORT3(p, sym)
+#define EXPORT3(p, sym) .globl p##sym; p##sym
+
+#define EXTERN(sym) EXTERN2(PREFIX, sym)
+#define EXTERN2(p, sym) EXTERN3(p, sym)
+#define EXTERN3(p, sym) p##sym
+
+.intel_syntax
+
+.text
+
+.balign 16
+d1:    .long 0x00ff00ff
+       .long 0x00ff00ff
+       .long 0x00ff00ff
+       .long 0x00ff00ff
+d2:    .long 0xff00ff00
+       .long 0xff00ff00
+       .long 0xff00ff00
+       .long 0xff00ff00
+
+_2be555_mask_r:        .long   0x7c007c00
+               .long   0x7c007c00
+               .long   0x7c007c00
+               .long   0x7c007c00
+_2be555_mask_g:        .long   0x03e003e0
+               .long   0x03e003e0
+               .long   0x03e003e0
+               .long   0x03e003e0
+_2be555_mask_b:        .long   0x001f001f
+               .long   0x001f001f
+               .long   0x001f001f
+               .long   0x001f001f
+
+.balign 16
+#################################################################################
+##
+##     IN: eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_mmx_convert_2be555_to_2le555):
+       add             %eax, 7
+       shr             %eax, 3         # we can convert 8 pixels at a time
+       movq            %mm5, [d1]
+       movq            %mm6, [d2]
+       jz              2f
+1:
+       movq            %mm1, [%edx]
+       movq            %mm3, [%edx+8]
+
+       ## convert big to little endian
+       movq            %mm2, %mm1
+       movq            %mm4, %mm3
+       pand            %mm1, %mm5
+       pand            %mm2, %mm6
+       pand            %mm3, %mm5
+       pand            %mm4, %mm6
+       psllw           %mm1, 8
+       psrlw           %mm2, 8
+       psllw           %mm3, 8
+       psrlw           %mm4, 8
+       por             %mm1, %mm2
+       por             %mm3, %mm4
+
+       movq            [%ecx], %mm1
+       movq            [%ecx+8], %mm3
+       add             %edx, 16
+       add             %ecx, 16
+       dec             %eax
+       jnz             1b
+
+       emms
+2:
+       ret
+
+.balign 16
+#################################################################################
+##
+##     IN: %eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_mmx_convert_2be555_to_2le565):
+       add             %eax, 7
+       shr             %eax, 3         # we can convert 8 pixels at a time
+       movq            %mm0, [d1]
+       movq            %mm7, [d2]
+       jz              2f
+1:
+       movq            %mm1, [%edx]
+       movq            %mm3, [%edx+8]
+       ## convert big to little endian
+       movq            %mm2, %mm1
+       movq            %mm4, %mm3
+       pand            %mm1, %mm0
+       pand            %mm2, %mm7
+       pand            %mm3, %mm0
+       pand            %mm4, %mm7
+       psllw           %mm1, 8
+       psrlw           %mm2, 8
+       psllw           %mm3, 8
+       psrlw           %mm4, 8
+       por             %mm1, %mm2
+       por             %mm4, %mm3
+
+       movq            %mm2, %mm1
+       movq            %mm3, %mm1
+       movq            %mm5, %mm4
+       movq            %mm6, %mm4
+       pand            %mm1, [_2be555_mask_r]
+       pand            %mm2, [_2be555_mask_g]
+       pand            %mm3, [_2be555_mask_b]
+       pand            %mm4, [_2be555_mask_r]
+       pand            %mm5, [_2be555_mask_g]
+       pand            %mm6, [_2be555_mask_b]
+       psllw           %mm1, 1         # red
+       psllw           %mm2, 1         # green
+#      psllw           %mm3, 0         # blue
+       psllw           %mm4, 1         # red
+       psllw           %mm5, 1         # green
+#      psllw           %mm6, 0         # blue
+       por             %mm1, %mm2
+       por             %mm4, %mm5
+       por             %mm1, %mm3
+       por             %mm4, %mm6
+       movq            [%ecx], %mm1
+       movq            [%ecx+8], %mm4
+       add             %edx, 16
+       add             %ecx, 16
+       dec             %eax
+       jnz             1b
+
+       emms
+2:
+       ret
+
+.balign 16
+#################################################################################
+##
+##     IN: %eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_mmx_convert_2be555_to_4le888):
+       add             %eax, 3
+       shr             %eax, 2         # we can convert 4 pixels at a time
+       movq            %mm7, [d1]
+       jz              2f
+
+       pxor            %mm0, %mm0
+1:
+       movq            %mm1, [%edx]
+
+       ## convert big to little endian
+       movq            %mm3, %mm1
+       pand            %mm1, %mm7
+       pand            %mm3, [d2]
+       psllw           %mm1, 8
+       psrlw           %mm3, 8
+       por             %mm1, %mm3
+
+       movq            %mm2, %mm1
+       movq            %mm3, %mm1
+       pand            %mm1, [_2be555_mask_r]
+       pand            %mm2, [_2be555_mask_g]
+       pand            %mm3, [_2be555_mask_b]
+       movq            %mm4, %mm1
+       movq            %mm5, %mm2
+       movq            %mm6, %mm3
+       punpcklwd       %mm1, %mm0
+       punpcklwd       %mm2, %mm0
+       punpcklwd       %mm3, %mm0
+       punpckhwd       %mm4, %mm0
+       punpckhwd       %mm5, %mm0
+       punpckhwd       %mm6, %mm0
+       pslld           %mm1, 16-10+3   # red
+       pslld           %mm2, 8-5+3     # green
+       pslld           %mm3, 0+3       # blue
+       pslld           %mm4, 16-10+3   # red
+       pslld           %mm5, 8-5+3     # green
+       pslld           %mm6, 0+3       # blue
+       por             %mm1, %mm2
+       por             %mm1, %mm3
+       por             %mm4, %mm5
+       por             %mm4, %mm6
+       movq            [%ecx], %mm1
+       movq            [%ecx+8], %mm4
+       add             %edx, 8
+       add             %ecx, 16
+       dec             %eax
+       jnz             1b
+
+2:
+       emms
+       ret
+
+
+.balign 16
+#################################################################################
+##
+##     IN: %eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_convert_4be888_to_4le888):
+       add             %eax, 3
+       shr             %eax, 2         # we can convert 4 pixels at a time
+       jz              2f
+
+       push            %ebx
+       push            %ebp
+       push            %esi
+       push            %edi
+1:
+       mov             %ebx, [%edx]
+       mov             %ebp, [%edx+4]
+       mov             %esi, [%edx+8]
+       mov             %edi, [%edx+12]
+       ## convert big to little endian
+       bswap           %ebx
+       bswap           %ebp
+       bswap           %esi
+       bswap           %edi
+       add             %edx, 16
+       mov             [%ecx], %ebx
+       mov             [%ecx+4], %ebp
+       mov             [%ecx+8], %esi
+       mov             [%ecx+12], %edi
+       add             %ecx, 16
+       dec             %eax
+       jnz             1b
+
+       pop             %edi
+       pop             %esi
+       pop             %ebp
+       pop             %ebx
+2:
+       ret
+
+.balign 16
+#################################################################################
+##
+##     IN: eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_sse2_convert_2be555_to_2le555):
+       add             %eax, 15
+       shr             %eax, 4         # we can convert 16 pixels at a time
+       movdqa          %xmm5, [d1]
+       movdqa          %xmm6, [d2]
+       jz              2f
+1:
+       movdqa          %xmm1, [%edx]
+       movdqa          %xmm3, [%edx+16]
+
+       ## convert big to little endian
+       movdqa          %xmm2, %xmm1
+       movdqa          %xmm4, %xmm3
+       pand            %xmm1, %xmm5
+       pand            %xmm2, %xmm6
+       pand            %xmm3, %xmm5
+       pand            %xmm4, %xmm6
+       psllw           %xmm1, 8
+       psrlw           %xmm2, 8
+       psllw           %xmm3, 8
+       psrlw           %xmm4, 8
+       por             %xmm1, %xmm2
+       por             %xmm3, %xmm4
+
+       movdqa          [%ecx], %xmm1
+       movdqa          [%ecx+16], %xmm3
+       add             %edx, 32
+       add             %ecx, 32
+       dec             %eax
+       jnz             1b
+
+2:
+       ret
+
+.balign 16
+#################################################################################
+##
+##     IN: %eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_sse2_convert_2be555_to_2le565):
+       add             %eax, 15
+       shr             %eax, 4         # we can convert 16 pixels at a time
+       movdqa          %xmm0, [d1]
+       movdqa          %xmm7, [d2]
+       jz              2f
+1:
+       movdqa          %xmm1, [%edx]
+       movdqa          %xmm3, [%edx+16]
+       ## convert big to little endian
+       movdqa          %xmm2, %xmm1
+       movdqa          %xmm4, %xmm3
+       pand            %xmm1, %xmm0
+       pand            %xmm2, %xmm7
+       pand            %xmm3, %xmm0
+       pand            %xmm4, %xmm7
+       psllw           %xmm1, 8
+       psrlw           %xmm2, 8
+       psllw           %xmm3, 8
+       psrlw           %xmm4, 8
+       por             %xmm1, %xmm2
+       por             %xmm4, %xmm3
+
+       movdqa          %xmm2, %xmm1
+       movdqa          %xmm3, %xmm1
+       movdqa          %xmm5, %xmm4
+       movdqa          %xmm6, %xmm4
+       pand            %xmm1, [_2be555_mask_r]
+       pand            %xmm2, [_2be555_mask_g]
+       pand            %xmm3, [_2be555_mask_b]
+       pand            %xmm4, [_2be555_mask_r]
+       pand            %xmm5, [_2be555_mask_g]
+       pand            %xmm6, [_2be555_mask_b]
+       psllw           %xmm1, 1                # red
+       psllw           %xmm2, 1                # green
+#      psllw           %xmm3, 0                # blue
+       psllw           %xmm4, 1                # red
+       psllw           %xmm5, 1                # green
+#      psllw           %xmm6, 0                # blue
+       por             %xmm1, %xmm2
+       por             %xmm4, %xmm5
+       por             %xmm1, %xmm3
+       por             %xmm4, %xmm6
+       movdqa          [%ecx], %xmm1
+       movdqa          [%ecx+16], %xmm4
+       add             %edx, 32
+       add             %ecx, 32
+       dec             %eax
+       jnz             1b
+2:
+       ret
+
+.balign 16
+#################################################################################
+##
+##     IN: %eax -- number of pixels to convert
+##         %edx -- input
+##          %ecx -- output
+
+EXPORT(x86_sse2_convert_2be555_to_4le888):
+       add             %eax, 3
+       shr             %eax, 3         # we can convert 8 pixels at a time
+       movdqa          %xmm7, [d1]
+       jz              2f
+
+       pxor            %xmm0, %xmm0
+1:
+       movdqa          %xmm1, [%edx]
+
+       ## convert big to little endian
+       movdqa          %xmm3, %xmm1
+       pand            %xmm1, %xmm7
+       pand            %xmm3, [d2]
+       psllw           %xmm1, 8
+       psrlw           %xmm3, 8
+       por             %xmm1, %xmm3
+
+       movdqa          %xmm2, %xmm1
+       movdqa          %xmm3, %xmm1
+       pand            %xmm1, [_2be555_mask_r]
+       pand            %xmm2, [_2be555_mask_g]
+       pand            %xmm3, [_2be555_mask_b]
+       movdqa          %xmm4, %xmm1
+       movdqa          %xmm5, %xmm2
+       movdqa          %xmm6, %xmm3
+       punpcklwd       %xmm1, %xmm0
+       punpcklwd       %xmm2, %xmm0
+       punpcklwd       %xmm3, %xmm0
+       punpckhwd       %xmm4, %xmm0
+       punpckhwd       %xmm5, %xmm0
+       punpckhwd       %xmm6, %xmm0
+       pslld           %xmm1, 16-10+3  # red
+       pslld           %xmm2, 8-5+3    # green
+       pslld           %xmm3, 0+3      # blue
+       pslld           %xmm4, 16-10+3  # red
+       pslld           %xmm5, 8-5+3    # green
+       pslld           %xmm6, 0+3      # blue
+       por             %xmm1, %xmm2
+       por             %xmm1, %xmm3
+       por             %xmm4, %xmm5
+       por             %xmm4, %xmm6
+       movdqa          [%ecx], %xmm1
+       movdqa          [%ecx+16], %xmm4
+       add             %edx, 16
+       add             %ecx, 32
+       dec             %eax
+       jnz             1b
+2:
+       ret
+
diff --git a/ppc/pearpc/system/arch/x86_64/sysendian.h b/ppc/pearpc/system/arch/x86_64/sysendian.h
new file mode 100644 (file)
index 0000000..0dff487
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *     PearPC
+ *     sysendian.h
+ *
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+#define __SYSTEM_ARCH_SPECIFIC_SYSENDIAN_H__
+
+#include "system/types.h"
+
+static inline FORCE_INLINE FUNCTION_CONST uint32 ppc_bswap_word(uint32 data)
+{
+#if 0
+       asm (
+               "bswapl %0": "=r" (data) : "0" (data)
+       );
+#endif
+       data = (data >> 24) | ((data >> 8) & 0x0000ff00) | ((data << 8) & 0x00ff0000) | (data << 24);
+       return data;
+}
+
+static inline FORCE_INLINE FUNCTION_CONST uint16 ppc_bswap_half(uint16 data) 
+{
+#if 0
+       asm (
+               "rolw $8, %0": "=r" (data): "0" (data)
+       );
+#endif
+       data = (data >> 8) | (data << 8);
+       return data;
+}
+
+static inline FORCE_INLINE FUNCTION_CONST uint64 ppc_bswap_dword(uint64 data)
+{
+#if 0
+       asm (
+               "bswapq %0": "=r" (data) : "0" (data)
+       );
+#endif
+       data = (ppc_bswap_word(data) << 32) | (ppc_bswap_word(data >> 32));
+       return data;
+}
+
+#      define ppc_dword_from_BE(data)  (ppc_bswap_dword(data))
+#      define ppc_word_from_BE(data)   (ppc_bswap_word(data))
+#      define ppc_half_from_BE(data)   (ppc_bswap_half(data))
+
+#      define ppc_dword_from_LE(data)  ((uint64)(data))
+#      define ppc_word_from_LE(data)   ((uint32)(data))
+#      define ppc_half_from_LE(data)   ((uint16)(data))
+
+#      define ppc_dword_to_LE(data)    ppc_dword_from_LE(data)
+#      define ppc_word_to_LE(data)     ppc_word_from_LE(data)
+#      define ppc_half_to_LE(data)     ppc_half_from_LE(data)
+
+#      define ppc_dword_to_BE(data)    ppc_dword_from_BE(data)
+#      define ppc_word_to_BE(data)     ppc_word_from_BE(data)
+#      define ppc_half_to_BE(data)     ppc_half_from_BE(data)
+
+#endif
diff --git a/ppc/pearpc/system/arch/x86_64/sysfeatures.h b/ppc/pearpc/system/arch/x86_64/sysfeatures.h
new file mode 100644 (file)
index 0000000..5830769
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *     PearPC
+ *     features.h - arch/x86 variant
+ *
+ *     Copyright (C) 2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+#define __SYSTEM_ARCH_SPECIFIC_FEATURES_H__
+
+// PPC_FEATURE_PROVIDED_BY_ARCH
+#if !defined(PPC_VIDEO_CONVERT_ACCEL_FEATURE) || (PPC_VIDEO_CONVERT_ACCEL_FEATURE < PPC_FEATURE_PROVIDED_BY_ARCH)
+#      undef PPC_VIDEO_CONVERT_ACCEL_FEATURE
+#      define PPC_VIDEO_CONVERT_ACCEL_FEATURE PPC_FEATURE_PROVIDED_BY_ARCH
+#endif
+
+#endif
diff --git a/ppc/pearpc/system/arch/x86_64/sysvaccel.cc b/ppc/pearpc/system/arch/x86_64/sysvaccel.cc
new file mode 100644 (file)
index 0000000..30f3bec
--- /dev/null
@@ -0,0 +1,130 @@
+/* 
+ *     HT Editor
+ *     sysvaccel.cc
+ *
+ *     Copyright (C) 2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "system/sysvaccel.h"
+
+#include "tools/snprintf.h"
+
+#if 0
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_2le555(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_2le565(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_mmx_convert_2be555_to_4le888(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_2le555(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_2le565(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_sse2_convert_2be555_to_4le888(uint32 pixel, byte *input, byte *output);
+extern "C" void __attribute__((regparm (3))) x86_convert_4be888_to_4le888(uint32 pixel, byte *input, byte *output);
+#endif
+
+static inline void convertBaseColor(uint &b, uint fromBits, uint toBits)
+{
+       if (toBits > fromBits) {
+               b <<= toBits - fromBits;
+       } else {
+               b >>= fromBits - toBits;
+       }
+}
+
+static inline void genericConvertDisplay(
+       const DisplayCharacteristics &aSrcChar,
+       const DisplayCharacteristics &aDestChar,
+       const void *aSrcBuf,
+       void *aDestBuf,
+       int firstLine,
+       int lastLine)
+{
+       byte *src = (byte*)aSrcBuf + aSrcChar.bytesPerPixel * aSrcChar.width * firstLine;
+       byte *dest = (byte*)aDestBuf + aDestChar.bytesPerPixel * aDestChar.width * firstLine;
+       for (int y=firstLine; y <= lastLine; y++) {
+               for (int x=0; x < aSrcChar.width; x++) {
+                       uint r, g, b;
+                       uint p;
+                       switch (aSrcChar.bytesPerPixel) {
+                       case 2:
+                               p = (src[0] << 8) | src[1];
+                               break;
+                       case 4:
+                               p = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+                               break;
+                       default:
+                               ht_printf("internal error in %s:%d\n", __FILE__, __LINE__);
+                               exit(1);
+                       break;
+                       }
+                       r = (p >> aSrcChar.redShift) & ((1<<aSrcChar.redSize)-1);
+                       g = (p >> aSrcChar.greenShift) & ((1<<aSrcChar.greenSize)-1);
+                       b = (p >> aSrcChar.blueShift) & ((1<<aSrcChar.blueSize)-1);
+                       convertBaseColor(r, aSrcChar.redSize, aDestChar.redSize);
+                       convertBaseColor(g, aSrcChar.greenSize, aDestChar.greenSize);
+                       convertBaseColor(b, aSrcChar.blueSize, aDestChar.blueSize);
+                       p = (r << aDestChar.redShift) | (g << aDestChar.greenShift)
+                               | (b << aDestChar.blueShift);
+                       switch (aDestChar.bytesPerPixel) {
+                       case 2:
+                               dest[0] = p; dest[1] = p>>8;
+                               break;
+                       case 3:
+                               dest[0] = p; dest[1] = p>>8; dest[2] = p>>16;
+                               break;
+                       case 4:
+                               *(uint32*)dest = p;
+                               break;
+                       default:
+                               ht_printf("internal error in %s:%d\n", __FILE__, __LINE__);
+                               exit(1);
+                       }
+                       dest += aDestChar.bytesPerPixel;
+                       src += aSrcChar.bytesPerPixel;
+               }
+               dest += aDestChar.scanLineLength - aDestChar.width*aDestChar.bytesPerPixel;
+               src += aSrcChar.scanLineLength - aSrcChar.width*aSrcChar.bytesPerPixel;
+       }
+}
+
+void sys_convert_display(
+       const DisplayCharacteristics &aSrcChar,
+       const DisplayCharacteristics &aDestChar,
+       const void *aSrcBuf,
+       void *aDestBuf,
+       int firstLine,
+       int lastLine)
+{
+#if 1
+       genericConvertDisplay(aSrcChar, aDestChar, aSrcBuf, aDestBuf, firstLine, lastLine);
+#else
+       byte *src = (byte*)aSrcBuf + aSrcChar.bytesPerPixel * aSrcChar.width * firstLine;
+       byte *dest = (byte*)aDestBuf + aDestChar.bytesPerPixel * aDestChar.width * firstLine;
+       uint32 pixel = (lastLine-firstLine+1) * aSrcChar.width;
+       if (aSrcChar.bytesPerPixel == 2 && aDestChar.bytesPerPixel == 2) {
+               if (aDestChar.redSize == 5 && aDestChar.greenSize == 6 && aDestChar.blueSize == 5) {
+                       x86_mmx_convert_2be555_to_2le565(pixel, src, dest);
+               } else if (aDestChar.redSize == 5 && aDestChar.greenSize == 5 && aDestChar.blueSize == 5) {
+                       x86_mmx_convert_2be555_to_2le555(pixel, src, dest);
+               } else {
+                       genericConvertDisplay(aSrcChar, aDestChar, aSrcBuf, aDestBuf, firstLine, lastLine);
+               }
+       } else if (aSrcChar.bytesPerPixel == 2 && aDestChar.bytesPerPixel == 4) {
+               x86_mmx_convert_2be555_to_4le888(pixel, src, dest);
+       } else if (aSrcChar.bytesPerPixel == 4 && aDestChar.bytesPerPixel == 4) {
+               x86_convert_4be888_to_4le888(pixel, src, dest);
+       } else {
+               genericConvertDisplay(aSrcChar, aDestChar, aSrcBuf, aDestBuf, firstLine, lastLine);
+       }
+#endif
+}
diff --git a/ppc/pearpc/system/systhread.h b/ppc/pearpc/system/systhread.h
new file mode 100644 (file)
index 0000000..312b715
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *     HT Editor
+ *     systhread.h
+ *
+ *     Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SYSTHREAD_H__
+#define __SYSTHREAD_H__
+
+#include "types.h"
+
+typedef void * sys_mutex;
+typedef void * sys_semaphore;
+typedef void * sys_thread;
+
+typedef void * (*sys_thread_function)(void *);
+
+/* system-dependent (implementation in $MYSYSTEM/systhread.cc) */
+/* all return 0 on success */
+int    sys_create_mutex(sys_mutex *m);
+int    sys_create_semaphore(sys_semaphore *s);
+int    sys_create_thread(sys_thread *t, int flags, sys_thread_function start_routine, void *arg);
+
+void   sys_destroy_mutex(sys_mutex m);
+void   sys_destroy_semaphore(sys_semaphore s);
+void   sys_destroy_thread(sys_semaphore s);
+
+int    sys_lock_mutex(sys_mutex m);
+int    sys_trylock_mutex(sys_mutex m);
+void   sys_unlock_mutex(sys_mutex m);
+
+void   sys_signal_semaphore(sys_semaphore s);
+void   sys_signal_all_semaphore(sys_semaphore s);
+void   sys_wait_semaphore(sys_semaphore s);
+void   sys_wait_semaphore_bounded(sys_semaphore s, int ms);
+
+void   sys_lock_semaphore(sys_semaphore s);
+void   sys_unlock_semaphore(sys_semaphore s);
+
+void   sys_exit_thread(void *ret);
+void * sys_join_thread(sys_thread t);
+
+#endif
diff --git a/ppc/pearpc/system/types.h b/ppc/pearpc/system/types.h
new file mode 100644 (file)
index 0000000..2319384
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ *     PearPC
+ *     types.h
+ *
+ *     Copyright (C) 1999-2003 Sebastian Biallas (sb@biallas.net)
+ *     Copyright (C) 1999-2004 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#define HAVE_CONFIG_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ *     compiler magic
+ */
+
+#ifdef __GNUC__
+
+       // FIXME: configure
+#      ifdef __i386__
+#              define FASTCALL __attribute__((regparm (3)))
+#      else
+#              define FASTCALL
+#      endif
+
+#      define FUNCTION_CONST   __attribute__((const))
+#      define PACKED           __attribute__((packed))
+#      define UNUSED           __attribute__((unused))
+#      define DEPRECATED       __attribute__((deprecated))
+#      define NORETURN         __attribute__((noreturn))
+#      define ALIGN_STRUCT(n)  __attribute__((aligned(n)))
+#      define FORCE_INLINE     __attribute__((always_inline)) 
+
+#elif _MSC_VER
+
+#define FORCE_INLINE __forceinline
+#define NOINLINE __declspec(noinline)
+
+#      define FASTCALL
+#      define FUNCTION_CONST
+#      define PACKED           __attribute__((packed))
+#      define UNUSED           __attribute__((unused))
+#      define DEPRECATED
+#      define ALIGN_STRUCT(n)  __attribute__((aligned(n)))
+#      define NORETURN __declspec(noreturn)
+
+typedef unsigned long long uint64;
+typedef signed long long sint64;
+typedef unsigned int uint32;
+typedef signed int sint32;
+typedef unsigned short uint16;
+typedef signed short sint16;
+typedef unsigned char uint8;
+typedef signed char sint8;
+typedef unsigned char byte;
+
+typedef unsigned int uint;
+
+#ifndef mode_t
+#define mode_t int
+#endif
+
+#endif /* !__GNUC__ */
+
+/*
+ *     integers
+ */
+
+//#include SYSTEM_OSAPI_SPECIFIC_TYPES_HDR
+
+/*
+ *     NULL
+ */
+
+#ifndef NULL
+#      define NULL 0
+#endif
+
+//FIXME: configure somehow (?)
+#ifndef UINT128
+#      define UINT128
+typedef struct uint128 {
+       uint64 l;
+       uint64 h;
+} uint128;
+typedef struct sint128 {
+       sint64 l;
+       sint64 h;
+} sint128;
+#endif
+
+union float_uint32 {
+       uint32 u;
+       float f;
+};
+
+union double_uint64 {
+       uint64 u;
+       double d;
+};
+
+#endif
diff --git a/ppc/pearpc/tools/debug.h b/ppc/pearpc/tools/debug.h
new file mode 100644 (file)
index 0000000..33667b2
--- /dev/null
@@ -0,0 +1,33 @@
+/* 
+ *     HT Editor
+ *     debug.h
+ *
+ *     Copyright (C) 1999-2002 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include "system/types.h"
+
+void NORETURN ht_assert_failed(const char *file, int line, const char *assertion);
+
+#define ASSERT(a) if (!(a)) ht_assert_failed(__FILE__, __LINE__, (#a));
+#define HERE __FILE__, __LINE__
+
+void debugDumpMem(void *buf, int len);
+
+#endif /* !__DEBUG_H__ */
diff --git a/ppc/pearpc/tools/endianess.h b/ppc/pearpc/tools/endianess.h
new file mode 100644 (file)
index 0000000..fe347d7
--- /dev/null
@@ -0,0 +1,54 @@
+/* 
+ *     HT Editor
+ *     endianess.h
+ *
+ *     Copyright (C) 1999-2002 Stefan Weyergraf
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ENDIANESS_H__
+#define __ENDIANESS_H__
+
+#include "system/types.h"
+
+// This is _NOT_ a bitmask!
+#define STRUCT_ENDIAN_8                1
+#define STRUCT_ENDIAN_16       2
+#define STRUCT_ENDIAN_32       4
+#define STRUCT_ENDIAN_64       8
+
+// This is a bitmask.
+#define STRUCT_ENDIAN_HOST     128
+
+typedef enum {
+       big_endian,
+       little_endian
+} Endianess;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void createForeignInt(void *buf, int i, int size, Endianess to_endianess);
+void createForeignInt64(void *buf, uint64 i, int size, Endianess to_endianess);
+int createHostInt(const void *buf, int size, Endianess from_endianess);
+uint64 createHostInt64(const void *buf, int size, Endianess from_endianess);
+void createHostStructx(void *buf, uint bufsize, const uint8 *table, Endianess from_endianess);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ENDIANESS_H__ */
diff --git a/ppc/pearpc/tools/snprintf.h b/ppc/pearpc/tools/snprintf.h
new file mode 100644 (file)
index 0000000..234513e
--- /dev/null
@@ -0,0 +1,39 @@
+/* 
+ *     HT Editor
+ *     snprintf.h
+ *
+ *     Copyright (C) 1999-2003 Sebastian Biallas (sb@biallas.net)
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ *
+ *     This program 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 General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __SNPRINTF_H__
+#define __SNPRINTF_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int ht_asprintf(char **ptr, const char *format, ...);
+int ht_vasprintf(char **ptr, const char *format, va_list ap);
+
+int ht_snprintf(char *str, size_t count, const char *fmt, ...);
+int ht_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
+
+int ht_fprintf(FILE *file, const char *fmt, ...);
+int ht_vfprintf(FILE *file, const char *fmt, va_list args);
+
+int ht_printf(const char *fmt, ...);
+int ht_vprintf(const char *fmt, va_list args);
+#endif
diff --git a/ppc/pearpc/uaeglue.cpp b/ppc/pearpc/uaeglue.cpp
new file mode 100644 (file)
index 0000000..a6b3341
--- /dev/null
@@ -0,0 +1,44 @@
+
+#include <cstring>
+#include <cstdio>
+#include <stdarg.h>
+
+#include "system/systhread.h"
+
+void write_log(const char *format, ...);
+
+int ht_printf(const char *fmt,...)
+{
+       char buffer[1000];
+       va_list parms;
+       va_start(parms, fmt);
+       vsprintf(buffer, fmt, parms);
+       write_log(buffer);
+       va_end(parms);
+       return 0;
+}
+int ht_fprintf(FILE *f, const char *fmt, ...)
+{
+       return 0;
+}
+int ht_vfprintf(FILE *file, const char *fmt, va_list args)
+{
+       return 0;
+}
+int ht_snprintf(char *str, size_t count, const char *fmt, ...)
+{
+       return 0;
+}
+int ht_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
+{
+       return 0;
+}
+
+void ht_assert_failed(const char *file, int line, const char *assertion)
+{
+}
+
+void prom_quiesce()
+{
+}
+
diff --git a/ppc/ppc.cpp b/ppc/ppc.cpp
new file mode 100644 (file)
index 0000000..400e82d
--- /dev/null
@@ -0,0 +1,323 @@
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "threaddep/thread.h"
+#include "ppc.h"
+#include "memory.h"
+#include "cpuboard.h"
+#include "debug.h"
+#include "custom.h"
+#include "uae.h"
+
+#include "cpu/cpu.h"
+
+#define PPC_SYNC_WRITE 0
+#define PPC_ACCESS_LOG 0
+
+volatile int ppc_state;
+
+static bool ppc_thread_running;
+static smp_comm_pipe ppcrequests, ppcreturn;
+static smp_comm_pipe ppcquery, ppcreply;
+int ppc_cycle_count;
+
+#define CSPPC_PVR 0x00090204
+#define BLIZZPPC_PVR 0x00070101
+
+static void *ppc_thread(void *v)
+{
+       for (;;) {
+               uae_u32 v = read_comm_pipe_u32_blocking(&ppcrequests);
+               if (v == 0xfffffff)
+                       break;
+               ppc_cpu_init(currprefs.cpuboard_type == BOARD_BLIZZARDPPC ? BLIZZPPC_PVR : CSPPC_PVR);
+               ppc_cpu_set_pc(0, 0xfff00100);
+               ppc_cycle_count = 240000000 / (hblank_hz * 4);
+               ppc_state = PPC_STATE_ACTIVE;
+               ppc_cpu_run();
+               if (ppc_state == PPC_STATE_ACTIVE || ppc_state == PPC_STATE_SLEEP)
+                       ppc_state = PPC_STATE_STOP;
+               write_log(_T("ppc_cpu_run() exited.\n"));
+               write_comm_pipe_u32(&ppcreturn, 0, 0);
+       }
+
+       ppc_thread_running = false;
+       return NULL;
+}
+
+void uae_ppc_poll_queue(void)
+{
+       if (comm_pipe_has_data(&ppcquery)) {
+               uae_u32 addr = read_comm_pipe_u32_blocking(&ppcquery);
+               uae_u32 size = read_comm_pipe_u32_blocking(&ppcquery);
+               uae_u32 data = 0, data2 = 0;
+               if (size & 0x80) {
+                       if (size & 0x08)
+                               data2 = read_comm_pipe_u32_blocking(&ppcquery);
+                       data = read_comm_pipe_u32_blocking(&ppcquery);
+                       switch (size & 127)
+                       {
+                       case 8:
+                               put_long(addr + 0, data2);
+                               put_long(addr + 4, data);
+                               break;
+                       case 4:
+                               put_long(addr, data);
+                               break;
+                       case 2:
+                               put_word(addr, data);
+                               break;
+                       case 1:
+                               put_byte(addr, data);
+                               break;
+                       }
+#if PPC_SYNC_WRITE
+                       write_comm_pipe_u32(&ppcreply, 0, 1);
+#else
+                       read_comm_pipe_u32_blocking(&ppcquery);
+#endif
+               } else {
+                       switch (size & 127)
+                       {
+                       case 8:
+                               data2 = get_long(addr + 0);
+                               data = get_long(addr + 4);
+                               break;
+                       case 4:
+                               data = get_long(addr);
+                               break;
+                       case 2:
+                               data = get_word(addr);
+                               break;
+                       case 1:
+                               data = get_byte(addr);
+                               break;
+                       }
+                       if (size & 0x08)
+                               write_comm_pipe_u32(&ppcreply, data2, 0);
+                       write_comm_pipe_u32(&ppcreply, data, 1);
+               }
+       }
+}
+
+void uae_ppc_sync (void)
+{
+       while (comm_pipe_has_data(&ppcquery));
+}
+
+bool uae_ppc_direct_physical_memory_handle(uint32 addr, byte *&ptr)
+{
+       if (valid_address(addr, 0x1000)) {
+               ptr = get_real_address(addr);
+               return true;
+       }
+       return false;
+}
+
+bool uae_ppc_io_mem_write(uint32 addr, uint32 data, int size)
+{
+       if (!valid_address(addr, size)) {
+               write_comm_pipe_u32(&ppcquery, addr, 0);
+               write_comm_pipe_u32(&ppcquery, size | 0x80, 0);
+               write_comm_pipe_u32(&ppcquery, data, 1);
+#if PPC_SYNC_WRITE
+               read_comm_pipe_u32_blocking(&ppcreply);
+#else
+               write_comm_pipe_u32(&ppcquery, data, 0);
+#endif
+#if PPC_ACCESS_LOG > 0
+               write_log(_T("PPC io write %08x = %08x %d\n"), addr, data, size);
+#endif
+               return true;
+       }
+       switch (size)
+       {
+       case 4:
+               put_long(addr, data);
+               break;
+       case 2:
+               put_word(addr, data);
+               break;
+       case 1:
+               put_byte(addr, data);
+               break;
+       default:
+               write_log(_T("unknown ppc write %d %08x\n"), addr, size);
+               return false;
+       }
+#if PPC_ACCESS_LOG > 2
+       write_log(_T("PPC mem write %08x = %08x %d\n"), addr, data, size);
+#endif
+       return true;
+}
+
+bool uae_ppc_io_mem_read(uint32 addr, uint32 &data, int size)
+{
+       uint32 v;
+
+       if (!valid_address(addr, size)) {
+               write_comm_pipe_u32(&ppcquery, addr, 0);
+               write_comm_pipe_u32(&ppcquery, size, 1);
+               v = read_comm_pipe_u32_blocking(&ppcreply);
+#if PPC_ACCESS_LOG > 0
+               if (addr != 0xbfe001)
+                       write_log(_T("PPC io read %08x=%08x %d\n"), addr, v, size);
+#endif
+               data = v;
+               return true;
+       }
+
+       switch (size)
+       {
+       case 4:
+               v = get_long(addr);
+               break;
+       case 2:
+               v = get_word(addr);
+               break;
+       case 1:
+               v = get_byte(addr);
+               break;
+       default:
+               write_log(_T("unknown ppc read %d %08x\n"), addr, size);
+               return false;
+       }
+       data = v;
+
+#if PPC_ACCESS_LOG > 2
+       write_log(_T("PPC mem read %08x=%08x %d\n"), addr, v, size);
+#endif
+       return true;
+}
+
+bool uae_ppc_io_mem_write64(uint32 addr, uint64 data)
+{
+       if (!valid_address(addr, 8)) {
+#if PPC_ACCESS_LOG > 0
+               write_log(_T("PPC io write64 %08x = %08llx\n"), addr, data);
+#endif
+               write_comm_pipe_u32(&ppcquery, addr, 0);
+               write_comm_pipe_u32(&ppcquery, 8 | 0x80, 0);
+               write_comm_pipe_u32(&ppcquery, data >> 32, 0);
+               write_comm_pipe_u32(&ppcquery, data & 0xffffffff, 1);
+#if PPC_SYNC_WRITE
+               read_comm_pipe_u32_blocking(&ppcreply);
+#else
+               write_comm_pipe_u32(&ppcquery, data, 0);
+#endif
+               return true;
+       }
+       put_long(addr + 0, data >> 32);
+       put_long(addr + 4, data & 0xffffffff);
+#if PPC_ACCESS_LOG > 2
+       write_log(_T("PPC mem write64 %08x = %08llx\n"), addr, data);
+#endif
+       return true;
+}
+
+bool uae_ppc_io_mem_read64(uint32 addr, uint64 &data)
+{
+       uae_u32 v1, v2;
+       if (!valid_address(addr, 8)) {
+               write_comm_pipe_u32(&ppcquery, addr, 0);
+               write_comm_pipe_u32(&ppcquery, 8, 0);
+               v1 = read_comm_pipe_u32_blocking(&ppcreply);
+               v2 = read_comm_pipe_u32_blocking(&ppcreply);
+               data = ((uint64)v1 << 32) | v2;
+#if PPC_ACCESS_LOG > 0
+               write_log(_T("PPC io read64 %08x = %08llx\n"), addr, data);
+#endif
+               return true;
+       }
+       v1 = get_long(addr + 0);
+       v2 = get_long(addr + 4);
+       data = ((uint64)v1 << 32) | v2;
+#if PPC_ACCESS_LOG > 2
+       write_log(_T("PPC mem read64 %08x = %08llx\n"), addr, data);
+#endif
+       return true;
+}
+
+void ppc_stop(void)
+{
+       if (ppc_thread_running && ppc_state) {
+               if (ppc_state == PPC_STATE_SLEEP)
+                       ppc_state = PPC_STATE_ACTIVE;
+               write_log(_T("Stopping PPC.\n"));
+               ppc_cpu_stop();
+               while (ppc_state != PPC_STATE_STOP && ppc_state != PPC_STATE_CRASH) {
+                       uae_ppc_poll_queue();
+               }
+               read_comm_pipe_u32_blocking(&ppcreturn);
+               write_log(_T("PPC stopped.\n"));
+       }
+}
+
+void ppc_reboot(void)
+{
+       write_log(_T("Starting PPC thread.\n"));
+       if (!ppc_thread_running) {
+               ppc_thread_running = true;
+               init_comm_pipe(&ppcrequests, 10, 1);
+               init_comm_pipe(&ppcreturn, 10, 1);
+               init_comm_pipe(&ppcreply, 100, 1);
+               init_comm_pipe(&ppcquery, 100, 1);
+               uae_start_thread(_T("ppc"), ppc_thread, NULL, NULL);
+       }
+       write_comm_pipe_u32(&ppcrequests, 1, 1);
+}
+
+void ppc_wakeup(void)
+{
+       if (ppc_state == PPC_STATE_SLEEP)
+               ppc_state = PPC_STATE_ACTIVE;
+}
+
+void ppc_cpu_atomic_raise_ext_exception(void);
+void ppc_cpu_atomic_cancel_ext_exception(void);
+
+void ppc_interrupt(bool active)
+{
+       if (active) {
+               ppc_cpu_atomic_raise_ext_exception();
+               ppc_wakeup();
+       } else {
+               ppc_cpu_atomic_cancel_ext_exception();
+       }
+}
+
+
+// sleep until interrupt (or PPC stopped)
+void ppc_doze(void)
+{
+       ppc_state = PPC_STATE_SLEEP;
+       while (ppc_state == PPC_STATE_SLEEP) {
+               sleep_millis(2);
+       }
+}
+
+void ppc_crash(void)
+{
+       ppc_state = PPC_STATE_CRASH;
+       ppc_cpu_stop();
+}
+
+typedef void * sys_mutex;
+
+int    sys_lock_mutex(sys_mutex m)
+{
+       uae_sem_wait(&m);
+       return 1;
+}
+void sys_unlock_mutex(sys_mutex m)
+{
+       uae_sem_post(&m);
+}
+int    sys_create_mutex(sys_mutex *m)
+{
+       if (!(*m))
+               uae_sem_init(m, 0, 1);
+       return 1;
+}
diff --git a/ppc/ppcd.cpp b/ppc/ppcd.cpp
new file mode 100644 (file)
index 0000000..2d84c71
--- /dev/null
@@ -0,0 +1,1770 @@
+// Very accurate PowerPC Architecture disassembler (both 32 and 64-bit instructions are supported)
+
+// Branch Target in output parameters is NOT relative. Its already precalculated
+// from effective address of current instruction.
+
+// Note, that old mnemonics and operands will be overwritten, after next disasm
+// call. So dont forget to copy them away, if supposed to use them lately.
+
+// Instruction class can be combined from many flags. There can exist, for example,
+// "FPU" + "LDST" instruction, except "ILLEGAL", which cannot be combined.
+
+// RLWINM-like instructions mask is placed in output "target" parameter.
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ppcd.h"
+
+#define POWERPC_32      // Use generic 32-bit model
+//efine POWERPC_64      // Use generic 64-bit model
+//efine GEKKO           // Use Gekko (32-bit ISA)
+//efine BROADWAY        // Use Broadway (32-bit ISA)
+
+#define SIMPLIFIED      // Allow simplified mnemonics
+//efine UPPERCASE       // Use upper case strings in output
+#define COMMA   ", "
+#define LPAREN  " ("
+#define RPAREN  ")"
+#define HEX1    "0x"    // prefix
+#define HEX2    ""      // suffix
+
+static int bigendian = -1;  // Autodetect.
+
+// ---------------------------------------------------------------------------
+// Implementation. Look away, code is messed :)
+// Dont miss 'l' and '1'.
+
+static PPCD_CB *o;
+#define Instr   (o->instr)
+#define DIS_PC  (o->pc)
+
+// Simple decoder
+#define DIS_RD      ((Instr >> 21) & 0x1f)
+#define DIS_RS      DIS_RD
+#define DIS_RA      ((Instr >> 16) & 0x1f)
+#define DIS_RB      ((Instr >> 11) & 0x1f)
+#define DIS_RC      ((Instr >>  6) & 0x1f)
+#define DIS_RE      ((Instr >>  1) & 0x1f)
+#define DIS_MB      DIS_RC
+#define DIS_ME      DIS_RE
+#define DIS_OE      (Instr & 0x400)
+#define DIS_SIMM    ((s16)Instr)
+#define DIS_UIMM    (Instr & 0xffff)
+#define DIS_CRM     ((Instr >> 12) & 0xff)
+#define AA          (Instr & 2)
+#define LK          (Instr & 1)
+#define AALK        (Instr & 3)
+#define Rc          LK
+
+// GPRs. sp, sd1 and sd2 are named corresponding to PPC EABI.
+static char *regname[] = {
+#ifdef UPPERCASE
+ "R0" , "R1" , "R2", "R3" , "R4" , "R5" , "R6" , "R7" , 
+ "R8" , "R9" , "R10", "R11", "R12", "R13", "R14", "R15", 
+ "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", 
+ "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31"
+#else
+ "r0" , "r1" , "r2", "r3" , "r4" , "r5" , "r6" , "r7" , 
+ "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", 
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+#endif
+};
+#define REGD        (regname[DIS_RD])
+#define REGS        (regname[DIS_RS])
+#define REGA        (regname[DIS_RA])
+#define REGB        (regname[DIS_RB])
+
+// Illegal instruction.
+static void ill(void)
+{
+#if 1
+    o->mnemonic[0] = o->operands[0] = '\0';
+#else
+    strcpy(o->mnemonic, ".word");
+    sprintf(o->operands, HEX1 "%08X" HEX2, Instr);
+#endif
+    o->iclass = PPC_DISA_ILLEGAL;
+}
+
+// Smart SIMM formatting (if hex=1, then force HEX; if s=1, use sign)
+static char * simm(int val, int hex, int s)
+{
+    static char out[16];
+    if( ((val >= -256) && (val <= 256)) && !hex) sprintf(out, "%i", val);
+    else
+    {
+        u16 hexval = (u16)val;
+        if((hexval & 0x8000) && s) sprintf(out, "-" HEX1 "%04X" HEX2, ((~hexval) & 0xffff) + 1);
+        else sprintf(out, HEX1 "%04X" HEX2, hexval);
+    }
+    return out;
+}
+
+// Simple instruction form + reserved bitmask.
+static void put(char * mnem, u32 mask, u32 chkval=0, int iclass=PPC_DISA_OTHER)
+{
+    if( (Instr & mask) != chkval ) { ill(); return; }
+    o->iclass |= iclass;
+    strncpy(o->mnemonic, mnem, sizeof(o->mnemonic));
+}
+
+// Simplified mnemonic trap conditions
+static char * t_cond[32] = {
+ NULL, "lgt", "llt", NULL, "eq", "lge", "lle", NULL,
+ "gt", NULL, NULL, NULL, "ge", NULL, NULL, NULL,
+ "lt", NULL, NULL, NULL, "le", NULL, NULL, NULL,
+ "ne", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+};
+
+// Trap instructions.
+static void trap(int L, int imm)
+{
+    static char t_mode[2] = { 'w', 'd' };
+    int rd = DIS_RD;    // TO
+    int s = (rd & 0x18) ? 1 : 0;
+#ifdef  SIMPLIFIED
+    if(t_cond[rd] != NULL)
+    {
+        sprintf(o->mnemonic, "t%c%s%c", t_mode[L & 1], t_cond[rd], imm ? 'i' : 0);
+        if(imm) sprintf(o->operands, "%s" COMMA "%s", REGA, simm(DIS_SIMM, 0, s));
+        else sprintf(o->operands, "%s" COMMA "%s", REGA, REGB);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+    }
+    else
+#endif
+    {
+        sprintf(o->mnemonic, "t%c%c", t_mode[L & 1], imm ? 'i' : 0);
+        if(imm) sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, simm(DIS_SIMM, 0, s));
+        else sprintf(o->operands, "%i" COMMA "%s" COMMA "%s", rd, REGA, REGB);
+    }
+    if(L) o->iclass |= PPC_DISA_64;
+    o->r[1] = DIS_RA; if(!imm) o->r[2] = DIS_RB;
+    if(imm)
+    {
+        o->immed = Instr & 0xFFFF;
+        if(o->immed & 0x8000) o->immed |= 0xFFFF0000;
+    }
+}
+
+// DAB mask
+#define DAB_D   4
+#define DAB_A   2
+#define DAB_B   1
+
+// ASB mask
+#define ASB_A   4
+#define ASB_S   2
+#define ASB_B   1
+
+// cr%i 
+#ifdef UPPERCASE
+    static char crname[] = "CR";
+#else
+    static char crname[] = "cr";
+#endif
+
+// fr%i
+#ifdef UPPERCASE
+    static char fregname[] = "FR";
+#else
+    static char fregname[] = "fr";
+#endif
+
+// Integer instructions
+// form: 'D'    rD, rA, (s)IMM
+//       'S'    rA, rS, (s)IMM
+//       'X'    rD, rA, rB
+//       'Z'    rA, rS, rB
+//       'F'    frD, rA, rB
+// dab LSB bits : [D][A][B] (D should always present)
+// 'hex' for logic opcodes, 's' for alu opcodes, 'crfD' and 'L' for cmp opcodes
+// 'imm': 1 to show immediate operand
+static void integer(char *mnem, char form, int dab, int hex=0, int s=1, int crfD=0, int L=0, int imm=1)
+{
+    char * ptr = o->operands;
+    int rd = DIS_RD, ra = DIS_RA, rb = DIS_RB;
+    strncpy(o->mnemonic, mnem, sizeof(o->mnemonic));
+    if(crfD) ptr += sprintf(ptr, "%s%i" COMMA, crname, rd >> 2); // CMP only
+    if(L) ptr += sprintf(ptr, "%i" COMMA, rd & 1);           // CMP only
+    if(form == 'D')
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s));
+    }
+    else if(form == 'S')
+    {
+        if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA);
+        if(dab & ASB_S)
+        {
+            if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGS);
+        }
+        if(imm) ptr += sprintf(ptr, COMMA "%s", simm(s ? DIS_SIMM : DIS_UIMM, hex, s));
+    }
+    else if(form == 'X')    // DAB
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s", REGD);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(dab & DAB_B)
+        {
+            if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else if(form == 'F')    // FPU DAB
+    {
+        if(dab & DAB_D) ptr += sprintf(ptr, "%s%i", fregname, rd);
+        if(dab & DAB_A)
+        {
+            if(dab & DAB_D) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGA);
+        }
+        if(dab & DAB_B)
+        {
+            if(dab & (DAB_D|DAB_A)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else if(form == 'Z')    // ASB
+    {
+        if(dab & ASB_A) ptr += sprintf(ptr, "%s", REGA);
+        if(dab & ASB_S)
+        {
+            if(dab & ASB_A) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGS);
+        }
+        if(dab & ASB_B)
+        {
+            if(dab & (ASB_A|ASB_S)) ptr += sprintf(ptr, "%s", COMMA);
+            ptr += sprintf(ptr, "%s", REGB);
+        }
+    }
+    else { ill(); return; }
+    if(form == 'D' || form == 'X' || form == 'F') { o->r[0] = rd; o->r[1] = ra; }
+    if(form == 'S' || form == 'Z') { o->r[0] = ra; o->r[1] = rd; }
+    if(form == 'X' || form == 'Z' || form == 'F') o->r[2] = rb;
+    if((form == 'D' || form == 'S') && imm)
+    {
+        o->immed = Instr & 0xFFFF;
+        if(o->immed & 0x8000 && s) o->immed |= 0xFFFF0000;
+    }
+    o->iclass |= PPC_DISA_INTEGER;
+}
+
+// Compare instructions (wraps to integer call)
+static void cmp(char *l, char *i)
+{
+    char mnem[sizeof(o->mnemonic)];
+    int rd = DIS_RD;
+    
+    if(rd & 2) { ill(); return; }   // Reserved bit set
+    if(rd & 1)
+    {
+#ifndef  POWERPC_64
+        { ill(); return; }
+#endif
+        o->iclass |= PPC_DISA_64;
+    }
+
+#ifdef  SIMPLIFIED
+    sprintf(mnem, "cmp%s%c%s", l, (rd & 1) ? 'd' : 'w', i);
+    integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, (rd >> 2) ? 1 : 0, 0);
+    o->iclass |= PPC_DISA_SIMPLIFIED;
+#else
+    sprintf(mnem, "cmp%s%s", l, i);
+    integer(mnem, (*i == 'i') ? 'D' : 'X', DAB_A|DAB_B, 0, 1, 1, 1);
+#endif
+}
+
+// Add immediate (wraps to integer call)
+static void addi(char *suffix)
+{
+    char mnem[sizeof(o->mnemonic)];
+
+#ifdef  SIMPLIFIED
+    if( (suffix[0] == '\0') && (DIS_RA == 0) )  // Load immediate
+    {
+        integer("li", 'D', DAB_D, 0, 1);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+        return;
+    }
+    if( (suffix[0] == 's') && (DIS_RA == 0) )   // Load address HI
+    {
+        integer("lis", 'D', DAB_D, 1, 0);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+        return;
+    }
+    if(DIS_UIMM & 0x8000)
+    {
+        sprintf(mnem, "subi%s", suffix);
+
+        // Fix immediate field.
+        u16 value = (u16)(~(DIS_UIMM) + 1);
+        Instr = (Instr & ~0xFFFF) | value;
+
+        integer(mnem, 'D', DAB_D|DAB_A, 0, 1);
+        o->iclass |= PPC_DISA_SIMPLIFIED;
+    }
+    else
+    {
+        sprintf(mnem, "addi%s", suffix);
+        integer(mnem, 'D', DAB_D|DAB_A, 0, 0);
+    }
+#else
+    sprintf(mnem, "addi%s", suffix);
+    integer(mnem, 'D', DAB_D|DAB_A);
+#endif
+}
+
+// Branch suffix: AA || LK.
+static char *b_opt[4] = { "", "l", "a", "la" };
+
+// Branch condition code: 4 * BO[1] + (BI & 3)
+static char * b_cond[8] = {
+ "ge", "le", "ne", "ns", "lt", "gt", "eq", "so"
+};
+
+// Branch on CTR code: BO[0..3]
+static char * b_ctr[16] = {
+ "dnzf", "dzf", NULL, NULL, "dnzt", "dzt", NULL, NULL,
+ "dnz", "dz", NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+// Place target address in operands. Helper for bcx/bx calls.
+static char *place_target(char *ptr, int comma)
+{
+    char *old;
+    u32 *t = (u32 *)&o->target;
+
+    if(comma) ptr += sprintf(ptr, "%s", COMMA);
+    old = ptr;
+#ifdef  POWERPC_32
+    ptr += sprintf(ptr, HEX1 "%08X" HEX2, (u32)o->target);
+#endif
+#ifdef  POWERPC_64
+    ptr = old;
+    if(bigendian) ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[0], t[1]);
+    else ptr += sprintf(ptr, HEX1 "%08X_%08X" HEX2, t[1], t[0]);
+#endif
+    return ptr;
+}
+
+// Branch conditional.
+// Disp:1 - branch with displacement..
+// Disp:0 - branch by register (L:1 for LR, L:0 for CTR).
+static void bcx(int Disp, int L)
+{
+    u64 bd = 0;
+    int bo = DIS_RD, bi = DIS_RA;
+    char *r = Disp ? "" : (L ? "lr" : "ctr");
+    char *ptr = o->operands;
+
+    if( DIS_RB && !Disp ) { ill(); return; }
+
+    o->operands[0] = '\0';
+    o->target = 0;
+    o->iclass |= PPC_DISA_BRANCH;
+
+    // Calculate displacement and target address
+    if(Disp)
+    {
+        bd = DIS_UIMM & ~3;
+        if(bd & 0x8000) bd |= 0xffffffffffff0000;
+        o->target = (AA ? 0 : DIS_PC) + bd;
+    }
+    else o->target = 0;
+
+    // Calculate branch prediction hint
+    char y = (bo & 1) ^ ((((s64)bd < 0) && Disp) ? 1 : 0);
+    y = y ? '+' : '-';
+
+    if(bo & 4)              // No CTR decrement                         // BO[2]
+    {
+        if(bo & 16)         // Branch always                            // BO[0]
+        {
+#ifdef  SIMPLIFIED
+            sprintf(o->mnemonic, "b%s%s", r, b_opt[Disp ? AALK : LK]);
+            if(Disp) ptr = place_target(ptr, 0);
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+#endif  // SIMPLIFIED
+        }
+        else                // Branch conditional
+        {
+            if(bo & 2) { ill(); return; }                               // BO[3]
+#ifdef  SIMPLIFIED
+            char *cond = b_cond[((bo & 8) >> 1) | (bi & 3)];
+            if(cond != NULL)                                            // BO[1]
+            {
+                sprintf(o->mnemonic, "b%s%s%s%c", cond, r, b_opt[Disp ? AALK : LK], y);
+                if(bi >= 4) ptr += sprintf(ptr, "%s%i", crname, bi >> 2);
+                if(Disp) ptr = place_target(ptr, bi >= 4);
+                o->iclass |= PPC_DISA_SIMPLIFIED;
+                return;
+            }
+#endif  // SIMPLIFIED
+        }
+    }
+    else                    // Decrement CTR
+    {
+        if(!L && !Disp) { ill(); return; }
+        if(bo & 8) { ill(); return; }                               // BO[1]
+#ifdef  SIMPLIFIED
+        if(b_ctr[bo >> 1])
+        {
+            sprintf(o->mnemonic, "b%s%s%s%c", b_ctr[bo >> 1], r, b_opt[Disp ? AALK : LK], y);
+            if(!(bo & 16)) ptr += sprintf(ptr, "%i", bi);
+            if(Disp) ptr = place_target(ptr, !(bo & 16));
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+#endif  // SIMPLIFIED
+    }
+
+    // Not simplified standard form
+    sprintf(o->mnemonic, "bc%s%s", r, b_opt[Disp ? AALK : LK]);
+    ptr += sprintf(ptr, "%i" COMMA "%i", bo, bi);
+    if(Disp) ptr = place_target(ptr, 1);
+}
+
+// Branch unconditional
+static void bx(void)
+{
+    // Calculate displacement and target address
+    u64 bd = Instr & 0x03fffffc;
+    if(bd & 0x02000000) bd |= 0xfffffffffc000000;
+    o->target = (AA ? 0 : DIS_PC) + bd;
+    o->iclass |= PPC_DISA_BRANCH;
+    sprintf(o->mnemonic, "b%s", b_opt[AALK]);
+    place_target(o->operands, 0);
+}
+
+// Move CR field
+static void mcrf(void)
+{
+    if(Instr & 0x63f801) { ill(); return; }
+    strncpy(o->mnemonic, "mcrf", sizeof(o->mnemonic));
+    sprintf(o->operands, "%s%i" COMMA "%s%i", crname, DIS_RD >> 2, crname, DIS_RA >> 2);
+}
+
+// CR logic operations
+static void crop(char *name, char *simp="", int ddd=0, int daa=0)
+{
+    if(Instr & 1) { ill(); return; }
+
+    int crfD = DIS_RD, crfA = DIS_RA, crfB = DIS_RB;
+
+#ifdef  SIMPLIFIED
+    if( crfA == crfB )
+    {
+        if( (crfD == crfA) && ddd )
+        {
+            sprintf(o->mnemonic, "cr%s", simp);
+            sprintf(o->operands, "%i", crfD);
+            o->r[0] = crfD;
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+        if( daa )
+        {
+            sprintf(o->mnemonic, "cr%s", simp);
+            sprintf(o->operands, "%i" COMMA "%i", crfD, crfA);
+            o->r[0] = crfD; o->r[1] = crfA;
+            o->iclass |= PPC_DISA_SIMPLIFIED;
+            return;
+        }
+    }
+#endif
+    sprintf(o->mnemonic, "cr%s", name);
+    sprintf(o->operands, "%i" COMMA "%i" COMMA "%i", crfD, crfA, crfB);
+    o->r[0] = crfD; o->r[1] = crfA; o->r[2] = crfB;
+}
+
+#define MASK32(b, e) \
+{ \
+    u32 mask = ((u32)0xffffffff >> (b)) ^ (((e) >= 31) ? 0 : ((u32)0xffffffff) >> ((e) + 1)); \
+    o->target = ((b) > (e)) ? (~mask) : (mask); \
+}
+
+#define MASK64(b, e) \
+{ \
+    u64 mask = ((u64)0xffffffffffffffff >> (b)) ^ (((e) >= 63) ? 0 : ((u64)0xffffffffffffffff) >> ((e) + 1)); \
+    o->target = ((b) > (e)) ? (~mask) : (mask); \
+}
+
+// Rotate left word.
+static void rlw(char *name, int rb, int ins=0)
+{
+    int mb = DIS_MB, me = DIS_ME;
+    char * ptr = o->operands;
+    sprintf(o->mnemonic, "rlw%s%c", name, Rc ? '.' : '\0');
+    ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS);
+    if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB);
+    else   ptr += sprintf(ptr, "%i" COMMA, DIS_RB);     // sh
+    ptr += sprintf(ptr, "%i" COMMA "%i", mb, me);
+
+    // Put mask in target.
+    MASK32(mb, me);
+#ifdef POWERPC_64
+    MASK64(mb+32, me+32);
+#endif
+
+    o->r[0] = DIS_RA;
+    o->r[1] = DIS_RS;
+    if(rb) o->r[2] = DIS_RB;
+    o->iclass |= PPC_DISA_INTEGER;
+}
+
+// RLD mask
+#define RLDM_LEFT       0       // MASK(b, 63)
+#define RLDM_RIGHT      1       // MASK(0, e)
+#define RLDM_INS        2       // MASK(b, ~n)
+
+// Rotate left double-word.
+static void rld(char *name, int rb, int mtype)
+{
+#ifdef POWERPC_64
+    int m = DIS_MB, n = DIS_RB;
+    if(Instr & 0x20) m += 32;   // b or e
+    if(Instr & 0x02) n += 32;   // sh
+
+    char * ptr = o->operands;
+    sprintf(o->mnemonic, "rld%s%c", name, Rc ? '.' : '\0');
+    ptr += sprintf(ptr, "%s" COMMA "%s" COMMA, REGA, REGS);
+    if(rb) ptr += sprintf(ptr, "%s" COMMA, REGB);
+    else   ptr += sprintf(ptr, "%i" COMMA, n);
+    ptr += sprintf(ptr, "%i", m);
+
+    // Put mask in target.
+    switch(mtype)
+    {
+        case RLDM_LEFT: MASK64(m, 63); break;
+        case RLDM_RIGHT: MASK64(0, m); break;
+        case RLDM_INS: MASK64(m, ~n); break;
+    }
+
+    o->r[0] = DIS_RA;
+    o->r[1] = DIS_RS;
+    if(rb) o->r[2] = DIS_RB;
+    o->iclass |= PPC_DISA_64 | PPC_DISA_INTEGER;
+#endif
+}
+
+// Load/Store.
+static void ldst(char *name, int x/*indexed*/, int load=1, int L=0, int string=0, int fload=0)
+{
+    if(x) integer(name, fload ? 'F' : 'X', DAB_D|DAB_A|DAB_B);
+    else
+    {
+        int rd = DIS_RD, ra = DIS_RA;
+        s16 imm = DIS_SIMM;
+        strcpy (o->mnemonic, name);
+        if(fload) sprintf (o->operands, "%s%i" COMMA "%s" LPAREN "%s" RPAREN, fregname, rd, simm(imm, 0, 1), regname[ra]);
+        else sprintf (o->operands, "%s" COMMA "%s" LPAREN "%s" RPAREN, regname[rd], simm(imm, 0, 1), regname[ra]);
+        o->r[0] = rd;
+        o->r[1] = ra;
+        o->immed = DIS_UIMM & 0x8000 ? DIS_UIMM | 0xFFFF0000 : DIS_UIMM;
+    }
+
+    o->iclass = PPC_DISA_LDST;
+    if(L) o->iclass |= PPC_DISA_64;
+    if(string) o->iclass |= PPC_DISA_STRING;
+    if(fload) o->iclass |= PPC_DISA_FPU;
+}
+
+// Cache.
+static void cache(char *name, int flag=PPC_DISA_OTHER)
+{
+    if (DIS_RD) { ill(); return; }
+    else
+    {
+        integer(name, 'X', DAB_A|DAB_B);
+        o->r[0] = o->r[1];
+        o->r[1] = o->r[2];
+        o->r[2] = 0;
+        o->iclass &= ~PPC_DISA_INTEGER;
+        o->iclass |= flag;
+    }
+}
+
+static void movesr(char *name, int from, int L, int xform)
+{
+    int reg = DIS_RD, sreg = DIS_RA & 0xF, regb = DIS_RB;
+
+    strncpy(o->mnemonic, name, sizeof(o->mnemonic));
+    if(xform)
+    {
+        if(Instr & 0x001F0001) { ill(); return; }
+        sprintf(o->operands, "%s" COMMA "%s", regname[reg], regname[regb]);
+        o->r[0] = reg;
+        o->r[1] = regb;
+    }
+    else
+    {
+        if(Instr & 0x0010F801) { ill(); return; }
+        if(from)
+        {
+            sprintf(o->operands, "%s" COMMA "%i", regname[reg], sreg);
+            o->r[0] = reg;
+            o->r[1] = sreg;
+        }
+        else
+        {
+            sprintf(o->operands, "%i" COMMA "%s", sreg, regname[reg]);
+            o->r[0] = sreg;
+            o->r[1] = reg;
+        }
+    }
+
+    if(L) o->iclass |= PPC_DISA_OEA | PPC_DISA_OPTIONAL | PPC_DISA_BRIDGE | PPC_DISA_64;
+    else o->iclass |= PPC_DISA_OEA | PPC_DISA_BRIDGE;
+}
+
+static void mtcrf(void)
+{
+    int rs = DIS_RS, crm = DIS_CRM;
+
+#ifdef SIMPLIFIED
+    if(crm == 0xFF)
+    {
+        strncpy(o->mnemonic, "mtcr", sizeof(o->mnemonic));
+        sprintf(o->operands, "%s", regname[rs]);
+    }
+    else
+#endif
+    {
+        strncpy(o->mnemonic, "mtcrf", sizeof(o->mnemonic));
+        sprintf(o->operands, HEX1 "%02X" HEX2 COMMA "%s", crm, regname[rs]);
+    }
+    o->r[0] = rs;
+}
+
+static void mcrxr(void)
+{
+    if (Instr & 0x007FF800) { ill(); return; }
+    strcpy (o->mnemonic, "mcrxr");
+    sprintf (o->operands, "%s%i", crname, DIS_RD >> 2);
+    o->r[0] = DIS_RD >> 2;
+}
+
+static char *spr_name(int n)
+{
+    static char def[8];
+
+    switch(n)
+    {
+        // General architecture special-purpose registers.
+        case 1: return "XER";
+        case 8: return "LR";
+        case 9: return "CTR";
+        case 18: return "DSISR";
+        case 19: return "DAR";
+        case 22: return "DEC";
+        case 25: return "SDR1";
+        case 26: return "SRR0";
+        case 27: return "SRR1";
+        case 272: return "SPRG0";
+        case 273: return "SPRG1";
+        case 274: return "SPRG2";
+        case 275: return "SPRG3";
+#ifdef  POWERPC_64
+        case 280: return "ASR";
+#endif
+        case 284: return "TBL";
+        case 285: return "TBU";
+        case 287: return "PVR";
+        case 528: return "IBAT0U";
+        case 529: return "IBAT0L";
+        case 530: return "IBAT1U";
+        case 531: return "IBAT1L";
+        case 532: return "IBAT2U";
+        case 533: return "IBAT2L";
+        case 534: return "IBAT3U";
+        case 535: return "IBAT3L";
+        case 536: return "DBAT0U";
+        case 537: return "DBAT0L";
+        case 538: return "DBAT1U";
+        case 539: return "DBAT1L";
+        case 540: return "DBAT2U";
+        case 541: return "DBAT2L";
+        case 542: return "DBAT3U";
+        case 543: return "DBAT3L";
+
+        // Optional registers.
+#if !defined(GEKKO) && !defined(BROADWAY)
+        case 282: return "EAR";
+        case 1013: return "DABR";
+        case 1022: return "FPECR";
+        case 1023: return "PIR";
+#endif
+
+        // Gekko-specific SPRs
+#ifdef GEKKO
+        case 282: return "EAR";
+        case 912: return "GQR0";
+        case 913: return "GQR1";
+        case 914: return "GQR2";
+        case 915: return "GQR3";
+        case 916: return "GQR4";
+        case 917: return "GQR5";
+        case 918: return "GQR6";
+        case 919: return "GQR7";
+        case 920: return "HID2";
+        case 921: return "WPAR";
+        case 922: return "DMAU";
+        case 923: return "DMAL";
+        case 936: return "UMMCR0";
+        case 940: return "UMMCR1";
+        case 937: return "UPMC1";
+        case 938: return "UPMC2";
+        case 939: return "USIA";
+        case 941: return "UPMC3";
+        case 942: return "UPMC4";
+        case 943: return "USDA";
+        case 952: return "MMCR0";
+        case 953: return "PMC1";
+        case 954: return "PMC2";
+        case 955: return "SIA";
+        case 956: return "MMCR1";
+        case 957: return "PMC3";
+        case 958: return "PMC4";
+        case 959: return "SDA";
+        case 1008: return "HID0";
+        case 1009: return "HID1";
+        case 1010: return "IABR";
+        case 1013: return "DABR";
+        case 1017: return "L2CR";
+        case 1019: return "ICTC";
+        case 1020: return "THRM1";
+        case 1021: return "THRM2";
+        case 1022: return "THRM3";
+#endif
+    }
+
+    sprintf(def, "%u", n);
+    return def;
+}
+
+static char *tbr_name(int n)
+{
+    static char def[8];
+
+    switch(n)
+    {
+        // General architecture time-base registers.
+        case 268: return "TBL";
+        case 269: return "TBU";
+    }
+
+    sprintf(def, "%u", n);
+    return def;
+}
+
+static void movespr(int from)
+{
+    int spr = (DIS_RB << 5) | DIS_RA, f = 1;
+    char *fix;
+
+    if( !((spr == 1) || (spr == 8) || (spr == 9)) ) o->iclass |= PPC_DISA_OEA;
+
+    // Handle simplified mnemonic
+    if (spr == 1) { fix = "xer"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (spr == 8) { fix = "lr"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (spr == 9) { fix = "ctr"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else { fix = "spr"; f = 0; }
+
+    // Mnemonics and operands.
+    sprintf (o->mnemonic, "m%c%s", from ? 'f' : 't', fix);
+    if (f)
+    {
+        sprintf (o->operands, "%s", regname[DIS_RD]);
+        o->r[0] = DIS_RD;
+    }
+    else
+    {
+        if (from)
+        {
+            sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], spr_name(spr));
+            o->r[0] = DIS_RD;
+            o->r[1] = spr;
+        }
+        else
+        {
+            sprintf (o->operands, "%s" COMMA "%s", spr_name(spr), regname[DIS_RD]);
+            o->r[0] = spr;
+            o->r[1] = DIS_RD;
+        }
+    }
+}
+
+static void movetbr(void)
+{
+    int tbr = (DIS_RB << 5) | DIS_RA, f = 1;
+    char *fix;
+
+    // Handle simplified mnemonic
+    if (tbr == 268) { fix = "tbl"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else if (tbr == 269) { fix = "tbu"; o->iclass |= PPC_DISA_SIMPLIFIED; }
+    else { fix = "tb"; f = 0; }
+
+    // Mnemonics and operands.
+    sprintf (o->mnemonic, "mf%s", fix);
+    if (f)
+    {
+        sprintf (o->operands, "%s", regname[DIS_RD]);
+        o->r[0] = DIS_RD;
+    }
+    else
+    {
+        sprintf (o->operands, "%s" COMMA "%s", regname[DIS_RD], tbr_name(tbr));
+        o->r[0] = DIS_RD;
+        o->r[1] = tbr;
+    }
+}
+
+static void srawi(void)
+{
+    int rs = DIS_RS, ra = DIS_RA, sh = DIS_RB;
+    sprintf (o->mnemonic, "srawi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh);
+    o->r[0] = ra;
+    o->r[1] = rs;
+    o->r[2] = sh;
+    o->iclass = PPC_DISA_INTEGER;
+}
+
+static void sradi(void)
+{
+    int rs = DIS_RS, ra = DIS_RA, sh = (((Instr >> 1) & 1) << 5) | DIS_RB;
+    sprintf (o->mnemonic, "sradi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[ra], regname[rs], sh);
+    o->r[0] = ra;
+    o->r[1] = rs;
+    o->r[2] = sh;
+    o->iclass = PPC_DISA_INTEGER | PPC_DISA_64;
+}
+
+static void lsswi(char *name)
+{
+    int rd = DIS_RD, ra = DIS_RA, nb = DIS_RB;
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%s" COMMA "%s" COMMA "%i", regname[rd], regname[ra], nb);
+    o->r[0] = rd;
+    o->r[1] = ra;
+    o->r[2] = nb;
+    o->iclass = PPC_DISA_LDST | PPC_DISA_STRING;
+}
+
+#define FPU_DAB     1
+#define FPU_DB      2
+#define FPU_DAC     3
+#define FPU_DACB    4
+#define FPU_D       5
+
+static void fpu(char *name, u32 mask, int type, int flag=PPC_DISA_OTHER)
+{
+    int d = DIS_RD, a = DIS_RA, c = DIS_RC, b = DIS_RB;
+
+    if(Instr & mask) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+
+    switch (type)
+    {
+        case FPU_DAB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b);
+            o->r[0] = d; o->r[1] = a; o->r[2] = b;
+            break;
+        case FPU_DB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b);
+            o->r[0] = d; o->r[1] = b;
+            break;
+        case FPU_DAC:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c);
+            o->r[0] = d; o->r[1] = a; o->r[2] = c;
+            break;
+        case FPU_DACB:
+            sprintf (o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b);
+            o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b;
+            break;
+        case FPU_D:
+            sprintf (o->operands, "%s%i", fregname, d);
+            o->r[0] = d;
+            break;
+    }
+    
+    o->iclass = PPC_DISA_FPU | flag;
+}
+
+static void fcmp(char *name)
+{
+    int crfd = DIS_RD >> 2, ra = DIS_RA, rb = DIS_RB;
+
+    if (Instr & 0x00600001) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%i" COMMA "%s%i" COMMA "%s%i", crfd, fregname, ra, fregname, rb);
+    o->r[0] = crfd; o->r[1] = ra; o->r[2] = rb;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsf(void)
+{
+    int fm = (Instr >> 17) & 0xFF, rb = DIS_RB;
+
+    if(Instr & 0x02010000) { ill(); return; }
+
+    sprintf (o->mnemonic, "mtfsf%c", Rc ? '.' : 0);
+    sprintf (o->operands, HEX1 "%02X" HEX2 COMMA "%s%i", fm, fregname, rb);
+    o->r[0] = fm; o->r[1] = rb;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsb(char *name)
+{
+    int crbd = DIS_RD;
+
+    if (Instr & 0x001FF800) { ill(); return; }
+
+    strcpy (o->mnemonic, name);
+    sprintf (o->operands, "%i", crbd);
+    o->r[0] = crbd;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mcrfs(void)
+{
+    int crfD = DIS_RD >> 2, crfS = DIS_RA >> 2;
+
+    if (Instr & 0x0063F801) { ill(); return; }
+
+    strcpy (o->mnemonic, "mcrfs");
+    sprintf (o->operands, "%s%i" COMMA "%s%i", crname, crfD, crname, crfS);
+    o->r[0] = crfD; o->r[1] = crfS;
+    o->iclass = PPC_DISA_FPU;
+}
+
+static void mtfsfi(void)
+{
+    int crfD = DIS_RD >> 2, imm = DIS_RB >> 1;
+
+    if (Instr & 0x007F0800) { ill(); return; }
+
+    sprintf (o->mnemonic, "mtfsfi%c", Rc ? '.' : 0);
+    sprintf (o->operands, "%s%i" COMMA "%i", crname, crfD, imm);
+    o->r[0] = crfD; o->r[1] = imm;
+    o->iclass = PPC_DISA_FPU;
+}
+
+/*
+ ***********************************************************************************
+ * Architecture-specific extensions: 
+ * Processor model: GEKKO
+ ***********************************************************************************
+*/
+
+#ifdef  GEKKO
+
+static void ps_cmpx(int n)
+{
+    static char *fix[] = { "u0", "o0", "u1", "o1" };
+    if(Instr & 0x00600001) { ill(); return; }
+    sprintf(o->mnemonic, "ps_cmp%s", fix[n]);
+    o->r[0] = DIS_RD>>2; o->r[1] = DIS_RA; o->r[2] = DIS_RB;
+    sprintf(o->operands, "%s%d" COMMA "%s%d" COMMA "%s%d", crname, o->r[0], fregname, o->r[1], fregname, o->r[2]);
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC; 
+}
+
+static char *ps_ldst_offs(unsigned long val)
+{
+    static char buf[8];
+
+    if(val == 0)
+    {
+        return "0";
+    }
+    else
+    {
+        if(val <= 128)
+        {
+            sprintf(buf, "%i", val);
+            return buf;
+        }
+
+        if(val & 0x800) sprintf(buf, "-" HEX1 "%03X" HEX2, ((~val) & 0xfff) + 1);
+        else sprintf(buf, HEX1 "%03X" HEX2, val);
+
+        return buf;
+    }
+}
+
+static void ps_ldst(char *fix)
+{
+  int s = DIS_RS, a = DIS_RA, d = (Instr & 0xfff);
+  sprintf(o->mnemonic, "psq_%s", fix);  
+  sprintf( o->operands, "%s%i" COMMA "%s" LPAREN "%s" RPAREN COMMA "%i" COMMA "%i",
+           fregname, s, ps_ldst_offs(d), regname[a], (Instr >> 15) & 1, (Instr >> 12) & 7 );
+  o->r[0] = s; o->r[1] = a; o->r[2] = DIS_RB >> 1;
+  o->immed = d & 0x800 ? d | 0xFFFFF000 : d;
+  o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC;
+}
+
+static void ps_ldstx(char *fix)
+{
+    int d = DIS_RD, a = DIS_RA, b = DIS_RB;
+    if(Instr & 1) { ill(); return; }
+    sprintf(o->mnemonic, "psq_%s", fix);
+    sprintf(o->operands, "%s%i" COMMA "%s" COMMA "%s" COMMA "%i" COMMA "%i", fregname, d, regname[a], regname[b], (Instr >> 10) & 1, (Instr >> 7) & 7);
+    o->r[0] = d; o->r[1] = a; o->r[2] = b; o->r[3] = DIS_RC >> 1;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_LDST | PPC_DISA_SPECIFIC; 
+}
+
+static void ps_dacb(char *fix)
+{
+    int a = DIS_RA, b = DIS_RB, c = DIS_RC, d = DIS_RD;
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c, fregname, b);
+    o->r[0] = d; o->r[1] = a; o->r[2] = c; o->r[3] = b; 
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_dac(char *fix)
+{
+    int a = DIS_RA, c = DIS_RC, d = DIS_RD;
+    if(Instr & 0x0000F800) { ill(); return; }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, c);
+    o->r[0] = d; o->r[1] = a; o->r[2] = c;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_dab(char *fix, int unmask=0)
+{
+    int d = DIS_RD, a = DIS_RA, b = DIS_RB;
+    if(Instr & 0x000007C0 && !unmask) { ill(); return; }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i" COMMA "%s%i", fregname, d, fregname, a, fregname, b);
+    o->r[0] = d; o->r[1] = a; o->r[2] = b;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+static void ps_db(char *fix, int aonly=0)
+{
+    int d = DIS_RD, b = DIS_RB;
+    if(aonly) { if(Instr & 0x001F0000) { ill(); return; } }
+    else  { if(Instr & 0x001F07C0) { ill(); return; } }
+    sprintf(o->mnemonic, "ps_%s%c", fix, Rc ? '.' : 0);
+    sprintf(o->operands, "%s%i" COMMA "%s%i", fregname, d, fregname, b);
+    o->r[0] = d; o->r[1] = b;
+    o->iclass = PPC_DISA_FPU | PPC_DISA_SPECIFIC;
+}
+
+#endif  /* END OF GEKKO */
+
+// ---------------------------------------------------------------------------
+
+void PPCDisasm(PPCD_CB *discb)
+{
+    // Save parameters in local variables for static calls
+    o = discb;
+    if(o == NULL) return;
+
+    // Detect endianness order.
+    if(bigendian == -1)
+    {
+        u8 test_value[2] = { 0xAA, 0xBB };
+        u16 *value = (u16 *)test_value;
+        if(*value == 0xAABB) bigendian = 1;
+        else bigendian = 0;
+    }
+
+    // Reset output parameters
+    o->iclass = PPC_DISA_OTHER;
+    o->r[0] = o->r[1] = o->r[2] = o->r[3] = 0;
+    o->immed = 0;
+    o->target = 0;
+    o->mnemonic[0] = o->operands[0] = '\0';
+
+    // Lets go!
+
+    /*
+     * Main table
+    */
+
+    switch(Instr >> 26 /* Main opcode, base 8 */) {
+#ifdef POWERPC_64
+        case 002: trap(1, 1); break;                                        // tdi
+#endif
+        case 003: trap(0, 1); break;                                        // twi
+        case 007: integer("mulli", 'D', DAB_D|DAB_A); break;                // mulli
+        case 010: integer("subfic", 'D', DAB_D|DAB_A); break;               // subfic
+        case 012: cmp("l", "i"); break;                                     // cmpli
+        case 013: cmp("", "i"); break;                                      // cmpi
+        case 014: addi("c"); break;                                         // addic
+        case 015: addi("c."); break;                                        // addic.
+        case 016: addi(""); break;                                          // addi
+        case 017: addi("s"); break;                                         // addis
+        case 020: bcx(1, 0); break;                                         // bcx
+        case 021: put("sc", 0x03ffffff, 2); break;                          // sc
+        case 022: bx(); break;                                              // bx
+        case 024: rlw("imi", 0, 1); break;                                  // rlwimix
+        case 025: rlw("inm", 0); break;                                     // rlwinmx
+        case 027: rlw("nm", 1); break;                                      // rlwnmx
+        case 030:                                                           // ori
+#ifdef SIMPLIFIED
+                  if(Instr == 0x60000000) put("nop", 0, 0, PPC_DISA_INTEGER | PPC_DISA_SIMPLIFIED);
+                  else
+#endif
+                  integer("ori", 'S', ASB_A|ASB_S, 1, 0); break;
+        case 031: integer("oris", 'S', ASB_A|ASB_S, 1, 0); break;           // oris
+        case 032: integer("xori", 'S', ASB_A|ASB_S, 1, 0); break;           // xori
+        case 033: integer("xoris", 'S', ASB_A|ASB_S, 1, 0); break;          // xoris
+        case 034: integer("andi.", 'S', ASB_A|ASB_S, 1, 0); break;          // andi.
+        case 035: integer("andis.", 'S', ASB_A|ASB_S, 1, 0); break;         // andis.
+        case 040: ldst("lwz", 0, 1); break;                                 // lwz
+        case 041: ldst("lwzu", 0, 1); break;                                // lwzu
+        case 042: ldst("lbz", 0, 1); break;                                 // lbz
+        case 043: ldst("lbzu", 0, 1); break;                                // lbzu
+        case 044: ldst("stw", 0, 0); break;                                 // stw
+        case 045: ldst("stwu", 0, 0); break;                                // stwu
+        case 046: ldst("stb", 0, 0); break;                                 // stb
+        case 047: ldst("stbu", 0, 0); break;                                // stbu
+        case 050: ldst("lhz", 0, 1); break;                                 // lhz
+        case 051: ldst("lhzu", 0, 1); break;                                // lhzu
+        case 052: ldst("lha", 0, 1); break;                                 // lha
+        case 053: ldst("lhau", 0, 1); break;                                // lhau
+        case 054: ldst("sth", 0, 0); break;                                 // sth
+        case 055: ldst("sthu", 0, 0); break;                                // sthu
+        case 056: ldst("lmw", 0, 1, 0, 1); break;                           // lmw
+        case 057: ldst("stmw", 0, 0, 0, 1); break;                          // stmw
+        case 060: ldst("lfs", 0, 1, 0, 0, 1); break;                        // lfs
+        case 061: ldst("lfsu", 0, 1, 0, 0, 1); break;                       // lfsu
+        case 062: ldst("lfd", 0, 1, 0, 0, 1); break;                        // lfd
+        case 063: ldst("lfdu", 0, 1, 0, 0, 1); break;                       // lfdu
+        case 064: ldst("stfs", 0, 0, 0, 0, 1); break;                       // stfs
+        case 065: ldst("stfsu", 0, 0, 0, 0, 1); break;                      // stfsu
+        case 066: ldst("stfd", 0, 0, 0, 0, 1); break;                       // stfd
+        case 067: ldst("stfdu", 0, 0, 0, 0, 1); break;                      // stfdu
+
+    /*
+     * Extention 1.
+    */
+
+        case 023:
+    switch((Instr >> 1) & 0x3ff /* Extended opcode 023, base 8 */) {
+        case 00020: bcx(0, 1); break;                                       // bclrx
+        case 01020: bcx(0, 0); break;                                       // bcctrx
+        case 00000: mcrf(); break;                                          // mcrf
+        case 00401: crop("and"); break;                                     // crand
+        case 00201: crop("andc"); break;                                    // crandc
+        case 00441: crop("eqv", "set", 1); break;                           // creqv
+        case 00341: crop("nand"); break;                                    // crnand
+        case 00041: crop("nor", "not", 0, 1); break;                        // crnor
+        case 00701: crop("or", "move", 0, 1); break;                        // cror
+        case 00641: crop("orc"); break;                                     // crorc
+        case 00301: crop("xor", "clr", 1); break;                           // crxor
+        case 00226: put("isync", 0x3fff801); break;                         // isync
+#ifdef  POWERPC_32
+        case 00062: put("rfi", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_BRIDGE ); break; // rfi
+#endif
+#ifdef  POWERPC_64
+        case 00022: put("rfid", 0x3fff801, 0, PPC_DISA_OEA | PPC_DISA_64 ); break; // rfid
+#endif
+        default: ill(); break;
+    } break;
+
+#ifdef  POWERPC_64
+        case 036:
+    switch((Instr >> 1) & 0xf /* Rotate left double */) {
+        case 0x0: rld("icl", 0, RLDM_LEFT); break;                          // rldiclx
+        case 0x1: rld("icl", 0, RLDM_LEFT); break;
+        case 0x2: rld("icr", 0, RLDM_RIGHT); break;                         // rldicrx
+        case 0x3: rld("icr", 0, RLDM_RIGHT); break;
+        case 0x4: rld("ic",  0, RLDM_INS); break;                           // rldicx
+        case 0x5: rld("ic",  0, RLDM_INS); break;
+        case 0x6: rld("imi", 0, RLDM_INS); break;                           // rldimix
+        case 0x7: rld("imi", 0, RLDM_INS); break;
+        case 0x8: rld("cl",  1, RLDM_LEFT); break;                          // rldclx
+        case 0x9: rld("cr",  1, RLDM_RIGHT); break;                         // rldcrx
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 2.
+    */
+
+        #define OE 02000
+        case 037:
+    switch(Instr & 0x7ff /* Extended opcode 037, base 8 */) {
+        case 00000: cmp("", ""); break;                                     // cmp
+        case 00010:                                                         // tw
+#ifdef SIMPLIFIED
+                    if(Instr == 0x7FE00008) put("trap", 0, 0, PPC_DISA_SIMPLIFIED);
+                    else
+#endif
+                    trap(0, 0); break;
+        case 00020: integer("subfc", 'X', DAB_D|DAB_A|DAB_B); break;        // subfcx
+        case 00020|OE: integer("subfco", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00021: integer("subfc.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00021|OE: integer("subfco.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00024: integer("addc", 'X', DAB_D|DAB_A|DAB_B); break;         // addcx
+        case 00024|OE: integer("addco", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00025: integer("addc.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00025|OE: integer("addco.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00026: integer("mulhwu", 'X', DAB_D|DAB_A|DAB_B); break;       // mulhwu
+        case 00027: integer("mulhwu.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00046: if(DIS_RA | DIS_RB) ill();                              // mfcr
+                    else { integer("mfcr", 'D', DAB_D, 0,0,0,0,0); o->iclass = PPC_DISA_OTHER; } break;
+        case 00050: ldst("lwarx", 1); break;                                // lwarx
+        case 00056: ldst("lwzx", 1); break;                                 // lwzx
+        case 00060: integer("slw", 'Z', ASB_A|ASB_S|ASB_B); break;          // slwx
+        case 00061: integer("slw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00064: if(DIS_RB) ill();                                       // cntlzwx
+                    else integer("cntlzw", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 00065: if(DIS_RB) ill();
+                    else integer("cntlzw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 00070: integer("and", 'Z', ASB_A|ASB_S|ASB_B); break;          // andx
+        case 00071: integer("and.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00100: cmp("l", ""); break;                                    // cmpl
+        case 00120: integer("subf", 'X', DAB_D|DAB_A|DAB_B); break;         // subfx
+        case 00120|OE: integer("subfo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00121: integer("subf.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00121|OE: integer("subfo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00154: cache("dcbst"); break;                                  // dcbst
+        case 00156: ldst("lwzux", 1); break;                                // lwzux
+        case 00170: integer("andc", 'Z', ASB_A|ASB_S|ASB_B); break;         // andcx
+        case 00171: integer("andc.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00226: integer("mulhw", 'X', DAB_D|DAB_A|DAB_B); break;        // mulhw
+        case 00227: integer("mulhw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00246: if(DIS_RA || DIS_RB) ill();                             // mfmsr
+                    else { integer("mfmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA; } break;
+        case 00254: cache("dcbf"); break;                                   // dcbf
+        case 00256: ldst("lbzx", 1, 1, 0); break;                           // lbzx
+        case 00320: if(DIS_RB) ill();                                       // negx
+                    else integer("neg", 'X', DAB_D|DAB_A); break;
+        case 00321: if(DIS_RB) ill();
+                    else integer("neg.", 'X', DAB_D|DAB_A); break;
+        case 00320|OE: if(DIS_RB) ill();
+                    else integer("nego", 'X', DAB_D|DAB_A); break;
+        case 00321|OE: if(DIS_RB) ill();
+                    else integer("nego.", 'X', DAB_D|DAB_A); break;
+        case 00356: ldst("lbzux", 1, 1); break;                             // lbzux
+        case 00370:                                                         // norx
+#ifdef SIMPLIFIED
+                    if(DIS_RS == DIS_RB) { integer("not", 'Z', ASB_A|ASB_S); o->iclass |= PPC_DISA_SIMPLIFIED; }
+                    else
+#endif
+                    integer("nor", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00371: integer("nor.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 00420: integer("subfe", 'X', DAB_D|DAB_A|DAB_B); break;        // subfex
+        case 00420|OE: integer("subfeo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00421: integer("subfe.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00421|OE: integer("subfeo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00424: integer("adde", 'X', DAB_D|DAB_A|DAB_B); break;         // addex
+        case 00424|OE: integer("addeo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00425: integer("adde.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00425|OE: integer("addeo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00440: mtcrf(); break;                                         // mtcrf
+#ifdef POWERPC_32
+        case 00444: if(DIS_RA || DIS_RB) ill();                             // mtmsr
+                    else { integer("mtmsr", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_BRIDGE; } break;
+#endif
+        case 00455: ldst("stwcx.", 1, 0, 0); break;                         // stwcx.
+        case 00456: ldst("stwx", 1, 0, 0); break;                           // stwx
+        case 00556: ldst("stwux", 1, 0, 0); break;                          // stwux
+        case 00620: if(DIS_RB) ill();                                       // subfzex
+                    else integer("subfze", 'X', DAB_D|DAB_A); break;
+        case 00620|OE: if(DIS_RB) ill();
+                    else integer("subfzeo", 'X', DAB_D|DAB_A); break;
+        case 00621: if(DIS_RB) ill();
+                    else integer("subfze.", 'X', DAB_D|DAB_A); break;
+        case 00621|OE: if(DIS_RB) ill();
+                    else integer("subfzeo.", 'X', DAB_D|DAB_A); break;
+        case 00624: if(DIS_RB) ill();                                       // addzex
+                    else integer("addze", 'X', DAB_D|DAB_A); break;
+        case 00624|OE: if(DIS_RB) ill();
+                    else integer("addzeo", 'X', DAB_D|DAB_A); break;
+        case 00625: if(DIS_RB) ill();
+                    else integer("addze.", 'X', DAB_D|DAB_A); break;
+        case 00625|OE: if(DIS_RB) ill();
+                    else integer("addzeo.", 'X', DAB_D|DAB_A); break;
+#ifdef POWERPC_32
+        case 00644: movesr("mtsr", 0, 0, 0); break;                         // mtsr
+#endif
+        case 00656: ldst("stbx", 1, 0, 0); break;                           // stbx
+        case 00720: if(DIS_RB) ill();                                       // subfmex
+                    else integer("subfme", 'X', DAB_D|DAB_A); break;
+        case 00720|OE: if(DIS_RB) ill();
+                    else integer("subfmeo", 'X', DAB_D|DAB_A); break;
+        case 00721: if(DIS_RB) ill();
+                    else integer("subfme.", 'X', DAB_D|DAB_A); break;
+        case 00721|OE: if(DIS_RB) ill();
+                    else integer("subfmeo.", 'X', DAB_D|DAB_A); break;
+        case 00724: if(DIS_RB) ill();                                       // addmex
+                    else integer("addme", 'X', DAB_D|DAB_A); break;
+        case 00724|OE: if(DIS_RB) ill();
+                    else integer("addmeo", 'X', DAB_D|DAB_A); break;
+        case 00725: if(DIS_RB) ill();
+                    else integer("addme.", 'X', DAB_D|DAB_A); break;
+        case 00725|OE: if(DIS_RB) ill();
+                    else integer("addmeo.", 'X', DAB_D|DAB_A); break;
+        case 00726: integer("mullw", 'X', DAB_D|DAB_A|DAB_B); break;        // mullwx
+        case 00726|OE: integer("mullwo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00727: integer("mullw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 00727|OE: integer("mullwo.", 'X', DAB_D|DAB_A|DAB_B); break;
+#ifdef POWERPC_32
+        case 00744: movesr("mtsrin", 0, 0, 1); break;                       // mtsrin
+#endif
+        case 00754: cache("dcbtst"); break;                                 // dcbtst
+        case 00756: ldst("stbux", 1, 0, 0); break;                          // stbux
+        case 01024: integer("add", 'X', DAB_D|DAB_A|DAB_B); break;          // addx
+        case 01024|OE: integer("addo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01025: integer("add.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01025|OE: integer("addo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01054: cache("dcbt"); break;                                   // dcbt
+        case 01056: ldst("lhzx", 1); break;                                 // lhzx
+        case 01070: integer("eqv", 'Z', ASB_A|ASB_S|ASB_B); break;          // eqvx
+        case 01071: integer("eqv.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01144: if(DIS_RD || DIS_RA) ill();                             // tlbie
+                    else { integer("tlbie", 'X', DAB_B); o->iclass = PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break;
+        case 01154: integer("eciwx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // eciwx
+        case 01156: ldst("lhzux", 1); break;                                // lhzux
+        case 01170: integer("xor", 'Z', ASB_A|ASB_S|ASB_B); break;          // xorx
+        case 01171: integer("xor.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01246: movespr(1); break;                                      // mfspr
+        case 01256: ldst("lhax", 1); break;                                 // lhax
+#if !defined(GEKKO)
+        case 01344: put("tlbia", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbia
+#endif
+        case 01346: movetbr(); break;                                       // mftb
+        case 01356: ldst("lhaux", 1); break;                                // lhaux
+        case 01456: ldst("sthx", 1, 0); break;                              // sthx
+        case 01470: integer("orc", 'Z', ASB_A|ASB_S|ASB_B); break;          // orcx
+        case 01471: integer("orc.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01554: integer("ecowx", 'X', DAB_D|DAB_A|DAB_B); o->iclass = PPC_DISA_OPTIONAL; break; // ecowx
+        case 01556: ldst("sthux", 1, 0); break;                             // sthux
+        case 01570: integer("or", 'Z', ASB_A|ASB_S|ASB_B); break;           // orx
+        case 01571: integer("or.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01626: integer("divwu", 'X', DAB_D|DAB_A|DAB_B); break;        // divwux
+        case 01626|OE: integer("divwuo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01627: integer("divwu.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01627|OE: integer("divwuo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01646: movespr(0); break;                                      // mtspr
+        case 01654: cache("dcbi", PPC_DISA_OEA); break;                     // dcbi
+        case 01670: integer("nand", 'Z', ASB_A|ASB_S|ASB_B); break;         // nandx
+        case 01671: integer("nand.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 01726: integer("divw", 'X', DAB_D|DAB_A|DAB_B); break;         // divwx
+        case 01726|OE: integer("divwo", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01727: integer("divw.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 01727|OE: integer("divwo.", 'X', DAB_D|DAB_A|DAB_B); break;
+        case 02000: mcrxr(); break;                                         // mcrxr
+        case 02052: ldst("lswx", 1, 1, 0, 1); break;                        // lswx
+        case 02054: ldst("lwbrx", 1); break;                                // lwbrx
+        case 02056: ldst("lfsx", 1, 1, 0, 0, 1); break;                     // lfsx
+        case 02060: integer("srw", 'Z', ASB_A|ASB_S|ASB_B); break;          // srwx
+        case 02061: integer("srw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 02154: put("tlbsync", 0x03FFF800, 0, PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // tlbsync
+        case 02156: ldst("lfsux", 1, 1, 0, 0, 1); break;                    // lfsux
+#ifdef POWERPC_32
+        case 02246: movesr("mfsr", 1, 0, 0); break;                         // mfsr
+#endif
+        case 02252: lsswi("lswi"); break;                                   // lswi
+        case 02254: put("sync", 0x03FFF800, 0); break;                      // sync
+        case 02256: ldst("lfdx", 1, 1, 0, 0, 1); break;                     // lfdx
+        case 02356: ldst("lfdux", 1, 1, 0, 0, 1); break;                    // lfdux
+#ifdef POWERPC_32
+        case 02446: movesr("mfsrin", 1, 0, 1); break;                       // mfsrin
+#endif
+        case 02452: ldst("stswx", 1, 1, 0, 1); break;                       // stswx
+        case 02454: ldst("stwbrx", 1, 0); break;                            // stwbrx
+        case 02456: ldst("stfsx", 1, 1, 0, 0, 1); break;                    // stfsx
+        case 02556: ldst("stfsux", 1, 1, 0, 0, 1); break;                   // stfsux
+        case 02652: lsswi("stswi"); break;                                  // stswi
+        case 02656: ldst("stfdx", 1, 1, 0, 0, 1); break;                    // stfdx
+#if !defined(GEKKO)
+        case 02754: cache("dcba", PPC_DISA_OPTIONAL); break;                // dcba
+#endif
+        case 02756: ldst("stfdux", 1, 1, 0, 0, 1); break;                   // stfdux
+        case 03054: ldst("lhbrx", 1); break;                                // lhbrx
+        case 03060: integer("sraw", 'Z', ASB_A|ASB_S|ASB_B); break;         // srawx
+        case 03061: integer("sraw.", 'Z', ASB_A|ASB_S|ASB_B); break;
+        case 03160: srawi(); break;                                         // srawi
+        case 03161: srawi(); break;
+        case 03254: put("eieio", 0x03FFF800, 0); break;                     // eieio
+        case 03454: ldst("sthbrx", 1, 0); break;                            // sthbrx
+        case 03464: if(DIS_RB) ill();                                       // extshx
+                    else integer("extsh", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03465: if(DIS_RB) ill();
+                    else integer("extsh.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03564: if(DIS_RB) ill();                                       // extsbx
+                    else integer("extsb", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03565: if(DIS_RB) ill();
+                    else integer("extsb.", 'S', ASB_A|ASB_S, 0,0,0,0,0); break;
+        case 03654: cache("icbi"); break;                                   // icbi
+        case 03656: ldst("stfiwx", 1, 1, 0, 0, 1); o->iclass |= PPC_DISA_OPTIONAL; break; // stfiwx
+        case 03754: cache("dcbz"); break;                                   // dcbz
+#ifdef POWERPC_64
+        case 00022: integer("mulhdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdux
+        case 00023: integer("mulhdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00052: ldst("ldx", 1, 1, 1); break;                            // ldx
+        case 00066: integer("sld", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sldx
+        case 00067: integer("sld.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 00152: ldst("ldux", 1, 1, 1); break;                           // ldux
+        case 00164: if(DIS_RB) ill();                                       // cntlzdx
+                    else integer("cntlzd", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+        case 00165: if(DIS_RB) ill();
+                    else integer("cntlzd.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; break;
+        case 00210: trap(1, 0); break;
+        case 00222: integer("mulhd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulhdx
+        case 00223: integer("mulhd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00244: movesr("mtsrd", 0, 1, 0); break;                        // mtrsd
+        case 00250: ldst("ldarx", 1, 1, 1); break;                          // ldarx
+        case 00344: movesr("mtsrdin", 0, 1, 1); break;                      // mtrsdin
+        case 00452: ldst("stdx", 1, 0, 1); break;                           // stdx
+        case 00544: if(DIS_RA || DIS_RB) ill();                             // mtmsrd
+                    else { integer("mtmsrd", 'X', DAB_D); o->iclass = PPC_DISA_OEA | PPC_DISA_64; } break;
+        case 00552: ldst("stdux", 1, 0, 1); break;                          // stdux
+        case 00655: ldst("stdcx.", 1, 0, 1); break;                         // stdcx.
+        case 00722: integer("mulld", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // mulldx
+        case 00722|OE: integer("mulldo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00723: integer("mulld.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 00723|OE: integer("mulldo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01252: ldst("lwax", 1, 1, 1); break;                           // lwax
+        case 01352: ldst("lwaux", 1, 1, 1); break;                          // lwaux
+        case 03164: sradi(); break;                                         // sradi
+        case 03165: sradi(); break;
+        case 03166: sradi(); break;
+        case 03167: sradi(); break;
+        case 01544: if(DIS_RD || DIS_RA) ill();                             // slbie
+                    else { integer("slbie", 'X', DAB_B); o->iclass = PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL; o->r[0] = o->r[2]; o->r[2] = 0; } break;
+        case 01622: integer("divdu", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdux
+        case 01622|OE: integer("divduo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01623: integer("divdu.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01623|OE: integer("divduo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01722: integer("divd", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break; // divdx
+        case 01722|OE: integer("divdo", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01723: integer("divd.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01723|OE: integer("divdo.", 'X', DAB_D|DAB_A|DAB_B); o->iclass |= PPC_DISA_64; break;
+        case 01744: put("slbia", 0x03FFF800, 0, PPC_DISA_64 | PPC_DISA_OEA | PPC_DISA_OPTIONAL); break; // slbia
+        case 02066: integer("srd", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // srdx
+        case 02067: integer("srd.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 03064: integer("srad", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break; // sradx
+        case 03065: integer("srad.", 'Z', ASB_A|ASB_S|ASB_B); o->iclass |= PPC_DISA_64; break;
+        case 03664: if(DIS_RB) ill();                                       // extswx
+                    else { integer("extsw", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; } break;
+        case 03665: if(DIS_RB) ill();
+                    else { integer("extsw.", 'S', ASB_A|ASB_S, 0,0,0,0,0); o->iclass |= PPC_DISA_64; } break;
+#endif
+        default: ill(); break;
+    } break;
+
+    /*
+     * Extention 3.
+    */
+
+#ifdef POWERPC_64
+        case 072:
+    switch(Instr & 3) {
+        case 0: Instr &= ~3; ldst("ld", 0, 1, 1); break;                    // ld
+        case 1: Instr &= ~3; ldst("ldu", 0, 1, 1); break;                   // ldu
+        case 2: Instr &= ~3; ldst("lwa", 0, 1, 1); break;                   // lwa
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 4.
+    */
+
+    #define MASK_D  (0x1F << 21)
+    #define MASK_A  (0x1F << 16)
+    #define MASK_B  (0x1F << 11)
+    #define MASK_C  (0x1F <<  6)
+        case 073:
+    switch(Instr & 0x3F) {
+        case 044: fpu("fdivs", MASK_C, FPU_DAB); break;                     // fdivsx
+        case 045: fpu("fdivs.", MASK_C, FPU_DAB); break;
+        case 050: fpu("fsubs", MASK_C, FPU_DAB); break;                     // fsubsx
+        case 051: fpu("fsubs.", MASK_C, FPU_DAB); break;
+        case 052: fpu("fadds", MASK_C, FPU_DAB); break;                     // faddsx
+        case 053: fpu("fadds.", MASK_C, FPU_DAB); break;
+#if !defined(GEKKO)
+        case 054: fpu("fsqrts", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtsx
+        case 055: fpu("fsqrts.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+#endif
+        case 060: fpu("fres", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fresx
+        case 061: fpu("fres.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+        case 062: fpu("fmuls", MASK_B, FPU_DAC); break;                     // fmulsx
+        case 063: fpu("fmuls.", MASK_B, FPU_DAC); break;
+        case 070: fpu("fmsubs", 0, FPU_DACB); break;                        // fmsubsx
+        case 071: fpu("fmsubs.", 0, FPU_DACB); break;
+        case 072: fpu("fmadds", 0, FPU_DACB); break;                        // fmaddsx
+        case 073: fpu("fmadds.", 0, FPU_DACB); break;
+        case 074: fpu("fnmsubs", 0, FPU_DACB); break;                       // fnmsubsx
+        case 075: fpu("fnmsubs.", 0, FPU_DACB); break;
+        case 076: fpu("fnmadds", 0, FPU_DACB); break;                       // fnmaddsx
+        case 077: fpu("fnmadds.", 0, FPU_DACB); break;
+        default: ill(); break;
+    } break;
+
+    /*
+     * Extention 5.
+    */
+
+#ifdef POWERPC_64
+        case 076:
+    switch(Instr & 3) {
+        case 0: Instr &= ~3; ldst("std", 0, 0, 1); break;                   // std
+        case 1: Instr &= ~3; ldst("stdu", 0, 0, 1); break;                  // stdu
+        default: ill(); break;
+    } break;
+#endif
+
+    /*
+     * Extention 6.
+    */
+
+        case 077:
+    switch(Instr & 0x3F) {
+        case 000:
+        switch(DIS_RC)
+        {
+            case 0: fcmp("fcmpu"); break;                                   // fcmpu
+            case 1: fcmp("fcmpo"); break;                                   // fcmpo
+            case 2: mcrfs(); break;                                         // mcrfs
+            default: ill(); break;
+        }
+        break;
+        case 014:
+        switch(DIS_RC)
+        {
+            case 1: mtfsb("mtfsb1"); break;                                 // mtfsb1
+            case 2: mtfsb("mtfsb0"); break;                                 // mtfsb0
+            case 4: mtfsfi(); break;                                        // mtfsfi
+            default: ill(); break;
+        }
+        break;
+        case 015:
+        switch(DIS_RC)
+        {
+            case 1: mtfsb("mtfsb1."); break;                                // mtfsb1.
+            case 2: mtfsb("mtfsb0."); break;                                // mtfsb0.
+            case 4: mtfsfi(); break;                                        // mtfsfi.
+            default: ill(); break;
+        }
+        break;
+        case 016:
+        switch(DIS_RC)
+        {
+            case 18: fpu("mffs", MASK_A|MASK_B, FPU_D); break;              // mffs
+            case 22: mtfsf(); break;                                        // mtfsf
+            default: ill(); break;
+        }
+        break;
+        case 017:
+        switch(DIS_RC)
+        {
+            case 18: fpu("mffs.", MASK_A|MASK_B, FPU_D); break;             // mffs.
+            case 22: mtfsf(); break;                                        // mtfsf.
+            default: ill(); break;
+        }
+        break;
+        case 020:
+        switch(DIS_RC)
+        {
+            case 1: fpu("fneg", MASK_A, FPU_DB); break;                     // fneg
+            case 2: fpu("fmr", MASK_A, FPU_DB); break;                      // fmr
+            case 4: fpu("fnabs", MASK_A, FPU_DB); break;                    // fnabs
+            case 8: fpu("fabs", MASK_A, FPU_DB); break;                     // fabs
+            default: ill(); break;
+        }
+        break;
+        case 021:
+        switch(DIS_RC)
+        {
+            case 1: fpu("fneg.", MASK_A, FPU_DB); break;                    // fneg
+            case 2: fpu("fmr.", MASK_A, FPU_DB); break;                     // fmr
+            case 4: fpu("fnabs.", MASK_A, FPU_DB); break;                   // fnabs
+            case 8: fpu("fabs.", MASK_A, FPU_DB); break;                    // fabs
+            default: ill(); break;
+        }
+        break;
+        case 030:
+        switch(DIS_RC)
+        {
+            case 0: fpu("frsp", MASK_A, FPU_DB); break;                     // frsp
+            default: ill(); break;
+        }
+        break;
+        case 031:
+        switch(DIS_RC)
+        {
+            case 0: fpu("frsp.", MASK_A, FPU_DB); break;                    // frsp.
+            default: ill(); break;
+        }
+        break;
+        case 034:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiw", MASK_A, FPU_DB); break;                    // fctiw
+#ifdef POWERPC_64
+            case 25: fpu("fctid", MASK_A, FPU_DB); break;                   // fctid
+            case 26: fpu("fcfid", MASK_A, FPU_DB); break;                   // fcfid
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 035:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiw.", MASK_A, FPU_DB); break;                   // fctiw.
+#ifdef POWERPC_64
+            case 25: fpu("fctid.", MASK_A, FPU_DB); break;                  // fctid.
+            case 26: fpu("fcfid.", MASK_A, FPU_DB); break;                  // fcfid.
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 036:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiwz", MASK_A, FPU_DB); break;                   // fctiwz
+#ifdef POWERPC_64
+            case 25: fpu("fctidz", MASK_A, FPU_DB); break;                  // fctidz
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 037:
+        switch(DIS_RC)
+        {
+            case 0: fpu("fctiwz.", MASK_A, FPU_DB); break;                  // fctiwz.
+#ifdef POWERPC_64
+            case 25: fpu("fctidz.", MASK_A, FPU_DB); break;                 // fctidz.
+#endif
+            default: ill(); break;
+        }
+        break;
+        case 044: fpu("fdiv", MASK_C, FPU_DAB); break;                      // fdivx
+        case 045: fpu("fdiv.", MASK_C, FPU_DAB); break;
+        case 050: fpu("fsub", MASK_C, FPU_DAB); break;                      // fsubx
+        case 051: fpu("fsub.", MASK_C, FPU_DAB); break;
+        case 052: fpu("fadd", MASK_C, FPU_DAB); break;                      // faddx
+        case 053: fpu("fadd.", MASK_C, FPU_DAB); break;
+#if !defined(GEKKO)
+        case 054: fpu("fsqrt", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // fsqrtx
+        case 055: fpu("fsqrt.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+#endif
+        case 056: fpu("fsel", 0, FPU_DACB, PPC_DISA_OPTIONAL); break;       // fselx
+        case 057: fpu("fsel.", 0, FPU_DACB, PPC_DISA_OPTIONAL); break;
+        case 062: fpu("fmul", MASK_B, FPU_DAC); break;                      // fmulx
+        case 063: fpu("fmul.", MASK_B, FPU_DAC); break;
+        case 064: fpu("frsqrte", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break; // frsqrtex
+        case 065: fpu("frsqrte.", MASK_A|MASK_C, FPU_DB, PPC_DISA_OPTIONAL); break;
+        case 070: fpu("fmsub", 0, FPU_DACB); break;                         // fmsubx
+        case 071: fpu("fmsub.", 0, FPU_DACB); break;
+        case 072: fpu("fmadd", 0, FPU_DACB); break;                         // fmaddx
+        case 073: fpu("fmadd.", 0, FPU_DACB); break;
+        case 074: fpu("fnmsub", 0, FPU_DACB); break;                        // fnmsubx
+        case 075: fpu("fnmsub.", 0, FPU_DACB); break;
+        case 076: fpu("fnmadd", 0, FPU_DACB); break;                        // fnmaddx
+        case 077: fpu("fnmadd.", 0, FPU_DACB); break;
+        default: ill(); break;
+    } break;
+
+    /*
+     ***********************************************************************************
+     * GEKKO Extention.
+     ***********************************************************************************
+    */
+
+#ifdef  GEKKO
+        case 004:
+            if(((Instr >> 1) & 0x3FF) == 1014)
+            {
+                cache("dcbz_l", PPC_DISA_SPECIFIC);                         // dcbz_l
+            }
+            else switch((Instr >> 1) & 0x1f)
+            {
+            case 0: ps_cmpx((Instr >> 6) & 3); break;                       // ps_cmpXX
+            case 6: if(Instr & 0x40) ps_ldstx("lux");                       // ps_lux
+                    else ps_ldstx("lx"); break;                             // ps_lx
+            case 7: if(Instr & 0x40) ps_ldstx("stux");                      // ps_stux
+                    else ps_ldstx("stx"); break;                            // ps_stx
+            case 8:
+            switch((Instr >> 6) & 0x1f)
+            {
+                case 1: ps_db("neg", 1); break;                             // ps_negx
+                case 2: ps_db("mr", 1); break;                              // ps_mrx
+                case 4: ps_db("nabs", 1); break;                            // ps_nabsx
+                case 8: ps_db("abs", 1); break;                             // ps_absx
+                default: ill(); break;
+            } break;
+            case 10: ps_dacb("sum0"); break;                                // ps_sum0x
+            case 11: ps_dacb("sum1"); break;                                // ps_sum1x
+            case 12: ps_dac("muls0"); break;                                // ps_muls0x
+            case 13: ps_dac("muls1"); break;                                // ps_muls1x
+            case 14: ps_dacb("madds0"); break;                              // ps_madds0x
+            case 15: ps_dacb("madds1"); break;                              // ps_madds1x
+            case 16:
+            switch((Instr >> 6) & 0x1f)
+            {
+                case 16: ps_dab("merge00", 1); break;                       // ps_merge00x
+                case 17: ps_dab("merge01", 1); break;                       // ps_merge11x
+                case 18: ps_dab("merge10", 1); break;                       // ps_merge10x
+                case 19: ps_dab("merge11", 1); break;                       // ps_merge11x
+                default: ill(); break;
+            } break;
+            case 18: ps_dab("div"); break;                                  // ps_divx
+            case 20: ps_dab("sub"); break;                                  // ps_subx
+            case 21: ps_dab("add"); break;                                  // ps_addx
+            case 23: ps_dacb("sel"); break;                                 // ps_selx
+            case 24: ps_db("res"); break;                                   // ps_resx
+            case 25: ps_dac("mul"); break;                                  // ps_mulx
+            case 26: ps_db("rsqrte"); break;                                // ps_rsqrtex
+            case 28: ps_dacb("msub"); break;                                // ps_msubx
+            case 29: ps_dacb("madd"); break;                                // ps_maddx
+            case 30: ps_dacb("nmsub"); break;                               // ps_nmsubx
+            case 31: ps_dacb("nmadd"); break;                               // ps_nmaddx
+            default: ill(); break;
+        } break;
+        
+        case 070: ps_ldst("l"); break;                                      // psq_l
+        case 071: ps_ldst("lu"); break;                                     // psq_lu
+        case 074: ps_ldst("st"); break;                                     // psq_st
+        case 075: ps_ldst("stu"); break;                                    // psq_stu
+#endif  /* GEKKO */
+
+        default: ill(); break;
+    }
+
+#ifdef  UPPERCASE
+    strupr(o->mnemonic);
+#endif
+}
+
+char *PPCDisasmSimple(u64 pc, u32 instr)
+{
+    PPCD_CB dis_out;
+    static char output[256];
+
+    dis_out.pc = pc;
+    dis_out.instr = instr;
+
+    PPCDisasm(&dis_out);
+    sprintf(output, "%08X  %08X  %-10s %s", pc, instr, dis_out.mnemonic, dis_out.operands);
+    return output;
+}
\ No newline at end of file
diff --git a/ppc/ppcd.h b/ppc/ppcd.h
new file mode 100644 (file)
index 0000000..2ebf794
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+/*
+ * General Data Types.
+*/
+
+typedef signed   char       s8;
+typedef signed   short      s16;
+typedef signed   long       s32;
+typedef unsigned char       u8;
+typedef unsigned short      u16;
+typedef unsigned long       u32;
+typedef float               f32;
+typedef double              f64;
+
+typedef unsigned long long  u64;
+typedef signed   long long  s64;
+
+#ifndef __cplusplus
+typedef enum { false = 0, true } bool;
+#endif
+
+#define FASTCALL    __fastcall
+#define INLINE      __inline
+
+// See some documentation in CPP file.
+
+// Instruction class
+#define PPC_DISA_OTHER      0x0000  // No additional information
+#define PPC_DISA_64         0x0001  // 64-bit architecture only
+#define PPC_DISA_INTEGER    0x0002  // Integer-type instruction
+#define PPC_DISA_BRANCH     0x0004  // Branch instruction
+#define PPC_DISA_LDST       0x0008  // Load-store instruction
+#define PPC_DISA_STRING     0x0010  // Load-store string/multiple
+#define PPC_DISA_FPU        0x0020  // Floating-point instruction
+#define PPC_DISA_OEA        0x0040  // Supervisor level
+#define PPC_DISA_OPTIONAL   0x0200  // Optional
+#define PPC_DISA_BRIDGE     0x0400  // Optional 64-bit bridge
+#define PPC_DISA_SPECIFIC   0x0800  // Implementation-specific
+#define PPC_DISA_ILLEGAL    0x1000  // Illegal
+#define PPC_DISA_SIMPLIFIED 0x8000  // Simplified mnemonic is used
+
+typedef struct PPCD_CB
+{
+    u64     pc;                     // Program counter (input)
+    u32     instr;                  // Instruction (input)
+    char    mnemonic[16];           // Instruction mnemonic.
+    char    operands[64];           // Instruction operands.
+    u32     immed;                  // Immediate value (displacement for load/store, immediate operand for arithm./logic).
+    int     r[4];                   // Index value for operand registers and immediates.
+    u64     target;                 // Target address for branch instructions / Mask for RLWINM-like instructions
+    int     iclass;                 // One or combination of PPC_DISA_* flags.
+} PPCD_CB;
+
+void    PPCDisasm(PPCD_CB *disa);
+char*   PPCDisasmSimple(u64 pc, u32 instr);