--- /dev/null
+
+#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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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");
+ }
+}
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+
+#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()
+{
+}
+
--- /dev/null
+
+#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;
+}
--- /dev/null
+// 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
--- /dev/null
+#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);