diff options
author | PCSX* teams | 2010-11-16 14:15:22 +0200 |
---|---|---|
committer | Grazvydas Ignotas | 2010-11-16 14:15:22 +0200 |
commit | ef79bbde537d6b9c745a7d86cb9df1d04c35590d (patch) | |
tree | ef8d2520dbb9e1e345b41b12c9959f300ca8fd10 /libpcsxcore/ppc | |
download | pcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.tar.gz pcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.tar.bz2 pcsx_rearmed-ef79bbde537d6b9c745a7d86cb9df1d04c35590d.zip |
pcsxr-1.9.92
Diffstat (limited to 'libpcsxcore/ppc')
-rw-r--r-- | libpcsxcore/ppc/pGte.h | 91 | ||||
-rw-r--r-- | libpcsxcore/ppc/pR3000A.c | 3540 | ||||
-rw-r--r-- | libpcsxcore/ppc/pasm.s | 124 | ||||
-rw-r--r-- | libpcsxcore/ppc/ppc.c | 32 | ||||
-rw-r--r-- | libpcsxcore/ppc/ppc.h | 60 | ||||
-rw-r--r-- | libpcsxcore/ppc/ppc_mnemonics.h | 529 | ||||
-rw-r--r-- | libpcsxcore/ppc/reguse.c | 419 | ||||
-rw-r--r-- | libpcsxcore/ppc/reguse.h | 83 |
8 files changed, 4878 insertions, 0 deletions
diff --git a/libpcsxcore/ppc/pGte.h b/libpcsxcore/ppc/pGte.h new file mode 100644 index 0000000..a968460 --- /dev/null +++ b/libpcsxcore/ppc/pGte.h @@ -0,0 +1,91 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifndef PGET_H +#define PGET_H + +#ifdef __cplusplus +extern "C" { +#endif + +int psxCP2time[64] = { + 2, 16 , 1 , 1, 1, 1 , 8, 1, // 00 + 1 , 1 , 1 , 1, 6 , 1 , 1 , 1, // 08 + 8 , 8, 8, 19, 13 , 1 , 44 , 1, // 10 + 1 , 1 , 1 , 17, 11 , 1 , 14 , 1, // 18 + 30 , 1 , 1 , 1, 1, 1 , 1 , 1, // 20 + 5 , 8 , 17 , 1, 1, 5, 6, 1, // 28 + 23 , 1 , 1 , 1, 1, 1 , 1 , 1, // 30 + 1 , 1 , 1 , 1, 1, 6 , 5 , 39 // 38 +}; + +#define CP2_FUNC(f) \ +void gte##f(); \ +static void rec##f() { \ + if (pc < cop2readypc) idlecyclecount += (cop2readypc - pc)>>2; \ + iFlushRegs(0); \ + LIW(0, (u32)psxRegs.code); \ + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + FlushAllHWReg(); \ + CALLFunc ((u32)gte##f); \ + cop2readypc = pc + psxCP2time[_fFunct_(psxRegs.code)]<<2; \ +} + +#define CP2_FUNCNC(f) \ +void gte##f(); \ +static void rec##f() { \ + if (pc < cop2readypc) idlecyclecount += (cop2readypc - pc)>>2; \ + iFlushRegs(0); \ + CALLFunc ((u32)gte##f); \ +/* branch = 2; */\ + cop2readypc = pc + psxCP2time[_fFunct_(psxRegs.code)]; \ +} + +CP2_FUNC(MFC2); +CP2_FUNC(MTC2); +CP2_FUNC(CFC2); +CP2_FUNC(CTC2); +CP2_FUNC(LWC2); +CP2_FUNC(SWC2); +CP2_FUNCNC(RTPS); +CP2_FUNC(OP); +CP2_FUNCNC(NCLIP); +CP2_FUNC(DPCS); +CP2_FUNC(INTPL); +CP2_FUNC(MVMVA); +CP2_FUNCNC(NCDS); +CP2_FUNCNC(NCDT); +CP2_FUNCNC(CDP); +CP2_FUNCNC(NCCS); +CP2_FUNCNC(CC); +CP2_FUNCNC(NCS); +CP2_FUNCNC(NCT); +CP2_FUNC(SQR); +CP2_FUNC(DCPL); +CP2_FUNCNC(DPCT); +CP2_FUNCNC(AVSZ3); +CP2_FUNCNC(AVSZ4); +CP2_FUNCNC(RTPT); +CP2_FUNC(GPF); +CP2_FUNC(GPL); +CP2_FUNCNC(NCCT); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/libpcsxcore/ppc/pR3000A.c b/libpcsxcore/ppc/pR3000A.c new file mode 100644 index 0000000..93745f8 --- /dev/null +++ b/libpcsxcore/ppc/pR3000A.c @@ -0,0 +1,3540 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307 USA + */ + +#ifdef _MSC_VER_ +#pragma warning(disable:4244) +#pragma warning(disable:4761) +#endif +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/mman.h> + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#include "../psxcommon.h" +#include "ppc.h" +#include "reguse.h" +#include "../r3000a.h" +#include "../psxhle.h" + +//#define NO_CONSTANT + +u32 *psxRecLUT; + +#undef _Op_ +#define _Op_ _fOp_(psxRegs.code) +#undef _Funct_ +#define _Funct_ _fFunct_(psxRegs.code) +#undef _Rd_ +#define _Rd_ _fRd_(psxRegs.code) +#undef _Rt_ +#define _Rt_ _fRt_(psxRegs.code) +#undef _Rs_ +#define _Rs_ _fRs_(psxRegs.code) +#undef _Sa_ +#define _Sa_ _fSa_(psxRegs.code) +#undef _Im_ +#define _Im_ _fIm_(psxRegs.code) +#undef _Target_ +#define _Target_ _fTarget_(psxRegs.code) + +#undef _Imm_ +#define _Imm_ _fImm_(psxRegs.code) +#undef _ImmU_ +#define _ImmU_ _fImmU_(psxRegs.code) + +#undef PC_REC +#undef PC_REC8 +#undef PC_REC16 +#undef PC_REC32 +#define PC_REC(x) (psxRecLUT[x >> 16] + (x & 0xffff)) +#define PC_REC8(x) (*(u8 *)PC_REC(x)) +#define PC_REC16(x) (*(u16*)PC_REC(x)) +#define PC_REC32(x) (*(u32*)PC_REC(x)) + +#define OFFSET(X,Y) ((u32)(Y)-(u32)(X)) + +#define RECMEM_SIZE (12*1024*1024) + +static char *recMem; /* the recompiled blocks will be here */ +static char *recRAM; /* and the ptr to the blocks here */ +static char *recROM; /* and here */ + +static u32 pc; /* recompiler pc */ +static u32 pcold; /* recompiler oldpc */ +static int count; /* recompiler intruction count */ +static int branch; /* set for branch */ +static u32 target; /* branch target */ +static u32 resp; + +u32 cop2readypc = 0; +u32 idlecyclecount = 0; + +#define NUM_REGISTERS 34 +typedef struct { + int state; + u32 k; + int reg; +} iRegisters; + +static iRegisters iRegs[34]; + +#define ST_UNK 0x00 +#define ST_CONST 0x01 +#define ST_MAPPED 0x02 + +#ifdef NO_CONSTANT +#define IsConst(reg) 0 +#else +#define IsConst(reg) (iRegs[reg].state & ST_CONST) +#endif +#define IsMapped(reg) (iRegs[reg].state & ST_MAPPED) + +static void (*recBSC[64])(); +static void (*recSPC[64])(); +static void (*recREG[32])(); +static void (*recCP0[32])(); +static void (*recCP2[64])(); +static void (*recCP2BSC[32])(); + +#define REG_LO 32 +#define REG_HI 33 + +// Hardware register usage +#define HWUSAGE_NONE 0x00 + +#define HWUSAGE_READ 0x01 +#define HWUSAGE_WRITE 0x02 +#define HWUSAGE_CONST 0x04 +#define HWUSAGE_ARG 0x08 /* used as an argument for a function call */ + +#define HWUSAGE_RESERVED 0x10 /* won't get flushed when flushing all regs */ +#define HWUSAGE_SPECIAL 0x20 /* special purpose register */ +#define HWUSAGE_HARDWIRED 0x40 /* specific hardware register mapping that is never disposed */ +#define HWUSAGE_INITED 0x80 +#define HWUSAGE_PSXREG 0x100 + +// Remember to invalidate the special registers if they are modified by compiler +enum { + ARG1 = 3, + ARG2 = 4, + ARG3 = 5, + PSXREGS, // ptr + PSXMEM, // ptr + CYCLECOUNT, // ptr + PSXPC, // ptr + TARGETPTR, // ptr + TARGET, // ptr + RETVAL, + REG_RZERO, + REG_WZERO +}; + +typedef struct { + int code; + u32 k; + int usage; + int lastUsed; + + void (*flush)(int hwreg); + int private; +} HWRegister; +static HWRegister HWRegisters[NUM_HW_REGISTERS]; +static int HWRegUseCount; +static int DstCPUReg; +static int UniqueRegAlloc; + +static int GetFreeHWReg(); +static void InvalidateCPURegs(); +static void DisposeHWReg(int index); +static void FlushHWReg(int index); +static void FlushAllHWReg(); +static void MapPsxReg32(int reg); +static void FlushPsxReg32(int hwreg); +static int UpdateHWRegUsage(int hwreg, int usage); +static int GetHWReg32(int reg); +static int PutHWReg32(int reg); +static int GetSpecialIndexFromHWRegs(int which); +static int GetHWRegFromCPUReg(int cpureg); +static int MapRegSpecial(int which); +static void FlushRegSpecial(int hwreg); +static int GetHWRegSpecial(int which); +static int PutHWRegSpecial(int which); +static void recRecompile(); +static void recError(); + +#pragma mark --- Generic register mapping --- + +static int GetFreeHWReg() +{ + int i, least, index; + + if (DstCPUReg != -1) { + index = GetHWRegFromCPUReg(DstCPUReg); + DstCPUReg = -1; + } else { + // LRU algorith with a twist ;) + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) { + break; + } + } + + least = HWRegisters[i].lastUsed; index = i; + for (; i<NUM_HW_REGISTERS; i++) { + if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) { + if (HWRegisters[i].usage == HWUSAGE_NONE && HWRegisters[i].code >= 13) { + index = i; + break; + } + else if (HWRegisters[i].lastUsed < least) { + least = HWRegisters[i].lastUsed; + index = i; + } + } + } + + // Cycle the registers + if (HWRegisters[index].usage == HWUSAGE_NONE) { + for (; i<NUM_HW_REGISTERS; i++) { + if (!(HWRegisters[i].usage & HWUSAGE_RESERVED)) { + if (HWRegisters[i].usage == HWUSAGE_NONE && + HWRegisters[i].code >= 13 && + HWRegisters[i].lastUsed < least) { + least = HWRegisters[i].lastUsed; + index = i; + break; + } + } + } + } + } + +/* if (HWRegisters[index].code < 13 && HWRegisters[index].code > 3) { + SysPrintf("Allocating volatile register %i\n", HWRegisters[index].code); + } + if (HWRegisters[index].usage != HWUSAGE_NONE) { + SysPrintf("RegUse too big. Flushing %i\n", HWRegisters[index].code); + }*/ + if (HWRegisters[index].usage & (HWUSAGE_RESERVED | HWUSAGE_HARDWIRED)) { + if (HWRegisters[index].usage & HWUSAGE_RESERVED) { + SysPrintf("Error! Trying to map a new register to a reserved register (r%i)", + HWRegisters[index].code); + } + if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) { + SysPrintf("Error! Trying to map a new register to a hardwired register (r%i)", + HWRegisters[index].code); + } + } + + if (HWRegisters[index].lastUsed != 0) { + UniqueRegAlloc = 0; + } + + // Make sure the register is really flushed! + FlushHWReg(index); + HWRegisters[index].usage = HWUSAGE_NONE; + HWRegisters[index].flush = NULL; + + return index; +} + +static void FlushHWReg(int index) +{ + if (index < 0) return; + if (HWRegisters[index].usage == HWUSAGE_NONE) return; + + if (HWRegisters[index].flush) { + HWRegisters[index].usage |= HWUSAGE_RESERVED; + HWRegisters[index].flush(index); + HWRegisters[index].flush = NULL; + } + + if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) { + HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE); + } else { + HWRegisters[index].usage = HWUSAGE_NONE; + } +} + +// get rid of a mapped register without flushing the contents to the memory +static void DisposeHWReg(int index) +{ + if (index < 0) return; + if (HWRegisters[index].usage == HWUSAGE_NONE) return; + + HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE); + if (HWRegisters[index].usage == HWUSAGE_NONE) { + SysPrintf("Error! not correctly disposing register (r%i)", HWRegisters[index].code); + } + + FlushHWReg(index); +} + +// operated on cpu registers +__inline static void FlushCPURegRange(int start, int end) +{ + int i; + + if (end <= 0) end = 31; + if (start <= 0) start = 0; + + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (HWRegisters[i].code >= start && HWRegisters[i].code <= end) + if (HWRegisters[i].flush) + FlushHWReg(i); + } + + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (HWRegisters[i].code >= start && HWRegisters[i].code <= end) + FlushHWReg(i); + } +} + +static void FlushAllHWReg() +{ + FlushCPURegRange(0,31); +} + +static void InvalidateCPURegs() +{ + FlushCPURegRange(0,12); +} + +#pragma mark --- Mapping utility functions --- + +static void MoveHWRegToCPUReg(int cpureg, int hwreg) +{ + int dstreg; + + if (HWRegisters[hwreg].code == cpureg) + return; + + dstreg = GetHWRegFromCPUReg(cpureg); + + HWRegisters[dstreg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG); + if (HWRegisters[hwreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) { + FlushHWReg(dstreg); + MR(HWRegisters[dstreg].code, HWRegisters[hwreg].code); + } else { + if (HWRegisters[dstreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) { + MR(HWRegisters[hwreg].code, HWRegisters[dstreg].code); + } + else if (HWRegisters[dstreg].usage != HWUSAGE_NONE) { + FlushHWReg(dstreg); + } + } + + HWRegisters[dstreg].code = HWRegisters[hwreg].code; + HWRegisters[hwreg].code = cpureg; +} + +static int UpdateHWRegUsage(int hwreg, int usage) +{ + HWRegisters[hwreg].lastUsed = ++HWRegUseCount; + if (usage & HWUSAGE_WRITE) { + HWRegisters[hwreg].usage &= ~HWUSAGE_CONST; + } + if (!(usage & HWUSAGE_INITED)) { + HWRegisters[hwreg].usage &= ~HWUSAGE_INITED; + } + HWRegisters[hwreg].usage |= usage; + + return HWRegisters[hwreg].code; +} + +static int GetHWRegFromCPUReg(int cpureg) +{ + int i; + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (HWRegisters[i].code == cpureg) { + return i; + } + } + + SysPrintf("Error! Register location failure (r%i)", cpureg); + return 0; +} + +// this function operates on cpu registers +void SetDstCPUReg(int cpureg) +{ + DstCPUReg = cpureg; +} + +static void ReserveArgs(int args) +{ + int index, i; + + for (i=0; i<args; i++) { + index = GetHWRegFromCPUReg(3+i); + HWRegisters[index].usage |= HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG; + } +} + +static void ReleaseArgs() +{ + int i; + + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (HWRegisters[i].usage & HWUSAGE_ARG) { + //HWRegisters[i].usage = HWUSAGE_NONE; + //HWRegisters[i].flush = NULL; + HWRegisters[i].usage &= ~(HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG); + FlushHWReg(i); + } + } +} + +#pragma mark --- Psx register mapping --- + +static void MapPsxReg32(int reg) +{ + int hwreg = GetFreeHWReg(); + HWRegisters[hwreg].flush = FlushPsxReg32; + HWRegisters[hwreg].private = reg; + + if (iRegs[reg].reg != -1) { + SysPrintf("error: double mapped psx register"); + } + + iRegs[reg].reg = hwreg; + iRegs[reg].state |= ST_MAPPED; +} + +static void FlushPsxReg32(int hwreg) +{ + int reg = HWRegisters[hwreg].private; + + if (iRegs[reg].reg == -1) { + SysPrintf("error: flushing unmapped psx register"); + } + + if (HWRegisters[hwreg].usage & HWUSAGE_WRITE) { + if (branch) { + /*int reguse = nextPsxRegUse(pc-8, reg); + if (reguse == REGUSE_NONE || (reguse & REGUSE_READ))*/ { + STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS)); + } + } else { + int reguse = nextPsxRegUse(pc-4, reg); + if (reguse == REGUSE_NONE || (reguse & REGUSE_READ)) { + STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS)); + } + } + } + + iRegs[reg].reg = -1; + iRegs[reg].state = ST_UNK; +} + +static int GetHWReg32(int reg) +{ + int usage = HWUSAGE_PSXREG | HWUSAGE_READ; + + if (reg == 0) { + return GetHWRegSpecial(REG_RZERO); + } + if (!IsMapped(reg)) { + usage |= HWUSAGE_INITED; + MapPsxReg32(reg); + + HWRegisters[iRegs[reg].reg].usage |= HWUSAGE_RESERVED; + if (IsConst(reg)) { + LIW(HWRegisters[iRegs[reg].reg].code, iRegs[reg].k); + usage |= HWUSAGE_WRITE | HWUSAGE_CONST; + //iRegs[reg].state &= ~ST_CONST; + } + else { + LWZ(HWRegisters[iRegs[reg].reg].code, OFFSET(&psxRegs, &psxRegs.GPR.r[reg]), GetHWRegSpecial(PSXREGS)); + } + HWRegisters[iRegs[reg].reg].usage &= ~HWUSAGE_RESERVED; + } + else if (DstCPUReg != -1) { + int dst = DstCPUReg; + DstCPUReg = -1; + + if (HWRegisters[iRegs[reg].reg].code < 13) { + MoveHWRegToCPUReg(dst, iRegs[reg].reg); + } else { + MR(DstCPUReg, HWRegisters[iRegs[reg].reg].code); + } + } + + DstCPUReg = -1; + + return UpdateHWRegUsage(iRegs[reg].reg, usage); +} + +static int PutHWReg32(int reg) +{ + int usage = HWUSAGE_PSXREG | HWUSAGE_WRITE; + if (reg == 0) { + return PutHWRegSpecial(REG_WZERO); + } + + if (DstCPUReg != -1 && IsMapped(reg)) { + if (HWRegisters[iRegs[reg].reg].code != DstCPUReg) { + int tmp = DstCPUReg; + DstCPUReg = -1; + DisposeHWReg(iRegs[reg].reg); + DstCPUReg = tmp; + } + } + if (!IsMapped(reg)) { + usage |= HWUSAGE_INITED; + MapPsxReg32(reg); + } + + DstCPUReg = -1; + iRegs[reg].state &= ~ST_CONST; + + return UpdateHWRegUsage(iRegs[reg].reg, usage); +} + +#pragma mark --- Special register mapping --- + +static int GetSpecialIndexFromHWRegs(int which) +{ + int i; + for (i=0; i<NUM_HW_REGISTERS; i++) { + if (HWRegisters[i].usage & HWUSAGE_SPECIAL) { + if (HWRegisters[i].private == which) { + return i; + } + } + } + return -1; +} + +static int MapRegSpecial(int which) +{ + int hwreg = GetFreeHWReg(); + HWRegisters[hwreg].flush = FlushRegSpecial; + HWRegisters[hwreg].private = which; + + return hwreg; +} + +static void FlushRegSpecial(int hwreg) +{ + int which = HWRegisters[hwreg].private; + + if (!(HWRegisters[hwreg].usage & HWUSAGE_WRITE)) + return; + + switch (which) { + case CYCLECOUNT: + STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.cycle), GetHWRegSpecial(PSXREGS)); + break; + case PSXPC: + STW(HWRegisters[hwreg].code, OFFSET(&psxRegs, &psxRegs.pc), GetHWRegSpecial(PSXREGS)); + break; + case TARGET: + STW(HWRegisters[hwreg].code, 0, GetHWRegSpecial(TARGETPTR)); + break; + } +} + +static int GetHWRegSpecial(int which) +{ + int index = GetSpecialIndexFromHWRegs(which); + int usage = HWUSAGE_READ | HWUSAGE_SPECIAL; + + if (index == -1) { + usage |= HWUSAGE_INITED; + index = MapRegSpecial(which); + + HWRegisters[index].usage |= HWUSAGE_RESERVED; + switch (which) { + case PSXREGS: + case PSXMEM: + SysPrintf("error! shouldn't be here!\n"); + //HWRegisters[index].flush = NULL; + //LIW(HWRegisters[index].code, (u32)&psxRegs); + break; + case TARGETPTR: + HWRegisters[index].flush = NULL; + LIW(HWRegisters[index].code, (u32)&target); + break; + case REG_RZERO: + HWRegisters[index].flush = NULL; + LIW(HWRegisters[index].code, 0); + break; + case RETVAL: + MoveHWRegToCPUReg(3, index); + /*reg = GetHWRegFromCPUReg(3); + HWRegisters[reg].code = HWRegisters[index].code; + HWRegisters[index].code = 3;*/ + HWRegisters[index].flush = NULL; + + usage |= HWUSAGE_RESERVED; + break; + + case CYCLECOUNT: + LWZ(HWRegisters[index].code, OFFSET(&psxRegs, &psxRegs.cycle), GetHWRegSpecial(PSXREGS)); + break; + case PSXPC: + LWZ(HWRegisters[index].code, OFFSET(&psxRegs, &psxRegs.pc), GetHWRegSpecial(PSXREGS)); + break; + case TARGET: + LWZ(HWRegisters[index].code, 0, GetHWRegSpecial(TARGETPTR)); + break; + default: + SysPrintf("Error: Unknown special register in GetHWRegSpecial()\n"); + break; + } + HWRegisters[index].usage &= ~HWUSAGE_RESERVED; + } + else if (DstCPUReg != -1) { + int dst = DstCPUReg; + DstCPUReg = -1; + + MoveHWRegToCPUReg(dst, index); + } + + return UpdateHWRegUsage(index, usage); +} + +static int PutHWRegSpecial(int which) +{ + int index = GetSpecialIndexFromHWRegs(which); + int usage = HWUSAGE_WRITE | HWUSAGE_SPECIAL; + + if (DstCPUReg != -1 && index != -1) { + if (HWRegisters[index].code != DstCPUReg) { + int tmp = DstCPUReg; + DstCPUReg = -1; + DisposeHWReg(index); + DstCPUReg = tmp; + } + } + switch (which) { + case PSXREGS: + case TARGETPTR: + SysPrintf("Error: Read-only special register in PutHWRegSpecial()\n"); + case REG_WZERO: + if (index >= 0) { + if (HWRegisters[index].usage & HWUSAGE_WRITE) + break; + } + index = MapRegSpecial(which); + HWRegisters[index].flush = NULL; + break; + default: + if (index == -1) { + usage |= HWUSAGE_INITED; + index = MapRegSpecial(which); + + HWRegisters[index].usage |= HWUSAGE_RESERVED; + switch (which) { + case ARG1: + case ARG2: + case ARG3: + MoveHWRegToCPUReg(3+(which-ARG1), index); + /*reg = GetHWRegFromCPUReg(3+(which-ARG1)); + + if (HWRegisters[reg].usage != HWUSAGE_NONE) { + HWRegisters[reg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG); + if (HWRegisters[reg].flush != NULL && HWRegisters[reg].usage & (HWUSAGE_WRITE | HWUSAGE_READ)) { + MR(HWRegisters[index].code, HWRegisters[reg].code); + } else { + FlushHWReg(reg); + } + } + HWRegisters[reg].code = HWRegisters[index].code; + if (!(HWRegisters[index].code >= 3 && HWRegisters[index].code <=31)) + SysPrintf("Error! Register allocation"); + HWRegisters[index].code = 3+(which-ARG1);*/ + HWRegisters[index].flush = NULL; + + usage |= HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG; + break; + } + } + HWRegisters[index].usage &= ~HWUSAGE_RESERVED; + break; + } + + DstCPUReg = -1; + + return UpdateHWRegUsage(index, usage); +} + +#pragma mark --- --- + +static void MapConst(int reg, u32 _const) { + if (reg == 0) + return; + if (IsConst(reg) && iRegs[reg].k == _const) + return; + + DisposeHWReg(iRegs[reg].reg); + iRegs[reg].k = _const; + iRegs[reg].state = ST_CONST; +} + +static void MapCopy(int dst, int src) +{ + // do it the lazy way for now + MR(PutHWReg32(dst), GetHWReg32(src)); +} + +static void iFlushReg(u32 nextpc, int reg) { + if (!IsMapped(reg) && IsConst(reg)) { + GetHWReg32(reg); + } + if (IsMapped(reg)) { + if (nextpc) { + int use = nextPsxRegUse(nextpc, reg); + if ((use & REGUSE_RW) == REGUSE_WRITE) { + DisposeHWReg(iRegs[reg].reg); + } else { + FlushHWReg(iRegs[reg].reg); + } + } else { + FlushHWReg(iRegs[reg].reg); + } + } +} + +static void iFlushRegs(u32 nextpc) { + int i; + + for (i=1; i<NUM_REGISTERS; i++) { + iFlushReg(nextpc, i); + } +} + +static void Return() +{ + iFlushRegs(0); + FlushAllHWReg(); + if (((u32)returnPC & 0x1fffffc) == (u32)returnPC) { + BA((u32)returnPC); + } + else { + LIW(0, (u32)returnPC); + MTLR(0); + BLR(); + } +} + +static void iRet() { + /* store cycle */ + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + Return(); +} + +static int iLoadTest() { + u32 tmp; + + // check for load delay + tmp = psxRegs.code >> 26; + switch (tmp) { + case 0x10: // COP0 + switch (_Rs_) { + case 0x00: // MFC0 + case 0x02: // CFC0 + return 1; + } + break; + case 0x12: // COP2 + switch (_Funct_) { + case 0x00: + switch (_Rs_) { + case 0x00: // MFC2 + case 0x02: // CFC2 + return 1; + } + break; + } + break; + case 0x32: // LWC2 + return 1; + default: + if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR + return 1; + } + break; + } + return 0; +} + +/* set a pending branch */ +static void SetBranch() { + int treg; + branch = 1; + psxRegs.code = PSXMu32(pc); + pc+=4; + + if (iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + treg = GetHWRegSpecial(TARGET); + MR(PutHWRegSpecial(ARG2), treg); + DisposeHWReg(GetHWRegFromCPUReg(treg)); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + recBSC[psxRegs.code>>26](); + + iFlushRegs(0); + treg = GetHWRegSpecial(TARGET); + MR(PutHWRegSpecial(PSXPC), GetHWRegSpecial(TARGET)); // FIXME: this line should not be needed + DisposeHWReg(GetHWRegFromCPUReg(treg)); + FlushAllHWReg(); + + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + // TODO: don't return if target is compiled + Return(); +} + +static void iJump(u32 branchPC) { + u32 *b1, *b2; + branch = 1; + psxRegs.code = PSXMu32(pc); + pc+=4; + + if (iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + LIW(PutHWRegSpecial(ARG2), branchPC); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + recBSC[psxRegs.code>>26](); + + iFlushRegs(branchPC); + LIW(PutHWRegSpecial(PSXPC), branchPC); + FlushAllHWReg(); + + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) { + // LIW(PutHWRegSpecial(CYCLECOUNT), 0); + //} else { + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + //} + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + if (!Config.HLE && Config.PsxOut && + ((branchPC & 0x1fffff) == 0xa0 || + (branchPC & 0x1fffff) == 0xb0 || + (branchPC & 0x1fffff) == 0xc0)) + CALLFunc((u32)psxJumpTest); + + // always return for now... + //Return(); + + // maybe just happened an interruption, check so + LIW(0, branchPC); + CMPLW(GetHWRegSpecial(PSXPC), 0); + BNE_L(b1); + + LIW(3, PC_REC(branchPC)); + LWZ(3, 0, 3); + CMPLWI(3, 0); + BNE_L(b2); + + B_DST(b1); + Return(); + + // next bit is already compiled - jump right to it + B_DST(b2); + MTCTR(3); + BCTR(); +} + +static void iBranch(u32 branchPC, int savectx) { + HWRegister HWRegistersS[NUM_HW_REGISTERS]; + iRegisters iRegsS[NUM_REGISTERS]; + int HWRegUseCountS = 0; + u32 respold=0; + u32 *b1, *b2; + + if (savectx) { + respold = resp; + memcpy(iRegsS, iRegs, sizeof(iRegs)); + memcpy(HWRegistersS, HWRegisters, sizeof(HWRegisters)); + HWRegUseCountS = HWRegUseCount; + } + + branch = 1; + psxRegs.code = PSXMu32(pc); + + // the delay test is only made when the branch is taken + // savectx == 0 will mean that :) + if (savectx == 0 && iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = (idlecyclecount + ((pc+4) - pcold) / 4) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + LIW(PutHWRegSpecial(ARG2), branchPC); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + pc+= 4; + recBSC[psxRegs.code>>26](); + + iFlushRegs(branchPC); + LIW(PutHWRegSpecial(PSXPC), branchPC); + FlushAllHWReg(); + + /* store cycle */ + count = (idlecyclecount + (pc - pcold) / 4) * BIAS; + //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) { + // LIW(PutHWRegSpecial(CYCLECOUNT), 0); + //} else { + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + //} + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + // always return for now... + //Return(); + + LIW(0, branchPC); + CMPLW(GetHWRegSpecial(PSXPC), 0); + BNE_L(b1); + + LIW(3, PC_REC(branchPC)); + LWZ(3, 0, 3); + CMPLWI(3, 0); + BNE_L(b2); + + B_DST(b1); + Return(); + + B_DST(b2); + MTCTR(3); + BCTR(); + + // maybe just happened an interruption, check so +/* CMP32ItoM((u32)&psxRegs.pc, branchPC); + j8Ptr[1] = JE8(0); + RET(); + + x86SetJ8(j8Ptr[1]); + MOV32MtoR(EAX, PC_REC(branchPC)); + TEST32RtoR(EAX, EAX); + j8Ptr[2] = JNE8(0); + RET(); + + x86SetJ8(j8Ptr[2]); + JMP32R(EAX);*/ + + pc-= 4; + if (savectx) { + resp = respold; + memcpy(iRegs, iRegsS, sizeof(iRegs)); + memcpy(HWRegisters, HWRegistersS, sizeof(HWRegisters)); + HWRegUseCount = HWRegUseCountS; + } +} + + +static void iDumpRegs() { + int i, j; + + printf("%lx %lx\n", psxRegs.pc, psxRegs.cycle); + for (i=0; i<4; i++) { + for (j=0; j<8; j++) + printf("%lx ", psxRegs.GPR.r[j*i]); + printf("\n"); + } +} + +void iDumpBlock(char *ptr) { +/* FILE *f; + u32 i; + + SysPrintf("dump1 %x:%x, %x\n", psxRegs.pc, pc, psxCurrentCycle); + + for (i = psxRegs.pc; i < pc; i+=4) + SysPrintf("%s\n", disR3000AF(PSXMu32(i), i)); + + fflush(stdout); + f = fopen("dump1", "w"); + fwrite(ptr, 1, (u32)x86Ptr - (u32)ptr, f); + fclose(f); + system("ndisasmw -u dump1"); + fflush(stdout);*/ +} + +#define REC_FUNC(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ +/* branch = 2; */\ +} + +#define REC_SYS(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ + branch = 2; \ + iRet(); \ +} + +#define REC_BRANCH(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ + branch = 2; \ + iRet(); \ +} + +static void freeMem(int all) +{ + if (recMem) free(recMem); + if (recRAM) free(recRAM); + if (recROM) free(recROM); + recMem = recRAM = recROM = 0; + + if (all && psxRecLUT) { + free(psxRecLUT); psxRecLUT = NULL; + } +} + +static int allocMem() { + int i; + + freeMem(0); + + if (psxRecLUT==NULL) + psxRecLUT = (u32*) malloc(0x010000 * 4); + + recMem = (char*) malloc(RECMEM_SIZE); + //recMem = mmap(NULL, RECMEM_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); + recRAM = (char*) malloc(0x200000); + recROM = (char*) malloc(0x080000); + if (recRAM == NULL || recROM == NULL || recMem == NULL/*(void *)-1*/ || psxRecLUT == NULL) { + freeMem(1); + SysMessage("Error allocating memory"); return -1; + } + + for (i=0; i<0x80; i++) psxRecLUT[i + 0x0000] = (u32)&recRAM[(i & 0x1f) << 16]; + memcpy(psxRecLUT + 0x8000, psxRecLUT, 0x80 * 4); + memcpy(psxRecLUT + 0xa000, psxRecLUT, 0x80 * 4); + + for (i=0; i<0x08; i++) psxRecLUT[i + 0xbfc0] = (u32)&recROM[i << 16]; + + return 0; +} + +static int recInit() { + return allocMem(); +} + +static void recReset() { + memset(recRAM, 0, 0x200000); + memset(recROM, 0, 0x080000); + + ppcInit(); + ppcSetPtr((u32 *)recMem); + + branch = 0; + memset(iRegs, 0, sizeof(iRegs)); + iRegs[0].state = ST_CONST; + iRegs[0].k = 0; +} + +static void recShutdown() { + freeMem(1); + ppcShutdown(); +} + +static void recError() { + SysReset(); + ClosePlugins(); + SysMessage("Unrecoverable error while running recompiler\n"); + SysRunGui(); +} + +__inline static void execute() { + void (**recFunc)(); + char *p; + + p = (char*)PC_REC(psxRegs.pc); + /*if (p != NULL)*/ recFunc = (void (**)()) (u32)p; + /*else { recError(); return; }*/ + + if (*recFunc == 0) { + recRecompile(); + } + recRun(*recFunc, (u32)&psxRegs, (u32)&psxM); +} + +static void recExecute() { + for (;;) execute(); +} + +static void recExecuteBlock() { + execute(); +} + +static void recClear(u32 Addr, u32 Size) { + memset((void*)PC_REC(Addr), 0, Size * 4); +} + +static void recNULL() { +// SysMessage("recUNK: %8.8x\n", psxRegs.code); +} + +/********************************************************* +* goes to opcodes tables... * +* Format: table[something....] * +*********************************************************/ + +//REC_SYS(SPECIAL); +static void recSPECIAL() { + recSPC[_Funct_](); +} + +static void recREGIMM() { + recREG[_Rt_](); +} + +static void recCOP0() { + recCP0[_Rs_](); +} + +//REC_SYS(COP2); +static void recCOP2() { + recCP2[_Funct_](); +} + +static void recBASIC() { + recCP2BSC[_Rs_](); +} + +//end of Tables opcodes... + +#pragma mark - Arithmetic with immediate operand - +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ + +#if 0 +/*REC_FUNC(ADDI); +REC_FUNC(ADDIU); +REC_FUNC(ANDI); +REC_FUNC(ORI); +REC_FUNC(XORI); +REC_FUNC(SLTI); +REC_FUNC(SLTIU);*/ +#else +static void recADDIU() { +// Rt = Rs + Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k + _Imm_); + } else { + if (_Imm_ == 0) { + MapCopy(_Rt_, _Rs_); + } else { + ADDI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _Imm_); + } + } +} + +static void recADDI() { +// Rt = Rs + Im + recADDIU(); +} + +//REC_FUNC(SLTI); +//REC_FUNC(SLTIU); +//CR0: SIGN | POSITIVE | ZERO | SOVERFLOW | SOVERFLOW | OVERFLOW | CARRY +static void recSLTI() { +// Rt = Rs < Im (signed) + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, (s32)iRegs[_Rs_].k < _Imm_); + } else { + if (_Imm_ == 0) { + SRWI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), 31); + } else { + int reg; + CMPWI(GetHWReg32(_Rs_), _Imm_); + reg = PutHWReg32(_Rt_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } + } +} + +static void recSLTIU() { +// Rt = Rs < Im (unsigned) + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k < _ImmU_); + } else { + int reg; + CMPLWI(GetHWReg32(_Rs_), _Imm_); + reg = PutHWReg32(_Rt_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } +} + +static void recANDI() { +// Rt = Rs And Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k & _ImmU_); + } else { + ANDI_(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } +} + +static void recORI() { +// Rt = Rs Or Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k | _ImmU_); + } else { + if (_Imm_ == 0) { + MapCopy(_Rt_, _Rs_); + } else { + ORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } + } +} + +static void recXORI() { +// Rt = Rs Xor Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k ^ _ImmU_); + } else { + XORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } +} +#endif +//end of * Arithmetic with immediate operand + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +//REC_FUNC(LUI); +//#if 0*/ +static void recLUI() { +// Rt = Imm << 16 + if (!_Rt_) return; + + MapConst(_Rt_, psxRegs.code << 16); +} +//#endif +//End of Load Higher ..... + +#pragma mark - Register arithmetic - +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +#if 0 +/*REC_FUNC(ADD); +REC_FUNC(ADDU); +REC_FUNC(SUB); +REC_FUNC(SUBU); +REC_FUNC(AND); +REC_FUNC(OR); +REC_FUNC(XOR); +REC_FUNC(NOR); +REC_FUNC(SLT); +REC_FUNC(SLTU);*/ +#else +static void recADDU() { +// Rd = Rs + Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k + iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), (s16)iRegs[_Rs_].k); + } else if ((iRegs[_Rs_].k & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k>>16); + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (s16)iRegs[_Rt_].k); + } else if ((iRegs[_Rt_].k & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k>>16); + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recADD() { +// Rd = Rs + Rt + recADDU(); +} + +static void recSUBU() { +// Rd = Rs - Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k - iRegs[_Rt_].k); + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((s32)(s16)(-iRegs[_Rt_].k) == (s32)(-iRegs[_Rt_].k)) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), -iRegs[_Rt_].k); + } else if (((-iRegs[_Rt_].k) & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (-iRegs[_Rt_].k)>>16); + } else { + SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recSUB() { +// Rd = Rs - Rt + recSUBU(); +} + +static void recAND() { +// Rd = Rs And Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k & iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + // TODO: implement shifted (ANDIS) versions of these + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recOR() { +// Rd = Rs Or Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k | iRegs[_Rt_].k); + } + else { + if (_Rs_ == _Rt_) { + MapCopy(_Rd_, _Rs_); + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + ORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + ORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recXOR() { +// Rd = Rs Xor Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k ^ iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + XORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + XORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recNOR() { +// Rd = Rs Nor Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, ~(iRegs[_Rs_].k | iRegs[_Rt_].k)); + } /*else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + NORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + NORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } */else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recSLT() { +// Rd = Rs < Rt (signed) + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, (s32)iRegs[_Rs_].k < (s32)iRegs[_Rt_].k); + } else { // TODO: add immidiate cases + int reg; + CMPW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + reg = PutHWReg32(_Rd_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } +} + +static void recSLTU() { +// Rd = Rs < Rt (unsigned) + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k < iRegs[_Rt_].k); + } else { // TODO: add immidiate cases + SUBFC(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + SUBFE(PutHWReg32(_Rd_), GetHWReg32(_Rd_), GetHWReg32(_Rd_)); + NEG(PutHWReg32(_Rd_), GetHWReg32(_Rd_)); + } +} +#endif +//End of * Register arithmetic + +#pragma mark - mult/div & Register trap logic - +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ + +#if 0 +REC_FUNC(MULT); +REC_FUNC(MULTU); +REC_FUNC(DIV); +REC_FUNC(DIVU); +#else + +int DoShift(u32 k) +{ + u32 i; + for (i=0; i<30; i++) { + if (k == (1ul << i)) + return i; + } + return -1; +} + +//REC_FUNC(MULT); + +// FIXME: doesn't work in GT - wrong way marker +static void recMULT() { +// Lo/Hi = Rs * Rt (signed) + s32 k; int r; + int usehi, uselo; + + if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) || + (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + u64 res = (s64)((s64)(s32)iRegs[_Rs_].k * (s64)(s32)iRegs[_Rt_].k); + MapConst(REG_LO, (res & 0xffffffff)); + MapConst(REG_HI, ((res >> 32) & 0xffffffff)); + return; + } + + if (IsConst(_Rs_)) { + k = (s32)iRegs[_Rs_].k; + r = _Rt_; + } else if (IsConst(_Rt_)) { + k = (s32)iRegs[_Rt_].k; + r = _Rs_; + } else { + r = -1; + k = 0; + } + + // FIXME: this should not be needed!!! +// uselo = isPsxRegUsed(pc, REG_LO); +// usehi = isPsxRegUsed(pc, REG_HI); + uselo = 1; //isPsxRegUsed(pc, REG_LO); + usehi = 1; //isPsxRegUsed(pc, REG_HI); + + + if (r != -1) { + int shift = DoShift(k); + if (shift != -1) { + if (uselo) { + SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift) + } + if (usehi) { + SRAWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift); + } + } else { + //if ((s32)(s16)k == k) { + // MULLWI(PutHWReg32(REG_LO), GetHWReg32(r), k); + // MULHWI(PutHWReg32(REG_HI), GetHWReg32(r), k); + //} else + { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + } + } else { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recMULTU() { +// Lo/Hi = Rs * Rt (unsigned) + u32 k; int r; + int usehi, uselo; + + if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) || + (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + u64 res = (u64)((u64)(u32)iRegs[_Rs_].k * (u64)(u32)iRegs[_Rt_].k); + MapConst(REG_LO, (res & 0xffffffff)); + MapConst(REG_HI, ((res >> 32) & 0xffffffff)); + return; + } + + if (IsConst(_Rs_)) { + k = (s32)iRegs[_Rs_].k; + r = _Rt_; + } else if (IsConst(_Rt_)) { + k = (s32)iRegs[_Rt_].k; + r = _Rs_; + } else { + r = -1; + k = 0; + } + + uselo = isPsxRegUsed(pc, REG_LO); + usehi = isPsxRegUsed(pc, REG_HI); + + if (r != -1) { + int shift = DoShift(k); + if (shift != -1) { + if (uselo) { + SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift); + } + if (usehi) { + SRWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift); + } + } else { + { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + } + } else { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recDIV() { +// Lo/Hi = Rs / Rt (signed) + int usehi; + + if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(REG_LO, (s32)iRegs[_Rs_].k / (s32)iRegs[_Rt_].k); + MapConst(REG_HI, (s32)iRegs[_Rs_].k % (s32)iRegs[_Rt_].k); + return; + } + + usehi = isPsxRegUsed(pc, REG_HI); + + if (IsConst(_Rt_)) { + int shift = DoShift(iRegs[_Rt_].k); + if (shift != -1) { + SRAWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift); + ADDZE(PutHWReg32(REG_LO), GetHWReg32(REG_LO)); + if (usehi) { + RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, 31-shift, 31); + } + } else if (iRegs[_Rt_].k == 3) { + // http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html + LIS(PutHWReg32(REG_HI), 0x5555); + ADDI(PutHWReg32(REG_HI), GetHWReg32(REG_HI), 0x5556); + MULHW(PutHWReg32(REG_LO), GetHWReg32(REG_HI), GetHWReg32(_Rs_)); + SRWI(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 31); + ADD(PutHWReg32(REG_LO), GetHWReg32(REG_LO), GetHWReg32(REG_HI)); + if (usehi) { + MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), 3); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } else { + DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + if ((iRegs[_Rt_].k & 0x7fff) == iRegs[_Rt_].k) { + MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), iRegs[_Rt_].k); + } else { + MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_)); + } + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } + } else { + DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } +} + +static void recDIVU() { +// Lo/Hi = Rs / Rt (unsigned) + int usehi; + + if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(REG_LO, (u32)iRegs[_Rs_].k / (u32)iRegs[_Rt_].k); + MapConst(REG_HI, (u32)iRegs[_Rs_].k % (u32)iRegs[_Rt_].k); + return; + } + + usehi = isPsxRegUsed(pc, REG_HI); + + if (IsConst(_Rt_)) { + int shift = DoShift(iRegs[_Rt_].k); + if (shift != -1) { + SRWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift); + if (usehi) { + RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, 31-shift, 31); + } + } else { + DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } + } else { + DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } +} +#endif +//End of * Register mult/div & Register trap logic + +#pragma mark - memory access - + +#if 0 +REC_FUNC(LB); +REC_FUNC(LBU); +REC_FUNC(LH); +REC_FUNC(LHU); +REC_FUNC(LW); + +REC_FUNC(SB); +REC_FUNC(SH); +REC_FUNC(SW); + +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); +#else +static void preMemRead() +{ + int rs; + + ReserveArgs(1); + if (_Rs_ != _Rt_) { + DisposeHWReg(iRegs[_Rt_].reg); + } + rs = GetHWReg32(_Rs_); + if (rs != 3 || _Imm_ != 0) { + ADDI(PutHWRegSpecial(ARG1), rs, _Imm_); + } + if (_Rs_ == _Rt_) { + DisposeHWReg(iRegs[_Rt_].reg); + } + InvalidateCPURegs(); + //FlushAllHWReg(); +} + +static void preMemWrite(int size) +{ + int rs; + + ReserveArgs(2); + rs = GetHWReg32(_Rs_); + if (rs != 3 || _Imm_ != 0) { + ADDI(PutHWRegSpecial(ARG1), rs, _Imm_); + } + if (size == 1) { + RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 24, 31); + //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xff); + } else if (size == 2) { + RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 16, 31); + //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xffff); + } else { + MR(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_)); + } + + InvalidateCPURegs(); + //FlushAllHWReg(); +} + +static void recLB() { +// Rt = mem[Rs + Im] (signed) + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRs8(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + addr = (u32)&psxM[addr & 0x1fffff]; + LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct? + LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_)); + EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + addr = (u32)&psxH[addr & 0xfff]; + LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct? + LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_)); + EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r8 %x\n", addr); + }*/ + + preMemRead(); + CALLFunc((u32)psxMemRead8); + if (_Rt_) { + EXTSB(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL)); + DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL)); + } +} + +static void recLBU() { +// Rt = mem[Rs + Im] (unsigned) + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu8(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + addr = (u32)&psxM[addr & 0x1fffff]; + LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct? + LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + addr = (u32)&psxH[addr & 0xfff]; + LIW(PutHWReg32(_Rt_), ((addr>>16)<<16)+(addr&0x8000<<1)); // FIXME: is this correct? + LBZ(PutHWReg32(_Rt_), addr&0xffff, GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r8 %x\n", addr); + }*/ + + preMemRead(); + CALLFunc((u32)psxMemRead8); + + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +static void recLH() { +// Rt = mem[Rs + Im] (signed) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRs16(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r16 %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead16); + if (_Rt_) { + EXTSH(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL)); + DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL)); + } +} + +static void recLHU() { +// Rt = mem[Rs + Im] (unsigned) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu16(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80) { + if (addr >= 0x1f801c00 && addr < 0x1f801e00) { + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), addr); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)SPU_readRegister); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + } + switch (addr) { + case 0x1f801100: case 0x1f801110: case 0x1f801120: + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)psxRcntRcount); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + + case 0x1f801104: case 0x1f801114: case 0x1f801124: + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)psxRcntRmode); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + + case 0x1f801108: case 0x1f801118: case 0x1f801128: + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)psxRcntRtarget); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + } + } + // SysPrintf("unhandled r16u %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead16); + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +static void recLW() { +// Rt = mem[Rs + Im] (unsigned) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu32(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80) { + switch (addr) { + case 0x1f801080: case 0x1f801084: case 0x1f801088: + case 0x1f801090: case 0x1f801094: case 0x1f801098: + case 0x1f8010a0: case 0x1f8010a4: case 0x1f8010a8: + case 0x1f8010b0: case 0x1f8010b4: case 0x1f8010b8: + case 0x1f8010c0: case 0x1f8010c4: case 0x1f8010c8: + case 0x1f8010d0: case 0x1f8010d4: case 0x1f8010d8: + case 0x1f8010e0: case 0x1f8010e4: case 0x1f8010e8: + case 0x1f801070: case 0x1f801074: + case 0x1f8010f0: case 0x1f8010f4: + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xffff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + + case 0x1f801810: + if (!_Rt_) return; + + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)GPU_readData); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + + case 0x1f801814: + if (!_Rt_) return; + + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)GPU_readStatus); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + } + } +// SysPrintf("unhandled r32 %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead32); + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); +/*extern u32 LWL_MASK[4]; +extern u32 LWL_SHIFT[4]; + +void iLWLk(u32 shift) { + if (IsConst(_Rt_)) { + MOV32ItoR(ECX, iRegs[_Rt_].k); + } else { + MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); + } + AND32ItoR(ECX, LWL_MASK[shift]); + SHL32ItoR(EAX, LWL_SHIFT[shift]); + OR32RtoR (EAX, ECX); +} + +void recLWL() { +// Rt = Rt Merge mem[Rs + Im] + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]); + iLWLk(addr & 3); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]); + iLWLk(addr & 3); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + return; + } + } + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + PUSH32R (EAX); + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + CALLFunc((u32)psxMemRead32); + + if (_Rt_) { + ADD32ItoR(ESP, 4); + POP32R (EDX); + AND32ItoR(EDX, 0x3); // shift = addr & 3; + + MOV32ItoR(ECX, (u32)LWL_SHIFT); + MOV32RmStoR(ECX, ECX, EDX, 2); + SHL32CLtoR(EAX); // mem(EAX) << LWL_SHIFT[shift] + + MOV32ItoR(ECX, (u32)LWL_MASK); + MOV32RmStoR(ECX, ECX, EDX, 2); + if (IsConst(_Rt_)) { + MOV32ItoR(EDX, iRegs[_Rt_].k); + } else { + MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]); + } + AND32RtoR(EDX, ECX); // _rRt_ & LWL_MASK[shift] + + OR32RtoR(EAX, EDX); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + } else { +// ADD32ItoR(ESP, 8); + resp+= 8; + } +} + +static void recLWBlock(int count) { + u32 *code = PSXM(pc); + int i, respsave; +// Rt = mem[Rs + Im] (unsigned) + +// iFlushRegs(0); + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + // since bios is readonly it won't change + for (i=0; i<count; i++, code++, addr+=4) { + if (_fRt_(*code)) { + MapConst(_fRt_(*code), psxRu32(addr)); + } + } + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + for (i=0; i<count; i++, code++, addr+=4) { + if (!_fRt_(*code)) return; + iRegs[_fRt_(*code)].state = ST_UNK; + + MOV32MtoR(EAX, (u32)&psxM[addr & 0x1fffff]); + MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX); + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + for (i=0; i<count; i++, code++, addr+=4) { + if (!_fRt_(*code)) return; + iRegs[_fRt_(*code)].state = ST_UNK; + + MOV32MtoR(EAX, (u32)&psxH[addr & 0xfff]); + MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX); + } + return; + } + } + + SysPrintf("recLWBlock %d: %d\n", count, IsConst(_Rs_)); + iPushOfB(); + CALLFunc((u32)psxMemPointer); +// ADD32ItoR(ESP, 4); + resp+= 4; + + respsave = resp; resp = 0; + TEST32RtoR(EAX, EAX); + j32Ptr[4] = JZ32(0); + XOR32RtoR(ECX, ECX); + for (i=0; i<count; i++, code++) { + if (_fRt_(*code)) { + iRegs[_fRt_(*code)].state = ST_UNK; + + MOV32RmStoR(EDX, EAX, ECX, 2); + MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EDX); + } + if (i != (count-1)) INC32R(ECX); + } + j32Ptr[5] = JMP32(0); + x86SetJ32(j32Ptr[4]); + for (i=0, code = PSXM(pc); i<count; i++, code++) { + psxRegs.code = *code; + recLW(); + } + ADD32ItoR(ESP, resp); + x86SetJ32(j32Ptr[5]); + resp = respsave; +} + +extern u32 LWR_MASK[4]; +extern u32 LWR_SHIFT[4]; + +void iLWRk(u32 shift) { + if (IsConst(_Rt_)) { + MOV32ItoR(ECX, iRegs[_Rt_].k); + } else { + MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); + } + AND32ItoR(ECX, LWR_MASK[shift]); + SHR32ItoR(EAX, LWR_SHIFT[shift]); + OR32RtoR (EAX, ECX); +} + +void recLWR() { +// Rt = Rt Merge mem[Rs + Im] + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]); + iLWRk(addr & 3); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]); + iLWRk(addr & 3); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + return; + } + } + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + PUSH32R (EAX); + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + CALLFunc((u32)psxMemRead32); + + if (_Rt_) { + ADD32ItoR(ESP, 4); + POP32R (EDX); + AND32ItoR(EDX, 0x3); // shift = addr & 3; + + MOV32ItoR(ECX, (u32)LWR_SHIFT); + MOV32RmStoR(ECX, ECX, EDX, 2); + SHR32CLtoR(EAX); // mem(EAX) >> LWR_SHIFT[shift] + + MOV32ItoR(ECX, (u32)LWR_MASK); + MOV32RmStoR(ECX, ECX, EDX, 2); + + if (IsConst(_Rt_)) { + MOV32ItoR(EDX, iRegs[_Rt_].k); + } else { + MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]); + } + AND32RtoR(EDX, ECX); // _rRt_ & LWR_MASK[shift] + + OR32RtoR(EAX, EDX); + + iRegs[_Rt_].state = ST_UNK; + MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); + } else { +// ADD32ItoR(ESP, 8); + resp+= 8; + } +}*/ + +static void recSB() { +// mem[Rs + Im] = Rt + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (IsConst(_Rt_)) { + MOV8ItoM((u32)&psxM[addr & 0x1fffff], (u8)iRegs[_Rt_].k); + } else { + MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV8RtoM((u32)&psxM[addr & 0x1fffff], EAX); + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (IsConst(_Rt_)) { + MOV8ItoM((u32)&psxH[addr & 0xfff], (u8)iRegs[_Rt_].k); + } else { + MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV8RtoM((u32)&psxH[addr & 0xfff], EAX); + } + return; + } +// SysPrintf("unhandled w8 %x\n", addr); + }*/ + + preMemWrite(1); + CALLFunc((u32)psxMemWrite8); +} + +static void recSH() { +// mem[Rs + Im] = Rt + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (IsConst(_Rt_)) { + MOV16ItoM((u32)&psxM[addr & 0x1fffff], (u16)iRegs[_Rt_].k); + } else { + MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV16RtoM((u32)&psxM[addr & 0x1fffff], EAX); + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (IsConst(_Rt_)) { + MOV16ItoM((u32)&psxH[addr & 0xfff], (u16)iRegs[_Rt_].k); + } else { + MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV16RtoM((u32)&psxH[addr & 0xfff], EAX); + } + return; + } + if (t == 0x1f80) { + if (addr >= 0x1f801c00 && addr < 0x1f801e00) { + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + PUSH32I (addr); + CALL32M ((u32)&SPU_writeRegister); +#ifndef __WIN32__ + resp+= 8; +#endif + return; + } + } +// SysPrintf("unhandled w16 %x\n", addr); + }*/ + + preMemWrite(2); + CALLFunc((u32)psxMemWrite16); +} + +static void recSW() { +// mem[Rs + Im] = Rt + u32 *b1, *b2; +#if 0 + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + LIW(0, addr & 0x1fffff); + STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + LIW(0, (u32)&psxH[addr & 0xfff]); + STWBRX(GetHWReg32(_Rt_), 0, 0); + return; + } + if (t == 0x1f80) { + switch (addr) { + case 0x1f801080: case 0x1f801084: + case 0x1f801090: case 0x1f801094: + case 0x1f8010a0: case 0x1f8010a4: + case 0x1f8010b0: case 0x1f8010b4: + case 0x1f8010c0: case 0x1f8010c4: + case 0x1f8010d0: case 0x1f8010d4: + case 0x1f8010e0: case 0x1f8010e4: + case 0x1f801074: + case 0x1f8010f0: + LIW(0, (u32)&psxH[addr & 0xffff]); + STWBRX(GetHWReg32(_Rt_), 0, 0); + return; + +/* case 0x1f801810: + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + CALL32M((u32)&GPU_writeData); +#ifndef __WIN32__ + resp+= 4; +#endif + return; + + case 0x1f801814: + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + CALL32M((u32)&GPU_writeStatus); +#ifndef __WIN32__ + resp+= 4; +#endif*/ + } + } +// SysPrintf("unhandled w32 %x\n", addr); + } + +/* LIS(0, 0x0079 + ((_Imm_ <= 0) ? 1 : 0)); + CMPLW(GetHWReg32(_Rs_), 0); + BGE_L(b1); + + //SaveContext(); + ADDI(0, GetHWReg32(_Rs_), _Imm_); + RLWINM(0, GetHWReg32(_Rs_), 0, 11, 31); + STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0); + B_L(b2); + + B_DST(b1);*/ +#endif + preMemWrite(4); + CALLFunc((u32)psxMemWrite32); + + //B_DST(b2); +} + +/* +static void recSWBlock(int count) { + u32 *code; + int i, respsave; +// mem[Rs + Im] = Rt + +// iFlushRegs(); + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + code = PSXM(pc); + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + for (i=0; i<count; i++, code++, addr+=4) { + if (IsConst(_fRt_(*code))) { + MOV32ItoM((u32)&psxM[addr & 0x1fffff], iRegs[_fRt_(*code)].k); + } else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_fRt_(*code)]); + MOV32RtoM((u32)&psxM[addr & 0x1fffff], EAX); + } + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + for (i=0; i<count; i++, code++, addr+=4) { + if (!_fRt_(*code)) return; + iRegs[_fRt_(*code)].state = ST_UNK; + + MOV32MtoR(EAX, (u32)&psxH[addr & 0xfff]); + MOV32RtoM((u32)&psxRegs.GPR.r[_fRt_(*code)], EAX); + } + return; + } + } + + SysPrintf("recSWBlock %d: %d\n", count, IsConst(_Rs_)); + iPushOfB(); + CALLFunc((u32)psxMemPointer); +// ADD32ItoR(ESP, 4); + resp+= 4; + + respsave = resp; resp = 0; + TEST32RtoR(EAX, EAX); + j32Ptr[4] = JZ32(0); + XOR32RtoR(ECX, ECX); + for (i=0, code = PSXM(pc); i<count; i++, code++) { + if (IsConst(_fRt_(*code))) { + MOV32ItoR(EDX, iRegs[_fRt_(*code)].k); + } else { + MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_fRt_(*code)]); + } + MOV32RtoRmS(EAX, ECX, 2, EDX); + if (i != (count-1)) INC32R(ECX); + } + j32Ptr[5] = JMP32(0); + x86SetJ32(j32Ptr[4]); + for (i=0, code = PSXM(pc); i<count; i++, code++) { + psxRegs.code = *code; + recSW(); + } + ADD32ItoR(ESP, resp); + x86SetJ32(j32Ptr[5]); + resp = respsave; +} + +extern u32 SWL_MASK[4]; +extern u32 SWL_SHIFT[4]; + +void iSWLk(u32 shift) { + if (IsConst(_Rt_)) { + MOV32ItoR(ECX, iRegs[_Rt_].k); + } else { + MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); + } + SHR32ItoR(ECX, SWL_SHIFT[shift]); + AND32ItoR(EAX, SWL_MASK[shift]); + OR32RtoR (EAX, ECX); +} + +void recSWL() { +// mem[Rs + Im] = Rt Merge mem[Rs + Im] + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]); + iSWLk(addr & 3); + MOV32RtoM((u32)&psxM[addr & 0x1ffffc], EAX); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]); + iSWLk(addr & 3); + MOV32RtoM((u32)&psxH[addr & 0xffc], EAX); + return; + } + } + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + PUSH32R (EAX); + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + + CALLFunc((u32)psxMemRead32); + + ADD32ItoR(ESP, 4); + POP32R (EDX); + AND32ItoR(EDX, 0x3); // shift = addr & 3; + + MOV32ItoR(ECX, (u32)SWL_MASK); + MOV32RmStoR(ECX, ECX, EDX, 2); + AND32RtoR(EAX, ECX); // mem & SWL_MASK[shift] + + MOV32ItoR(ECX, (u32)SWL_SHIFT); + MOV32RmStoR(ECX, ECX, EDX, 2); + if (IsConst(_Rt_)) { + MOV32ItoR(EDX, iRegs[_Rt_].k); + } else { + MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]); + } + SHR32CLtoR(EDX); // _rRt_ >> SWL_SHIFT[shift] + + OR32RtoR (EAX, EDX); + PUSH32R (EAX); + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + + CALLFunc((u32)psxMemWrite32); +// ADD32ItoR(ESP, 8); + resp+= 8; +} + +extern u32 SWR_MASK[4]; +extern u32 SWR_SHIFT[4]; + +void iSWRk(u32 shift) { + if (IsConst(_Rt_)) { + MOV32ItoR(ECX, iRegs[_Rt_].k); + } else { + MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); + } + SHL32ItoR(ECX, SWR_SHIFT[shift]); + AND32ItoR(EAX, SWR_MASK[shift]); + OR32RtoR (EAX, ECX); +} + +void recSWR() { +// mem[Rs + Im] = Rt Merge mem[Rs + Im] + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + MOV32MtoR(EAX, (u32)&psxM[addr & 0x1ffffc]); + iSWRk(addr & 3); + MOV32RtoM((u32)&psxM[addr & 0x1ffffc], EAX); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + MOV32MtoR(EAX, (u32)&psxH[addr & 0xffc]); + iSWRk(addr & 3); + MOV32RtoM((u32)&psxH[addr & 0xffc], EAX); + return; + } + } + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + PUSH32R (EAX); + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + + CALLFunc((u32)psxMemRead32); + + ADD32ItoR(ESP, 4); + POP32R (EDX); + AND32ItoR(EDX, 0x3); // shift = addr & 3; + + MOV32ItoR(ECX, (u32)SWR_MASK); + MOV32RmStoR(ECX, ECX, EDX, 2); + AND32RtoR(EAX, ECX); // mem & SWR_MASK[shift] + + MOV32ItoR(ECX, (u32)SWR_SHIFT); + MOV32RmStoR(ECX, ECX, EDX, 2); + if (IsConst(_Rt_)) { + MOV32ItoR(EDX, iRegs[_Rt_].k); + } else { + MOV32MtoR(EDX, (u32)&psxRegs.GPR.r[_Rt_]); + } + SHL32CLtoR(EDX); // _rRt_ << SWR_SHIFT[shift] + + OR32RtoR (EAX, EDX); + PUSH32R (EAX); + + if (IsConst(_Rs_)) MOV32ItoR(EAX, iRegs[_Rs_].k + _Imm_); + else { + MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); + if (_Imm_) ADD32ItoR(EAX, _Imm_); + } + AND32ItoR(EAX, ~3); + PUSH32R (EAX); + + CALLFunc((u32)psxMemWrite32); +// ADD32ItoR(ESP, 8); + resp+= 8; +}*/ +#endif + +#if 0 +/*REC_FUNC(SLL); +REC_FUNC(SRL); +REC_FUNC(SRA);*/ +#else +static void recSLL() { +// Rd = Rt << Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rt_].k << _Sa_); + } else { + SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} + +static void recSRL() { +// Rd = Rt >> Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rt_].k >> _Sa_); + } else { + SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} + +static void recSRA() { +// Rd = Rt >> Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, (s32)iRegs[_Rt_].k >> _Sa_); + } else { + SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} +#endif + +#pragma mark - shift ops - +#if 0 +/*REC_FUNC(SLLV); +REC_FUNC(SRLV); +REC_FUNC(SRAV);*/ +#else +static void recSLLV() { +// Rd = Rt << Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, iRegs[_Rt_].k << iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SLW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} + +static void recSRLV() { +// Rd = Rt >> Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, iRegs[_Rt_].k >> iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SRW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} + +static void recSRAV() { +// Rd = Rt >> Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, (s32)iRegs[_Rt_].k >> iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SRAW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} +#endif + +//REC_SYS(SYSCALL); +//REC_SYS(BREAK); + +//#if 0*/ +/*int dump;*/ +static void recSYSCALL() { +// dump=1; + iFlushRegs(0); + + ReserveArgs(2); + LIW(PutHWRegSpecial(PSXPC), pc - 4); + LIW(PutHWRegSpecial(ARG1), 0x20); + LIW(PutHWRegSpecial(ARG2), (branch == 1 ? 1 : 0)); + FlushAllHWReg(); + CALLFunc ((u32)psxException); + + branch = 2; + iRet(); +} + +static void recBREAK() { +} +//#endif + +#if 0 +/*REC_FUNC(MFHI); +REC_FUNC(MTHI); +REC_FUNC(MFLO); +REC_FUNC(MTLO);*/ +#else +static void recMFHI() { +// Rd = Hi + if (!_Rd_) return; + + if (IsConst(REG_HI)) { + MapConst(_Rd_, iRegs[REG_HI].k); + } else { + MapCopy(_Rd_, REG_HI); + } +} + +static void recMTHI() { +// Hi = Rs + + if (IsConst(_Rs_)) { + MapConst(REG_HI, iRegs[_Rs_].k); + } else { + MapCopy(REG_HI, _Rs_); + } +} + +static void recMFLO() { +// Rd = Lo + if (!_Rd_) return; + + if (IsConst(REG_LO)) { + MapConst(_Rd_, iRegs[REG_LO].k); + } else { + MapCopy(_Rd_, REG_LO); + } +} + +static void recMTLO() { +// Lo = Rs + + if (IsConst(_Rs_)) { + MapConst(REG_LO, iRegs[_Rs_].k); + } else { + MapCopy(REG_LO, _Rs_); + } +} +#endif + +#pragma mark - branch ops - +#if 0 +/*REC_BRANCH(J); +REC_BRANCH(JR); +REC_BRANCH(JAL); +REC_BRANCH(JALR); +REC_BRANCH(BLTZ); +REC_BRANCH(BGTZ); +REC_BRANCH(BLTZAL); +REC_BRANCH(BGEZAL); +REC_BRANCH(BNE); +REC_BRANCH(BEQ); +REC_BRANCH(BLEZ); +REC_BRANCH(BGEZ);*/ +#else +static void recBLTZ() { +// Branch if Rs < 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k < 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGTZ() { +// Branch if Rs > 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k > 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBLTZAL() { +// Branch if Rs < 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k < 0) { + MapConst(31, pc + 4); + + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + MapConst(31, pc + 4); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGEZAL() { +// Branch if Rs >= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k >= 0) { + MapConst(31, pc + 4); + + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + MapConst(31, pc + 4); + + iBranch(bpc, 0); + pc+=4; +} + +static void recJ() { +// j target + + iJump(_Target_ * 4 + (pc & 0xf0000000)); +} + +static void recJAL() { +// jal target + MapConst(31, pc + 4); + + iJump(_Target_ * 4 + (pc & 0xf0000000)); +} + +static void recJR() { +// jr Rs + + if (IsConst(_Rs_)) { + iJump(iRegs[_Rs_].k); + //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k); + } else { + MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_)); + SetBranch(); + } +} + +static void recJALR() { +// jalr Rs + + if (_Rd_) { + MapConst(_Rd_, pc + 4); + } + + if (IsConst(_Rs_)) { + iJump(iRegs[_Rs_].k); + //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k); + } else { + MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_)); + SetBranch(); + } +} + +static void recBEQ() { +// Branch if Rs == Rt + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (_Rs_ == _Rt_) { + iJump(bpc); + } + else { + if (IsConst(_Rs_) && IsConst(_Rt_)) { + if (iRegs[_Rs_].k == iRegs[_Rt_].k) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + + BEQ_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; + } +} + +static void recBNE() { +// Branch if Rs != Rt + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (_Rs_ == _Rt_) { + iJump(pc+4); + } + else { + if (IsConst(_Rs_) && IsConst(_Rt_)) { + if (iRegs[_Rs_].k != iRegs[_Rt_].k) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + + BNE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; + } +} + +static void recBLEZ() { +// Branch if Rs <= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k <= 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGEZ() { +// Branch if Rs >= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k >= 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} +#endif + +#if 1 +//REC_FUNC(MFC0); +//REC_SYS(MTC0); +//REC_FUNC(CFC0); +//REC_SYS(CTC0); +REC_FUNC(RFE); +//#else +static void recMFC0() { +// Rt = Cop0->Rd + if (!_Rt_) return; + + LWZ(PutHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); +} + +static void recCFC0() { +// Rt = Cop0->Rd + + recMFC0(); +} + +static void recMTC0() { +// Cop0->Rd = Rt + + /*if (IsConst(_Rt_)) { + switch (_Rd_) { + case 12: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k); + break; + case 13: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k & ~(0xfc00)); + break; + default: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k); + break; + } + } else*/ { + switch (_Rd_) { + case 13: + RLWINM(0,GetHWReg32(_Rt_),0,22,15); // & ~(0xfc00) + STW(0, OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); + break; + default: + STW(GetHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); + break; + } + } + + if (_Rd_ == 12 || _Rd_ == 13) { + iFlushRegs(0); + LIW(PutHWRegSpecial(PSXPC), (u32)pc); + FlushAllHWReg(); + CALLFunc((u32)psxTestSWInts); + if(_Rd_ == 12) { + LWZ(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS)); + ORIS(0, 0, 0x8000); + STW(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS)); + } + branch = 2; + iRet(); + } +} + +static void recCTC0() { +// Cop0->Rd = Rt + + recMTC0(); +} +#else +static void recRFE() { + // TODO: implement multiple temp registers or cop0 registers + RLWINM(t1,Status,0,0,27); + RLWINM(Status,Status,30,28,31); + OR(Status,t1,Status); + + MOV32MtoR(EAX, (u32)&psxRegs.CP0.n.Status); + MOV32RtoR(ECX, EAX); + AND32ItoR(EAX, 0xfffffff0); + AND32ItoR(ECX, 0x3c); + SHR32ItoR(ECX, 2); + OR32RtoR (EAX, ECX); + MOV32RtoM((u32)&psxRegs.CP0.n.Status, EAX); + CALLFunc((u32)psxExceptionTest); +} +#endif + +#if 0 +#define CP2_FUNC(f) \ +void gte##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(0, (u32)psxRegs.code); \ + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + FlushAllHWReg(); \ + CALLFunc ((u32)gte##f); \ +} +CP2_FUNC(LWC2); +CP2_FUNC(SWC2); + +#else +#include "pGte.h" +#endif +// + +static void recHLE() { + iFlushRegs(0); + FlushAllHWReg(); + + if ((psxRegs.code & 0x3ffffff) == (psxRegs.code & 0x7)) { + CALLFunc((u32)psxHLEt[psxRegs.code & 0x7]); + } else { + // somebody else must have written to current opcode for this to happen!!!! + CALLFunc((u32)psxHLEt[0]); // call dummy function + } + + count = (idlecyclecount + (pc - pcold) / 4 + 20) * BIAS; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + Return(); + + branch = 2; +} + +// + +static void (*recBSC[64])() = { + recSPECIAL, recREGIMM, recJ , recJAL , recBEQ , recBNE , recBLEZ, recBGTZ, + recADDI , recADDIU , recSLTI, recSLTIU, recANDI, recORI , recXORI, recLUI , + recCOP0 , recNULL , recCOP2, recNULL , recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL , recNULL, recNULL, recNULL, recNULL, + recLB , recLH , recLWL , recLW , recLBU , recLHU , recLWR , recNULL, + recSB , recSH , recSWL , recSW , recNULL, recNULL, recSWR , recNULL, + recNULL , recNULL , recLWC2, recNULL , recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recSWC2, recHLE , recNULL, recNULL, recNULL, recNULL +}; + +static void (*recSPC[64])() = { + recSLL , recNULL, recSRL , recSRA , recSLLV , recNULL , recSRLV, recSRAV, + recJR , recJALR, recNULL, recNULL, recSYSCALL, recBREAK, recNULL, recNULL, + recMFHI, recMTHI, recMFLO, recMTLO, recNULL , recNULL , recNULL, recNULL, + recMULT, recMULTU, recDIV, recDIVU, recNULL , recNULL , recNULL, recNULL, + recADD , recADDU, recSUB , recSUBU, recAND , recOR , recXOR , recNOR , + recNULL, recNULL, recSLT , recSLTU, recNULL , recNULL , recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL , recNULL , recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL , recNULL , recNULL, recNULL +}; + +static void (*recREG[32])() = { + recBLTZ , recBGEZ , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recBLTZAL, recBGEZAL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void (*recCP0[32])() = { + recMFC0, recNULL, recCFC0, recNULL, recMTC0, recNULL, recCTC0, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recRFE , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void (*recCP2[64])() = { + recBASIC, recRTPS , recNULL , recNULL, recNULL, recNULL , recNCLIP, recNULL, // 00 + recNULL , recNULL , recNULL , recNULL, recOP , recNULL , recNULL , recNULL, // 08 + recDPCS , recINTPL, recMVMVA, recNCDS, recCDP , recNULL , recNCDT , recNULL, // 10 + recNULL , recNULL , recNULL , recNCCS, recCC , recNULL , recNCS , recNULL, // 18 + recNCT , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 20 + recSQR , recDCPL , recDPCT , recNULL, recNULL, recAVSZ3, recAVSZ4, recNULL, // 28 + recRTPT , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 30 + recNULL , recNULL , recNULL , recNULL, recNULL, recGPF , recGPL , recNCCT // 38 +}; + +static void (*recCP2BSC[32])() = { + recMFC2, recNULL, recCFC2, recNULL, recMTC2, recNULL, recCTC2, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void recRecompile() { + //static int recCount = 0; + char *p; + u32 *ptr; + int i; + + cop2readypc = 0; + idlecyclecount = 0; + + // initialize state variables + UniqueRegAlloc = 1; + HWRegUseCount = 0; + DstCPUReg = -1; + memset(HWRegisters, 0, sizeof(HWRegisters)); + for (i=0; i<NUM_HW_REGISTERS; i++) + HWRegisters[i].code = cpuHWRegisters[NUM_HW_REGISTERS-i-1]; + + // reserve the special psxReg register + HWRegisters[0].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED; + HWRegisters[0].private = PSXREGS; + HWRegisters[0].k = (u32)&psxRegs; + + HWRegisters[1].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED; + HWRegisters[1].private = PSXMEM; + HWRegisters[1].k = (u32)&psxM; + + // reserve the special psxRegs.cycle register + //HWRegisters[1].usage = HWUSAGE_SPECIAL | HWUSAGE_RESERVED | HWUSAGE_HARDWIRED; + //HWRegisters[1].private = CYCLECOUNT; + + //memset(iRegs, 0, sizeof(iRegs)); + for (i=0; i<NUM_REGISTERS; i++) { + iRegs[i].state = ST_UNK; + iRegs[i].reg = -1; + } + iRegs[0].k = 0; + iRegs[0].state = ST_CONST; + + /* if ppcPtr reached the mem limit reset whole mem */ + if (((u32)ppcPtr - (u32)recMem) >= (RECMEM_SIZE - 0x10000)) + recReset(); + + ppcAlign(/*32*/4); + ptr = ppcPtr; + + // give us write access + //mprotect(recMem, RECMEM_SIZE, PROT_EXEC|PROT_READ|PROT_WRITE); + + // tell the LUT where to find us + PC_REC32(psxRegs.pc) = (u32)ppcPtr; + + pcold = pc = psxRegs.pc; + + //SysPrintf("RecCount: %i\n", recCount++); + + for (count=0; count<500;) { + p = (char *)PSXM(pc); + if (p == NULL) recError(); + psxRegs.code = SWAP32(*(u32 *)p); +/* + if ((psxRegs.code >> 26) == 0x23) { // LW + int i; + u32 code; + + for (i=1;; i++) { + p = (char *)PSXM(pc+i*4); + if (p == NULL) recError(); + code = *(u32 *)p; + + if ((code >> 26) != 0x23 || + _fRs_(code) != _Rs_ || + _fImm_(code) != (_Imm_+i*4)) + break; + } + if (i > 1) { + recLWBlock(i); + pc = pc + i*4; continue; + } + } + + if ((psxRegs.code >> 26) == 0x2b) { // SW + int i; + u32 code; + + for (i=1;; i++) { + p = (char *)PSXM(pc+i*4); + if (p == NULL) recError(); + code = *(u32 *)p; + + if ((code >> 26) != 0x2b || + _fRs_(code) != _Rs_ || + _fImm_(code) != (_Imm_+i*4)) + break; + } + if (i > 1) { + recSWBlock(i); + pc = pc + i*4; continue; + } + }*/ + + pc+=4; count++; +// iFlushRegs(0); // test + recBSC[psxRegs.code>>26](); + + if (branch) { + branch = 0; + //if (dump) iDumpBlock(ptr); + goto done; + } + } + + iFlushRegs(pc); + + LIW(PutHWRegSpecial(PSXPC), pc); + + iRet(); + +done:; +#if 0 + MakeDataExecutable(ptr, ((u8*)ppcPtr)-((u8*)ptr)); +#else + u32 a = (u32)(u8*)ptr; + while(a < (u32)(u8*)ppcPtr) { + __asm__ __volatile__("icbi 0,%0" : : "r" (a)); + __asm__ __volatile__("dcbst 0,%0" : : "r" (a)); + a += 4; + } + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); +#endif + +#if 1 + sprintf((char *)ppcPtr, "PC=%08x", pcold); + ppcPtr += strlen((char *)ppcPtr); +#endif + + //mprotect(recMem, RECMEM_SIZE, PROT_EXEC|PROT_READ/*|PROT_WRITE*/); +} + + +R3000Acpu psxRec = { + recInit, + recReset, + recExecute, + recExecuteBlock, + recClear, + recShutdown +}; + diff --git a/libpcsxcore/ppc/pasm.s b/libpcsxcore/ppc/pasm.s new file mode 100644 index 0000000..96891b4 --- /dev/null +++ b/libpcsxcore/ppc/pasm.s @@ -0,0 +1,124 @@ + + +#define OLD_REGISTER_OFFSET (19*4) +#define SP_SIZE (OLD_REGISTER_OFFSET+4+8) + +/*asm void recRun(register void (*func)(), register u32 hw1, register u32 hw2)*/ + .text + .align 4 + .globl recRun +recRun: + /* prologue code */ + mflr r0 + stmw r13, -(32-13)*4(r1) + stw r0, 4(r1) + stwu r1, -((32-13)*4+8)(r1) + + /* execute code */ + mtctr r3 + mr r31, r4 + mr r30, r5 + bctrl +/* +} +asm void returnPC() +{*/ + .text + .align 4 + .globl returnPC +returnPC: + // end code + lwz r0, (32-13)*4+8+4(r1) + addi r1, r1, (32-13)*4+8 + mtlr r0 + lmw r13, -(32-13)*4(r1) + blr +//}*/ + +// Memory functions that only works with a linear memory + + .text + .align 4 + .globl dynMemRead8 +dynMemRead8: +// assumes that memory pointer is in r30 + addis r2,r3,-0x1f80 + srwi. r4,r2,16 + bne+ .norm8 + cmplwi r2,0x1000 + blt- .norm8 + b psxHwRead8 +.norm8: + clrlwi r5,r3,3 + lbzx r3,r5,r30 + blr + + .text + .align 4 + .globl dynMemRead16 +dynMemRead16: +// assumes that memory pointer is in r30 + addis r2,r3,-0x1f80 + srwi. r4,r2,16 + bne+ .norm16 + cmplwi r2,0x1000 + blt- .norm16 + b psxHwRead16 +.norm16: + clrlwi r5,r3,3 + lhbrx r3,r5,r30 + blr + + .text + .align 4 + .globl dynMemRead32 +dynMemRead32: +// assumes that memory pointer is in r30 + addis r2,r3,-0x1f80 + srwi. r4,r2,16 + bne+ .norm32 + cmplwi r2,0x1000 + blt- .norm32 + b psxHwRead32 +.norm32: + clrlwi r5,r3,3 + lwbrx r3,r5,r30 + blr + +/* + N P Z + 0 0 0 X +- 0 0 1 X + 1 0 0 X + 1 0 1 X + +P | (!N & Z) +P | !(N | !Z) +*/ + + .text + .align 4 + .globl dynMemWrite32 +dynMemWrite32: +// assumes that memory pointer is in r30 + addis r2,r3,-0x1f80 + srwi. r5,r2,16 + bne+ .normw32 + cmplwi r2,0x1000 + blt .normw32 + b psxHwWrite32 +.normw32: + mtcrf 0xFF, r3 + clrlwi r5,r3,3 + crandc 0, 2, 0 + cror 2, 1, 0 + bne+ .okw32 + // write test + li r2,0x0130 + addis r2,r2,0xfffe + cmplw r3,r2 + bnelr +.okw32: + stwbrx r4,r5,r30 + blr + diff --git a/libpcsxcore/ppc/ppc.c b/libpcsxcore/ppc/ppc.c new file mode 100644 index 0000000..efaf8b6 --- /dev/null +++ b/libpcsxcore/ppc/ppc.c @@ -0,0 +1,32 @@ +/* + * ix86 core v0.5.1 + * Authors: linuzappz <linuzappz@pcsx.net> + * alexey silinov + */ + +#include <stdio.h> +#include <string.h> + +#include "ppc.h" + +// General Purpose hardware registers +int cpuHWRegisters[NUM_HW_REGISTERS] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +u32 *ppcPtr; + +void ppcInit() { +} +void ppcSetPtr(u32 *ptr) { + ppcPtr = ptr; +} +void ppcAlign(int bytes) { + // forward align + ppcPtr = (u32*)(((u32)ppcPtr + bytes) & ~(bytes - 1)); +} + +void ppcShutdown() { +} + diff --git a/libpcsxcore/ppc/ppc.h b/libpcsxcore/ppc/ppc.h new file mode 100644 index 0000000..a6134d4 --- /dev/null +++ b/libpcsxcore/ppc/ppc.h @@ -0,0 +1,60 @@ +/* + * ppc definitions v0.5.1 + * Authors: linuzappz <linuzappz@pcsx.net> + * alexey silinov + */ + +#ifndef __PPC_H__ +#define __PPC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// include basic types +#include "../psxcommon.h" +#include "ppc_mnemonics.h" + +#define NUM_HW_REGISTERS 29 + +/* general defines */ +#define write8(val) *(u8 *)ppcPtr = val; ppcPtr++; +#define write16(val) *(u16*)ppcPtr = val; ppcPtr+=2; +#define write32(val) *(u32*)ppcPtr = val; ppcPtr+=4; +#define write64(val) *(u64*)ppcPtr = val; ppcPtr+=8; + +#define CALLFunc(FUNC) \ +{ \ + u32 _func = (FUNC); \ + ReleaseArgs(); \ + if ((_func & 0x1fffffc) == _func) { \ + BLA(_func); \ + } else { \ + LIW(0, _func); \ + MTCTR(0); \ + BCTRL(); \ + } \ +} + +extern int cpuHWRegisters[NUM_HW_REGISTERS]; + +extern u32 *ppcPtr; +extern u8 *j8Ptr[32]; +extern u32 *j32Ptr[32]; + +void ppcInit(); +void ppcSetPtr(u32 *ptr); +void ppcShutdown(); + +void ppcAlign(int bytes); +void returnPC(); +void recRun(void (*func)(), u32 hw1, u32 hw2); +u8 dynMemRead8(u32 mem); +u16 dynMemRead16(u32 mem); +u32 dynMemRead32(u32 mem); +void dynMemWrite32(u32 mem, u32 val); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/libpcsxcore/ppc/ppc_mnemonics.h b/libpcsxcore/ppc/ppc_mnemonics.h new file mode 100644 index 0000000..3cc6525 --- /dev/null +++ b/libpcsxcore/ppc/ppc_mnemonics.h @@ -0,0 +1,529 @@ +// ppc_mnemonics.h + +#define INSTR (*(ppcPtr)++) + +/* Link register related */ +#define MFLR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0802A6 | (_reg << 21));} + +#define MTLR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0803A6 | (_reg << 21));} + +#define MTCTR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0903A6 | (_reg << 21));} + +#define BLR() \ + {INSTR = (0x4E800020);} + +#define BGTLR() \ + {INSTR = (0x4D810020);} + + +/* Load ops */ +#define LI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x38000000 | (_reg << 21) | ((IMM) & 0xffff));} + +#define LIS(REG_DST, IMM) \ + {int _dst = (REG_DST); \ + INSTR = (0x3C000000 | (_dst << 21) | ((IMM) & 0xffff));} + +#define LWZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0x80000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LWZX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00002E | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LWBRX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00042C | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LHZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xA0000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LHA(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xA8000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LHBRX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00062C | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LBZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0x88000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LMW(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xB8000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + + + +/* Store ops */ +#define STMW(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0xBC000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STW(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x90000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STWBRX(REG_SRC, REG, REG_OFF) \ + {int _reg = (REG), _src=(REG_SRC), _off = (REG_OFF); \ + INSTR = (0x7C00052C | (_src << 21) | (_reg << 16) | (_off << 11));} + +#define STH(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0xB0000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STHBRX(REG_SRC, REG, REG_OFF) \ + {int _reg = (REG), _src=(REG_SRC), _off = (REG_OFF); \ + INSTR = (0x7C00072C | (_src << 21) | (_reg << 16) | (_off << 11));} + +#define STB(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x98000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STWU(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x94000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + + +/* Arithmic ops */ +#define ADDI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x38000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDIS(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x3C000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define MR(REG_DST, REG_SRC) \ + {int __src = (REG_SRC); int __dst=(REG_DST); \ + if (__src != __dst) {ADDI(__dst, __src, 0)}} + +#define ADD(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000214 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000614 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDEO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000514 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDE(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000114 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDCO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000414 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDIC(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x30000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDIC_(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x34000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDZE(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000194 | (_dst << 21) | (_src << 16));} + +#define SUBF(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000050 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000450 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFC(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000010 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFE(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000110 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFCO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000410 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFCO_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000411 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUB(REG_DST, REG1, REG2) \ + {SUBF(REG_DST, REG2, REG1)} + +#define SUBO(REG_DST, REG1, REG2) \ + {SUBFO(REG_DST, REG2, REG1)} + +#define SUBCO(REG_DST, REG1, REG2) \ + {SUBFCO(REG_DST, REG2, REG1)} + +#define SUBCO_(REG_DST, REG1, REG2) \ + {SUBFCO_(REG_DST, REG2, REG1)} + +#define SRAWI(REG_DST, REG_SRC, SHIFT) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000670 | (_src << 21) | (_dst << 16) | (SHIFT << 11));} + +#define MULHW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000096 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULLW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0001D6 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULHWU(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000016 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULLI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x1C000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define DIVW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0003D6 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define DIVWU(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000396 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + + +/* Branch ops */ +#define B_FROM(VAR) VAR = ppcPtr +#define B_DST(VAR) *VAR = *VAR | (((s16)((u32)ppcPtr - (u32)VAR)) & 0xfffc) + +#define B(DST) \ + {INSTR = (0x48000000 | (((s32)(((DST)+1)<<2)) & 0x3fffffc));} + +#define B_L(VAR) \ + {B_FROM(VAR); INSTR = (0x48000000);} + +#define BA(DST) \ + {INSTR = (0x48000002 | ((s32)((DST) & 0x3fffffc)));} + +#define BLA(DST) \ + {INSTR = (0x48000003 | ((s32)((DST) & 0x3fffffc)));} + +#define BNS(DST) \ + {INSTR = (0x40830000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BNE(DST) \ + {INSTR = (0x40820000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BNE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40820000);} + +#define BEQ(DST) \ + {INSTR = (0x41820000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BEQ_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41820000);} + +#define BLT(DST) \ + {INSTR = (0x41800000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BLT_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41800000);} + +#define BGT(DST) \ + {INSTR = (0x41810000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BGT_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41810000);} + +#define BGE(DST) \ + {INSTR = (0x40800000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BGE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40800000);} + +#define BLE(DST) \ + {INSTR = (0x40810000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BLE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40810000);} + +#define BCTRL() \ + {INSTR = (0x4E800421);} + +#define BCTR() \ + {INSTR = (0x4E800420);} + + +/* compare ops */ +#define CMPLWI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x28000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLWI2(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x29000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLWI7(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2B800000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLW(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C000040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPLW1(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C800040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPLW2(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7D000040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C000000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW1(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C800000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW2(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7D000000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPWI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2C000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPWI2(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2D000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define MTCRF(MASK, REG) \ + {int _reg = (REG); \ + INSTR = (0x7C000120 | (_reg << 21) | (((MASK)&0xff)<<12));} + +#define MFCR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C000026 | (_reg << 21));} + +#define CROR(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000382 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRXOR(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000182 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRNAND(CR_DST, CR1, CR2) \ + {INSTR = (0x4C0001C2 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRANDC(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000102 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + + +/* shift ops */ +#define RLWINM(REG_DST, REG_SRC, SHIFT, START, END) \ + {int _src = (REG_SRC); int _dst = (REG_DST); \ + INSTR = (0x54000000 | (_src << 21) | (_dst << 16) | (SHIFT << 11) | (START << 6) | (END << 1));} + +#define RLWINM_(REG_DST, REG_SRC, SHIFT, START, END) \ + {int _src = (REG_SRC); int _dst = (REG_DST); \ + INSTR = (0x54000001 | (_src << 21) | (_dst << 16) | (SHIFT << 11) | (START << 6) | (END << 1));} + +#define CLRRWI(REG_DST, REG_SRC, LEN) \ + RLWINM(REG_DST, REG_SRC, 0, 0, 31-LEN) + +#define SLWI(REG_DST, REG_SRC, SHIFT) \ + {int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + {RLWINM(REG_DST, REG_SRC, _shift, 0, 31-_shift)}} + +#define SRWI(REG_DST, REG_SRC, SHIFT) \ + {int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + RLWINM(REG_DST, REG_SRC, 32-_shift, _shift, 31)} + +#define SLW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000030 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000430 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRAW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000630 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRAWI(REG_DST, REG_SRC, SHIFT) \ + {int _src = (REG_SRC); int _dst = (REG_DST); int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + INSTR = (0x7C000670 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define RLWNM(REG_DST, REG_SRC, REG_SHIFT, START, END) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x5C000000 | (_src << 21) | (_dst << 16) | (_shift << 11) | (START << 6) | (END << 1));} + +/* other ops */ +#define ORI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC), _imm = (IMM); int _dst = (REG_DST); \ + if (!((_imm == 0) && ((_src^_dst) == 0))) \ + INSTR = (0x60000000 | (_src << 21) | (_dst << 16) | (_imm & 0xffff));} + +#define ORIS(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC), _imm = (IMM); int _dst = (REG_DST); \ + if (!((_imm == 0) && ((_src^_dst) == 0))) \ + INSTR = (0x64000000 | (_src << 21) | (_dst << 16) | (_imm & 0xffff));} + +#define OR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000378 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define OR_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000379 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define XORI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x68000000 | (_src << 21) | (_dst << 16) | ((IMM) & 0xffff));} + +#define XOR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000278 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define XOR_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000279 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define ANDI_(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x70000000 | (_src << 21) | (_dst << 16) | ((IMM) & 0xffff));} + +#define AND(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000038 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define NOR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0000f8 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define NEG(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C0000D0 | (_dst << 21) | (_src << 16));} + +#define NOP() \ + {INSTR = 0x60000000;} + +#define MCRXR(CR_DST) \ + {INSTR = (0x7C000400 | (CR_DST << 23));} + +#define EXTSB(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000774 | (_src << 21) | (_dst << 16));} + +#define EXTSH(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000734 | (_src << 21) | (_dst << 16));} + + +/* floating point ops */ +#define FDIVS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC000024 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FDIV(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC000024 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FMULS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC000032 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FMUL(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC000032 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FADDS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC00002A | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FADD(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC00002A | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FRSP(FPR_DST, FPR_SRC) \ + {INSTR = (0xFC000018 | (FPR_DST << 21) | (FPR_SRC << 11));} + +#define FCTIW(FPR_DST, FPR_SRC) \ + {INSTR = (0xFC00001C | (FPR_DST << 21) | (FPR_SRC << 11));} + + +#define LFS(FPR_DST, OFFSET, REG) \ + {INSTR = (0xC0000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define STFS(FPR_DST, OFFSET, REG) \ + {INSTR = (0xD0000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define LFD(FPR_DST, OFFSET, REG) \ + {INSTR = (0xC8000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define STFD(FPR_DST, OFFSET, REG) \ + {INSTR = (0xD8000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + + + +/* extra combined opcodes */ +#if 1 +#define LIW(REG, IMM) /* Load Immidiate Word */ \ +{ \ + int __reg = (REG); u32 __imm = (u32)(IMM); \ + if ((s32)__imm == (s32)((s16)__imm)) \ + { \ + LI(__reg, (s32)((s16)__imm)); \ + } else if (__reg == 0) { \ + LIS(__reg, (((u32)__imm)>>16)); \ + if ((((u32)__imm) & 0xffff) != 0) \ + { \ + ORI(__reg, __reg, __imm); \ + } \ + } else { \ + if ((((u32)__imm) & 0xffff) == 0) { \ + LIS(__reg, (((u32)__imm)>>16)); \ + } else { \ + LI(__reg, __imm); \ + if ((__imm & 0x8000) == 0) { \ + ADDIS(__reg, __reg, ((u32)__imm)>>16); \ + } else { \ + ADDIS(__reg, __reg, ((((u32)__imm)>>16) & 0xffff) + 1); \ + } \ + } \ + /*if ((((u32)__imm) & 0xffff) != 0) \ + { \ + ORI(__reg, __reg, __imm); \ + }*/ \ + } \ +} +#else +#define LIW(REG, IMM) /* Load Immidiate Word */ \ +{ \ + int __reg = (REG); u32 __imm = (u32)(IMM); \ + if ((s32)__imm == (s32)((s16)__imm)) \ + { \ + LI(__reg, (s32)((s16)__imm)); \ + } \ + else \ + { \ + LIS(__reg, (((u32)__imm)>>16)); \ + if ((((u32)__imm) & 0xffff) != 0) \ + { \ + ORI(__reg, __reg, __imm); \ + } \ + } \ +} +#endif diff --git a/libpcsxcore/ppc/reguse.c b/libpcsxcore/ppc/reguse.c new file mode 100644 index 0000000..47d70a5 --- /dev/null +++ b/libpcsxcore/ppc/reguse.c @@ -0,0 +1,419 @@ + +#include "../psxcommon.h" +#include "reguse.h" + +#include "../r3000a.h" + +//#define SAME_CYCLE_MODE + +static const int useBSC[64] = { + /*recSPECIAL*/ REGUSE_SUB | REGUSE_SPECIAL, + /*recREGIMM*/ REGUSE_SUB | REGUSE_REGIMM, + /*recJ*/ REGUSE_JUMP, + /*recJAL*/ REGUSE_JUMP | REGUSE_R31_W, + /*recBEQ*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, + /*recBNE*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, + /*recBLEZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recBGTZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recADDI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recADDIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recSLTI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recSLTIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recANDI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recXORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recLUI*/ REGUSE_ACC | REGUSE_RT_W, + /*recCOP0*/ REGUSE_SUB | REGUSE_COP0, + REGUSE_NONE, + /*recCOP2*/ REGUSE_SUB | REGUSE_COP2, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recLB*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLH*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLWL*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, + /*recLW*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLBU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLHU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLWR*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, + REGUSE_NONE, + /*recSB*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + /*recSH*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + /*recSWL*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, + /*recSW*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + REGUSE_NONE, REGUSE_NONE, + /*recSWR*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recLWC2*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_COP2_RT_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recSWC2*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_COP2_RT_R, + /*recHLE*/ REGUSE_UNKNOWN, // TODO: can this be done in a better way + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE +}; + +static const int useSPC[64] = { + /*recSLL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, + /*recSRL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + /*recSRA*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + /*recSLLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, + /*recSRLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSRAV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recJR*/ REGUSE_JUMPR | REGUSE_RS_R, + /*recJALR*/ REGUSE_JUMPR | REGUSE_RS_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, + /*rSYSCALL*/ REGUSE_SYS | REGUSE_PC | REGUSE_COP0_STATUS | REGUSE_EXCEPTION, + /*recBREAK*/ REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recMFHI*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_HI_R, + /*recMTHI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_HI_W, + /*recMFLO*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_LO_R, + /*recMTLO*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_LO_W, + REGUSE_NONE, REGUSE_NONE , REGUSE_NONE, REGUSE_NONE, + /*recMULT*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recMULTU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recDIV*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recDIVU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recADD*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recADDU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSUB*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSUBU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recAND*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recXOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recNOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, + /*recSLT*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSLTU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE +}; + +static const int useREGIMM[32] = { + /*recBLTZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recBGEZ*/ REGUSE_BRANCH | REGUSE_RS_R, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recBLTZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, + /*recBGEZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE +}; + +static const int useCP0[32] = { + /*recMFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, + REGUSE_NONE, + /*recCFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, + REGUSE_NONE, + /*recMTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, + REGUSE_NONE, + /*recCTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recRFE*/ REGUSE_LOGIC | REGUSE_COP0_STATUS, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE +}; + +// TODO: make more explicit +static const int useCP2[64] = { + /*recBASIC*/ REGUSE_SUB | REGUSE_BASIC, + /*recRTPS*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recNCLIP*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recOP*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recDPCS*/ REGUSE_GTE, + /*recINTPL*/ REGUSE_GTE, + /*recMVMVA*/ REGUSE_GTE, + /*recNCDS*/ REGUSE_GTE, + /*recCDP*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCDT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recNCCS*/ REGUSE_GTE, + /*recCC*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCS*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, + /*recSQR*/ REGUSE_GTE, + /*recDCPL*/ REGUSE_GTE, + /*recDPCT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, + /*recAVSZ3*/ REGUSE_GTE, + /*recAVSZ4*/ REGUSE_GTE, + REGUSE_NONE, + /*recRTPT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recGPF*/ REGUSE_GTE, + /*recGPL*/ REGUSE_GTE, + /*recNCCT*/ REGUSE_GTE +}; + +static const int useCP2BSC[32] = { + /*recMFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, + REGUSE_NONE, + /*recCFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, + REGUSE_NONE, + /*recMTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, + REGUSE_NONE, + /*recCTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE +}; + +static int getRegUse(u32 code) __attribute__ ((__pure__)); +static int getRegUse(u32 code) +{ + int use = useBSC[code>>26]; + + switch (use & REGUSE_SUBMASK) { + case REGUSE_NONE: + break; + case REGUSE_SPECIAL: + use = useSPC[_fFunct_(code)]; + break; + case REGUSE_REGIMM: + use = useREGIMM[_fRt_(code)]; + break; + case REGUSE_COP0: + use = useCP0[_fRs_(code)]; + break; + case REGUSE_COP2: + use = useCP2[_fFunct_(code)]; + if ((use & REGUSE_SUBMASK) == REGUSE_BASIC) + use = useCP2BSC[_fRs_(code)]; + break; + default: + use = REGUSE_UNKNOWN; + break; + } + + if ((use & REGUSE_COP0_RD_W)) { + if (_fRd_(code) == 12 || _fRd_(code) == 13) { + use = REGUSE_UNKNOWN; + } + } + + return use; +} + +/* returns how psxreg is used in the code instruction */ +int useOfPsxReg(u32 code, int use, int psxreg) +{ + int retval = REGUSE_NONE; + + // get use if it wasn't supplied + if (-1 == use) use = getRegUse(code); + + // if we don't know what the usage is, assume it's read from + if (REGUSE_UNKNOWN == use) return REGUSE_READ; + + if (psxreg < 32) { + // check for 3 standard types + if ((use & REGUSE_RT) && _fRt_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RT_R) ? REGUSE_READ:0) | ((use & REGUSE_RT_W) ? REGUSE_WRITE:0); + } + if ((use & REGUSE_RS) && _fRs_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RS_R) ? REGUSE_READ:0) | ((use & REGUSE_RS_W) ? REGUSE_WRITE:0); + } + if ((use & REGUSE_RD) && _fRd_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RD_R) ? REGUSE_READ:0) | ((use & REGUSE_RD_W) ? REGUSE_WRITE:0); + } + // some instructions explicitly writes to r31 + if ((use & REGUSE_R31_W) && 31 == psxreg) { + retval |= REGUSE_WRITE; + } + } else if (psxreg == 32) { // Special register LO + retval |= ((use & REGUSE_LO_R) ? REGUSE_READ:0) | ((use & REGUSE_LO_W) ? REGUSE_WRITE:0); + } else if (psxreg == 33) { // Special register HI + retval |= ((use & REGUSE_HI_R) ? REGUSE_READ:0) | ((use & REGUSE_HI_W) ? REGUSE_WRITE:0); + } + + return retval; +} + +//#define NOREGUSE_FOLLOW + +static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) __attribute__ ((__pure__, __unused__)); +static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) +{ + u32 *ptr, code, bPC = 0; + int i, use, reguse = 0; + + for (i=0; i<numInstr; ) { + // load current instruction + ptr = PSXM(pc); + if (ptr==NULL) { + // going nowhere... might as well assume a write, since we will hopefully never reach here + reguse = REGUSE_WRITE; + break; + } + code = SWAP32(*ptr); + // get usage patterns for instruction + use = getRegUse(code); + // find the use of psxreg in the instruction + reguse = useOfPsxReg(code, use, psxreg); + + // return if we have found a use + if (reguse != REGUSE_NONE) + break; + + // goto next instruction + pc += 4; + i++; + + // check for code branches/jumps + if (i != numInstr) { + if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) { +#ifndef NOREGUSE_FOLLOW + // check delay slot + reguse = _nextPsxRegUse(pc, psxreg, 1); + if (reguse != REGUSE_NONE) break; + + bPC = _fImm_(code) * 4 + pc; + reguse = _nextPsxRegUse(pc+4, psxreg, (numInstr-i-1)/2); + if (reguse != REGUSE_NONE) { + int reguse2 = _nextPsxRegUse(bPC, psxreg, (numInstr-i-1)/2); + if (reguse2 != REGUSE_NONE) + reguse |= reguse2; + else + reguse = REGUSE_NONE; + } +#endif + break; + } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) { +#ifndef NOREGUSE_FOLLOW + // check delay slot + reguse = _nextPsxRegUse(pc, psxreg, 1); + if (reguse != REGUSE_NONE) break; + + bPC = _fTarget_(code) * 4 + (pc & 0xf0000000); + reguse = _nextPsxRegUse(bPC, psxreg, numInstr-i-1); +#endif + break; + } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR) { +#ifndef NOREGUSE_FOLLOW + // jump to unknown location - bail after checking delay slot + reguse = _nextPsxRegUse(pc, psxreg, 1); +#endif + break; + } else if ((use & REGUSE_TYPEM) == REGUSE_SYS) { + break; + } + } + } + + return reguse; +} + + +int nextPsxRegUse(u32 pc, int psxreg) +{ +#if 1 + if (psxreg == 0) + return REGUSE_WRITE; // pretend we are writing to it to fool compiler + +#ifdef SAME_CYCLE_MODE + return REGUSE_READ; +#else + return _nextPsxRegUse(pc, psxreg, 80); +#endif +#else + u32 code, bPC = 0; + int use, reguse = 0, reguse1 = 0, b = 0, i, index = 0; + +retry: + for (i=index; i<80; i++) { + code = PSXMu32(pc); + use = getRegUse(code); + reguse = useOfPsxReg(code, use, psxreg); + + if (reguse != REGUSE_NONE) break; + + pc += 4; + if ((use & REGUSE_TYPEM) == REGUSE_BRANCH) { + if (b == 0) { + bPC = _fImm_(code) * 4 + pc; + index = i+1; + } + b += 1; // TODO: follow branches + continue; + } else if ((use & REGUSE_TYPEM) == REGUSE_JUMP) { + if (b == 0) { + bPC = _fTarget_(code) * 4 + (pc & 0xf0000000); + } + b = 2; + continue; + } else if ((use & REGUSE_TYPEM) == REGUSE_JUMPR || + (use & REGUSE_TYPEM) == REGUSE_SYS) { + b = 2; + continue; + } + + if (b == 2 && bPC && index == 0) { + pc = bPC; bPC = 0; + b = 1; + } + if (b >= 2) break; // only follow 1 branch + } + if (reguse == REGUSE_NONE) return reguse; + + if (bPC) { + reguse1 = reguse; + pc = bPC; bPC = 0; + b = 1; + goto retry; + } + + return reguse1 | reguse; +#endif +} + +int isPsxRegUsed(u32 pc, int psxreg) +{ + int use = nextPsxRegUse(pc, psxreg); + + if (use == REGUSE_NONE) + return 2; // unknown use - assume it is used + else if (use & REGUSE_READ) + return 1; // the next use is a read + else + return 0; // the next use is a write, i.e. current value is not important +} diff --git a/libpcsxcore/ppc/reguse.h b/libpcsxcore/ppc/reguse.h new file mode 100644 index 0000000..de42dec --- /dev/null +++ b/libpcsxcore/ppc/reguse.h @@ -0,0 +1,83 @@ +#ifndef __REGUSE_H__ +#define __REGUSE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// include basic types +#include "../psxcommon.h" + +#define REGUSE_NONE 0x0000 +#define REGUSE_UNKNOWN 0x0001 + +//sub functions +#define REGUSE_SPECIAL 0x0002 +#define REGUSE_REGIMM 0x0004 +#define REGUSE_COP0 0x0006 +#define REGUSE_COP2 0x0008 +#define REGUSE_BASIC 0x000a +#define REGUSE_SUBMASK 0x000e /* sub function mask */ + +#define REGUSE_ACC 0x0010 /* accumulator */ +#define REGUSE_LOGIC 0x0020 /* logic operations */ +#define REGUSE_MULT 0x0030 /* multiplier */ +#define REGUSE_JUMP 0x0040 /* jump to dest */ +#define REGUSE_JUMPR 0x0050 /* jump to reg */ +#define REGUSE_BRANCH 0x0060 /* branch */ +#define REGUSE_MEM_R 0x0070 /* read from memory */ +#define REGUSE_MEM_W 0x0080 /* write to memory */ +#define REGUSE_MEM 0x0090 /* read and write to memory */ +#define REGUSE_SYS 0x00a0 /* syscall */ +#define REGUSE_GTE 0x00b0 /* gte operation */ +#define REGUSE_SUB 0x00f0 /* sub usage */ +#define REGUSE_TYPEM 0x00f0 /* type mask */ + + +#define REGUSE_RS_R 0x0100 +#define REGUSE_RS_W 0x0200 +#define REGUSE_RS (REGUSE_RS_R | REGUSE_RS_W) +#define REGUSE_RT_R 0x0400 +#define REGUSE_RT_W 0x0800 +#define REGUSE_RT (REGUSE_RT_R | REGUSE_RT_W) +#define REGUSE_RD_R 0x1000 +#define REGUSE_RD_W 0x2000 +#define REGUSE_RD (REGUSE_RD_R | REGUSE_RD_W) + +#define REGUSE_R31_W 0x4000 /* writes to link register (r31) */ +#define REGUSE_PC 0x8000 /* reads pc */ + +#define REGUSE_LO_R 0x10000 +#define REGUSE_LO_W 0x20000 +#define REGUSE_LO (REGUSE_LO_R | REGUSE_LO_W) +#define REGUSE_HI_R 0x40000 +#define REGUSE_HI_W 0x80000 +#define REGUSE_HI (REGUSE_HI_R | REGUSE_HI_W) + +#define REGUSE_COP0_RD_R 0x100000 +#define REGUSE_COP0_RD_W 0x200000 +#define REGUSE_COP0_RD (REGUSE_COP0_RD_R | REGUSE_COP0_RD_W) +#define REGUSE_COP0_STATUS 0x400000 +#define REGUSE_EXCEPTION 0x800000 + +#define REGUSE_COP2_RT_R 0x1000000 +#define REGUSE_COP2_RT_W 0x2000000 +#define REGUSE_COP2_RT (REGUSE_COP2_RT_R | REGUSE_COP2_RT_W) +#define REGUSE_COP2_RD_R 0x4000000 +#define REGUSE_COP2_RD_W 0x8000000 +#define REGUSE_COP2_RD (REGUSE_COP2_RD_R | REGUSE_COP2_RD_W) + + +// specific register use +#define REGUSE_READ 1 +#define REGUSE_WRITE 2 +#define REGUSE_RW 3 + +int useOfPsxReg(u32 code, int use, int psxreg) __attribute__ ((__pure__));; +int nextPsxRegUse(u32 pc, int psxreg) __attribute__ ((__pure__));; +int isPsxRegUsed(u32 pc, int psxreg) __attribute__ ((__pure__));; + +#ifdef __cplusplus +} +#endif +#endif |