diff --git a/pcsx2/Misc.cpp b/pcsx2/Misc.cpp index c3cd0c3386..a229ce74c9 100644 --- a/pcsx2/Misc.cpp +++ b/pcsx2/Misc.cpp @@ -34,6 +34,7 @@ #include "VU.h" #include "iCore.h" #include "iVUzerorec.h" +#include "BaseblockEx.h" // for debuild block dumping (which may or may not work anymore?) #include "GS.h" #include "COP0.h" diff --git a/pcsx2/Patch.h b/pcsx2/Patch.h index b02a6f5911..a804b08b5a 100644 --- a/pcsx2/Patch.h +++ b/pcsx2/Patch.h @@ -119,7 +119,6 @@ int AddPatch(int Mode, int Place, int Address, int Size, u64 data); namespace Dynarec { extern void SetFastMemory(int); // iR5900LoadStore.c - extern void SetVUNanMemory(int); // iVUmicro.c extern void SetVUNanMode(int mode); } diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index 66db619b3a..9247f28b65 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -2176,6 +2176,14 @@ + + + + @@ -2421,6 +2429,14 @@ + + + blocks; -}; - -void BASEBLOCKS::Add(BASEBLOCKEX* pex) -{ - assert( pex != NULL ); - - switch(blocks.size()) { - case 0: - blocks.push_back(pex); - return; - case 1: - assert( blocks.front()->startpc != pex->startpc ); - - if( blocks.front()->startpc < pex->startpc ) { - blocks.push_back(pex); - } - else blocks.insert(blocks.begin(), pex); - - return; - - default: - { - int imin = 0, imax = blocks.size(), imid; - - while(imin < imax) { - imid = (imin+imax)>>1; - - if( blocks[imid]->startpc > pex->startpc ) imax = imid; - else imin = imid+1; - } - - assert( imin == blocks.size() || blocks[imin]->startpc > pex->startpc ); - if( imin > 0 ) assert( blocks[imin-1]->startpc < pex->startpc ); - blocks.insert(blocks.begin()+imin, pex); - - return; - } - } -} - -int BASEBLOCKS::Get(u32 startpc) -{ - switch(blocks.size()) { - case 1: - return 0; - case 2: - return blocks.front()->startpc < startpc; - - default: - { - int imin = 0, imax = blocks.size()-1, imid; - - while(imin < imax) { - imid = (imin+imax)>>1; - - if( blocks[imid]->startpc > startpc ) imax = imid; - else if( blocks[imid]->startpc == startpc ) return imid; - else imin = imid+1; - } - - assert( blocks[imin]->startpc == startpc ); - return imin; - } - } -} - -void BASEBLOCKS::Remove(BASEBLOCKEX* pex) -{ - assert( pex != NULL ); - int i = Get(pex->startpc); - assert( blocks[i] == pex ); - blocks.erase(blocks.begin()+i); -} - -void BASEBLOCKS::Reset() -{ - blocks.resize(0); - blocks.reserve(512); -} - -BASEBLOCKEX** BASEBLOCKS::GetAll(int* pnum) -{ - assert( pnum != NULL ); - *pnum = blocks.size(); - return &blocks[0]; -} - -static BASEBLOCKS s_vecBaseBlocksEx[2]; - -void AddBaseBlockEx(BASEBLOCKEX* pex, int cpu) -{ - s_vecBaseBlocksEx[cpu].Add(pex); -} - -BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu) -{ - return s_vecBaseBlocksEx[cpu].blocks[s_vecBaseBlocksEx[cpu].Get(startpc)]; -} - -void RemoveBaseBlockEx(BASEBLOCKEX* pex, int cpu) -{ - s_vecBaseBlocksEx[cpu].Remove(pex); -} - -void ResetBaseBlockEx(int cpu) -{ - s_vecBaseBlocksEx[cpu].Reset(); -} - -BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu) -{ - return s_vecBaseBlocksEx[cpu].GetAll(pnum); -} - //////////////////////////////////////////////////// //#include "R3000A.h" //#include "PsxCounters.h" diff --git a/pcsx2/x86/iCore.h b/pcsx2/x86/iCore.h index d09822083c..beeec134cc 100644 --- a/pcsx2/x86/iCore.h +++ b/pcsx2/x86/iCore.h @@ -22,41 +22,70 @@ #include "ix86/ix86.h" #include "iVUmicro.h" -// Namespace Note : Dyanmic recompiler tools used by EE, IOP, and PS2 hardware. -// Underneath this namespace thenare Dynarec::R5900, Dynarec::R3000a, etc. for each -// of the items specific to those CPUs (those are defined in other headers). +// Namespace Note : iCore32 contains all of the Register Allocation logic, in addition to a handful +// of utility functions for emitting frequent code. namespace Dynarec { -// used to keep block information -#define BLOCKTYPE_STARTPC 4 // startpc offset -#define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot +//////////////////////////////////////////////////////////////////////////////// +// Shared Register allocation flags (apply to X86, XMM, MMX, etc). -struct BASEBLOCK -{ - u32 pFnptr : 28; - u32 uType : 4; - u32 startpc; -}; +#define MODE_READ 1 +#define MODE_WRITE 2 +#define MODE_READHALF 4 // read only low 64 bits +#define MODE_VUXY 0x8 // vector only has xy valid (real zw are in mem), not the same as MODE_READHALF +#define MODE_VUZ 0x10 // z only doesn't work for now +#define MODE_VUXYZ (MODE_VUZ|MODE_VUXY) // vector only has xyz valid (real w is in memory) +#define MODE_NOFLUSH 0x20 // can't flush reg to mem +#define MODE_NOFRAME 0x40 // when allocating x86regs, don't use ebp reg +#define MODE_8BITREG 0x80 // when allocating x86regs, use only eax, ecx, edx, and ebx -C_ASSERT( sizeof(BASEBLOCK) == 8 ); +#define PROCESS_EE_MMX 0x01 +#define PROCESS_EE_XMM 0x02 -// extra block info (only valid for start of fn) -struct BASEBLOCKEX -{ - u16 size; // size in dwords - u16 dummy; - u32 startpc; // for debugging? +// currently only used in FPU +#define PROCESS_EE_S 0x04 // S is valid, otherwise take from mem +#define PROCESS_EE_T 0x08 // T is valid, otherwise take from mem -#ifdef PCSX2_DEVBUILD - u32 visited; // number of times called - LARGE_INTEGER ltime; // regs it assumes to have set already -#endif +// not used in VU recs +#define PROCESS_EE_MODEWRITES 0x10 // if s is a reg, set if not in cpuRegs +#define PROCESS_EE_MODEWRITET 0x20 // if t is a reg, set if not in cpuRegs +#define PROCESS_EE_LO 0x40 // lo reg is valid +#define PROCESS_EE_HI 0x80 // hi reg is valid +#define PROCESS_EE_ACC 0x40 // acc reg is valid -}; +// used in VU recs +#define PROCESS_VU_UPDATEFLAGS 0x10 +#define PROCESS_VU_SUPER 0x40 // set if using supervu recompilation +#define PROCESS_VU_COP2 0x80 // simple cop2 -#define GET_BLOCKTYPE(b) ((b)->Type) -#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) +#define EEREC_S (((info)>>8)&0xf) +#define EEREC_T (((info)>>12)&0xf) +#define EEREC_D (((info)>>16)&0xf) +#define EEREC_LO (((info)>>20)&0xf) +#define EEREC_HI (((info)>>24)&0xf) +#define EEREC_ACC (((info)>>20)&0xf) +#define EEREC_TEMP (((info)>>24)&0xf) +#define VUREC_FMAC ((info)&0x80000000) + +#define PROCESS_EE_SET_S(reg) ((reg)<<8) +#define PROCESS_EE_SET_T(reg) ((reg)<<12) +#define PROCESS_EE_SET_D(reg) ((reg)<<16) +#define PROCESS_EE_SET_LO(reg) ((reg)<<20) +#define PROCESS_EE_SET_HI(reg) ((reg)<<24) +#define PROCESS_EE_SET_ACC(reg) ((reg)<<20) + +#define PROCESS_VU_SET_ACC(reg) PROCESS_EE_SET_ACC(reg) +#define PROCESS_VU_SET_TEMP(reg) ((reg)<<24) + +#define PROCESS_VU_SET_FMAC() 0x80000000 + +// special info not related to above flags +#define PROCESS_CONSTS 1 +#define PROCESS_CONSTT 2 + +//////////////////////////////////////////////////////////////////////////////// +// X86 (32-bit) Register Allocation Tools #define X86TYPE_TEMP 0 #define X86TYPE_GPR 1 @@ -106,56 +135,8 @@ void _flushCachedRegs(); void _flushConstRegs(); void _flushConstReg(int reg); -// see MEM_X defines for argX format -extern void _callPushArg(u32 arg, uptr argmem); /// X86ARG is ignored for 32bit recs -extern void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem); -extern void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem); -extern void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem); - -// return type: 0 - const, 1 - mmx, 2 - xmm -#define PROCESS_EE_MMX 0x01 -#define PROCESS_EE_XMM 0x02 - -// currently only used in FPU -#define PROCESS_EE_S 0x04 // S is valid, otherwise take from mem -#define PROCESS_EE_T 0x08 // T is valid, otherwise take from mem - -// not used in VU recs -#define PROCESS_EE_MODEWRITES 0x10 // if s is a reg, set if not in cpuRegs -#define PROCESS_EE_MODEWRITET 0x20 // if t is a reg, set if not in cpuRegs -#define PROCESS_EE_LO 0x40 // lo reg is valid -#define PROCESS_EE_HI 0x80 // hi reg is valid -#define PROCESS_EE_ACC 0x40 // acc reg is valid - -// used in VU recs -#define PROCESS_VU_UPDATEFLAGS 0x10 -#define PROCESS_VU_SUPER 0x40 // set if using supervu recompilation -#define PROCESS_VU_COP2 0x80 // simple cop2 - -#define EEREC_S (((info)>>8)&0xf) -#define EEREC_T (((info)>>12)&0xf) -#define EEREC_D (((info)>>16)&0xf) -#define EEREC_LO (((info)>>20)&0xf) -#define EEREC_HI (((info)>>24)&0xf) -#define EEREC_ACC (((info)>>20)&0xf) -#define EEREC_TEMP (((info)>>24)&0xf) -#define VUREC_FMAC ((info)&0x80000000) - -#define PROCESS_EE_SET_S(reg) ((reg)<<8) -#define PROCESS_EE_SET_T(reg) ((reg)<<12) -#define PROCESS_EE_SET_D(reg) ((reg)<<16) -#define PROCESS_EE_SET_LO(reg) ((reg)<<20) -#define PROCESS_EE_SET_HI(reg) ((reg)<<24) -#define PROCESS_EE_SET_ACC(reg) ((reg)<<20) - -#define PROCESS_VU_SET_ACC(reg) PROCESS_EE_SET_ACC(reg) -#define PROCESS_VU_SET_TEMP(reg) ((reg)<<24) - -#define PROCESS_VU_SET_FMAC() 0x80000000 - -// special info not related to above flags -#define PROCESS_CONSTS 1 -#define PROCESS_CONSTT 2 +//////////////////////////////////////////////////////////////////////////////// +// XMM (128-bit) Register Allocation Tools #define XMM_CONV_VU(VU) (VU==&VU1) @@ -207,49 +188,8 @@ u8 _hasFreeXMMreg(); void _freeXMMregs(); int _getNumXMMwrite(); -// Constants used for controlling iFlushCall, _psxFlushCall -#define FLUSH_CACHED_REGS 1 -#define FLUSH_FLUSH_XMM 2 -#define FLUSH_FREE_XMM 4 // both flushes and frees -#define FLUSH_FLUSH_MMX 8 -#define FLUSH_FREE_MMX 16 // both flushes and frees -#define FLUSH_FLUSH_ALLX86 32 // flush x86 -#define FLUSH_FREE_TEMPX86 64 // flush and free temporary x86 regs -#define FLUSH_FREE_ALLX86 128 // free all x86 regs -#define FLUSH_FREE_VU0 0x100 // free all vu0 related regs - -// Flushing vs. Freeing, as understood by Air (I could be wrong still....) - -// "Freeing" registers means that the contents of the registers are flushed to memory. -// This is good for any sort of C code function that plans to modify the actual -// registers. When the Recs resume, they'll reload the registers with values saved -// as needed. (similar to a "FreezeXMMRegs") - -// "Flushing" means that in addition to the standard free (which is actually a flush) -// the register allocations are additionally wiped. This should only be necessary if -// the code being called is going to modify register allocations -- ie, be doing -// some kind of recompiling of its own. - -#define FLUSH_EVERYTHING 0xfff -// no freeing, used when callee won't destroy mmx/xmm regs -#define FLUSH_NODESTROY (FLUSH_CACHED_REGS|FLUSH_FLUSH_XMM|FLUSH_FLUSH_MMX|FLUSH_FLUSH_ALLX86) -// used when regs aren't going to be changed be callee -#define FLUSH_NOCONST (FLUSH_FREE_XMM|FLUSH_FREE_MMX|FLUSH_FREE_TEMPX86) - -// Note: All functions with _ee prefix are for EE only - -// finds where the GPR is stored and moves lower 32 bits to EAX -void _eeMoveGPRtoR(x86IntRegType to, int fromgpr); -void _eeMoveGPRtoM(u32 to, int fromgpr); -void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr); - -void _psxMoveGPRtoR(x86IntRegType to, int fromgpr); -void _psxMoveGPRtoM(u32 to, int fromgpr); -void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr); - // uses MEM_MMXTAG/MEM_XMMTAG to differentiate between the regs void _recPushReg(int mmreg); - void _signExtendSFtoM(u32 mem); // returns new index of reg, lower 32 bits already in mmx @@ -264,10 +204,8 @@ int _signExtendXMMtoM(u32 to, x86SSERegType from, int candestroy); // returns tr #define MEM_EECONSTTAG 0x0100 // argument is a GPR and comes from g_cpuConstRegs #define MEM_PSXCONSTTAG 0x0200 #define MEM_MEMORYTAG 0x0400 -// mmreg is mmxreg -#define MEM_MMXTAG 0x0800 -// mmreg is xmmreg -#define MEM_XMMTAG 0x8000 +#define MEM_MMXTAG 0x0800 // mmreg is mmxreg +#define MEM_XMMTAG 0x8000 // mmreg is xmmreg #define MEM_X86TAG 0x4000 // ignored most of the time #define MEM_GPRTAG 0x2000 // argument is a GPR reg #define MEM_CONSTTAG 0x1000 // argument is a const @@ -319,13 +257,13 @@ struct EEINST }; extern EEINST* g_pCurInstInfo; // info for the cur instruction -void _recClearInst(EEINST* pinst); +extern void _recClearInst(EEINST* pinst); // returns the number of insts + 1 until written (0 if not written) -u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg); +extern u32 _recIsRegWritten(EEINST* pinst, int size, u8 xmmtype, u8 reg); // returns the number of insts + 1 until used (0 if not used) -u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg); -void _recFillRegister(EEINST& pinst, int type, int reg, int write); +extern u32 _recIsRegUsed(EEINST* pinst, int size, u8 xmmtype, u8 reg); +extern void _recFillRegister(EEINST& pinst, int type, int reg, int write); #define EEINST_ISLIVE64(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1)) #define EEINST_ISLIVEXMM(reg) (g_pCurInstInfo->regs[reg] & (EEINST_LIVE0|EEINST_LIVE1|EEINST_LIVE2)) @@ -345,21 +283,7 @@ void _recFillRegister(EEINST& pinst, int type, int reg, int write); #define EEINST_RESETSIGNEXT(reg) { if( (reg) < 32 ) g_cpuRegHasSignExt &= ~(1<<(reg)); } #define EEINST_ISSIGNEXT(reg) (g_cpuPrevRegHasSignExt&(1<<(reg))) -// writeback inst (used for cop2) -struct EEINSTWRITEBACK -{ - int cycle; - u32 viwrite; // mask of written viregs (REG_STATUS_FLAG and REG_MAC_FLAG are treated the same) - EEINST* parent; -}; - -void _recClearWritebacks(); -void _recAddWriteBack(int cycle, u32 viwrite, EEINST* parent); - -// if cycle == -1, returns the next writeback (used for flushing) -EEINSTWRITEBACK* _recCheckWriteBack(int cycle); - -extern u32 g_recWriteback; // used for jumps +extern u32 g_recWriteback; // used for jumps (VUrec mess!) extern u32 g_cpuRegHasLive1, g_cpuPrevRegHasLive1; extern u32 g_cpuRegHasSignExt, g_cpuPrevRegHasSignExt; @@ -379,35 +303,13 @@ int _allocCheckFPUtoXMM(EEINST* pinst, int fpureg, int mode); // allocates only if later insts use this register int _allocCheckGPRtoX86(EEINST* pinst, int gprreg, int mode); -// 0 - ee, 1 - iop -void AddBaseBlockEx(BASEBLOCKEX*, int cpu); -void RemoveBaseBlockEx(BASEBLOCKEX*, int cpu); -BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu); -void ResetBaseBlockEx(int cpu); - -BASEBLOCKEX** GetAllBaseBlocks(int* pnum, int cpu); - -#define MODE_READ 1 -#define MODE_WRITE 2 -#define MODE_READHALF 4 // read only low 64 bits -#define MODE_VUXY 0x8 // vector only has xy valid (real zw are in mem), not the same as MODE_READHALF -#define MODE_VUZ 0x10 // z only doesn't work for now -#define MODE_VUXYZ (MODE_VUZ|MODE_VUXY) // vector only has xyz valid (real w is in memory) -#define MODE_NOFLUSH 0x20 // can't flush reg to mem -#define MODE_NOFRAME 0x40 // when allocating x86regs, don't use ebp reg -#define MODE_8BITREG 0x80 // when allocating x86regs, use only eax, ecx, edx, and ebx - -void SetMMXstate(); - -void _recMove128MtoM(u32 to, u32 from); - -///////////////////////////// -// MMX x86-32 only // -///////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// MMX (64-bit) Register Allocation Tools #define FPU_STATE 0 #define MMX_STATE 1 +void SetMMXstate(); void SetFPUstate(); // max is 0x7f, when 0x80 is set, need to flush reg @@ -453,33 +355,77 @@ int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode); void _recMove128RmOffsettoM(u32 to, u32 offset); void _recMove128MtoRmOffset(u32 offset, u32 from); -// op = 0, and -// op = 1, or -// op = 2, xor -// op = 3, nor (the 32bit versoins only do OR) -void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); -void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); - // returns new index of reg, lower 32 bits already in mmx // shift is used when the data is in the top bits of the mmx reg to begin with // a negative shift is for sign extension -int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift); +extern int _signExtendGPRtoMMX(x86MMXRegType to, u32 gprreg, int shift); extern _mmxregs mmxregs[MMXREGS], s_saveMMXregs[MMXREGS]; extern u16 x86FpuState, iCWstate; -void LogicalOp32RtoM(uptr to, x86IntRegType from, int op); -void LogicalOp32MtoR(x86IntRegType to, uptr from, int op); -void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); -void LogicalOp32ItoM(uptr to, u32 from, int op); +extern void iDumpRegisters(u32 startpc, u32 temp); + +////////////////////////////////////////////////////////////////////////// +// iFlushCall / _psxFlushCall Parameters + +// Flushing vs. Freeing, as understood by Air (I could be wrong still....) + +// "Freeing" registers means that the contents of the registers are flushed to memory. +// This is good for any sort of C code function that plans to modify the actual +// registers. When the Recs resume, they'll reload the registers with values saved +// as needed. (similar to a "FreezeXMMRegs") + +// "Flushing" means that in addition to the standard free (which is actually a flush) +// the register allocations are additionally wiped. This should only be necessary if +// the code being called is going to modify register allocations -- ie, be doing +// some kind of recompiling of its own. + +#define FLUSH_CACHED_REGS 1 +#define FLUSH_FLUSH_XMM 2 +#define FLUSH_FREE_XMM 4 // both flushes and frees +#define FLUSH_FLUSH_MMX 8 +#define FLUSH_FREE_MMX 16 // both flushes and frees +#define FLUSH_FLUSH_ALLX86 32 // flush x86 +#define FLUSH_FREE_TEMPX86 64 // flush and free temporary x86 regs +#define FLUSH_FREE_ALLX86 128 // free all x86 regs +#define FLUSH_FREE_VU0 0x100 // free all vu0 related regs + +#define FLUSH_EVERYTHING 0xfff +// no freeing, used when callee won't destroy mmx/xmm regs +#define FLUSH_NODESTROY (FLUSH_CACHED_REGS|FLUSH_FLUSH_XMM|FLUSH_FLUSH_MMX|FLUSH_FLUSH_ALLX86) +// used when regs aren't going to be changed be callee +#define FLUSH_NOCONST (FLUSH_FREE_XMM|FLUSH_FREE_MMX|FLUSH_FREE_TEMPX86) + + +////////////////////////////////////////////////////////////////////////// +// Utility Functions -- that should probably be part of the Emitter. + +// see MEM_X defines for argX format +extern void _callPushArg(u32 arg, uptr argmem); /// X86ARG is ignored for 32bit recs +extern void _callFunctionArg1(uptr fn, u32 arg1, uptr arg1mem); +extern void _callFunctionArg2(uptr fn, u32 arg1, u32 arg2, uptr arg1mem, uptr arg2mem); +extern void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr arg1mem, uptr arg2mem, uptr arg3mem); + +// Moves 128 bits of data using EAX/EDX (used by iCOP2 only currently) +extern void _recMove128MtoM(u32 to, u32 from); + +// op = 0, and +// op = 1, or +// op = 2, xor +// op = 3, nor (the 32bit versoins only do OR) +extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); +extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); + +extern void LogicalOp32RtoM(uptr to, x86IntRegType from, int op); +extern void LogicalOp32MtoR(x86IntRegType to, uptr from, int op); +extern void LogicalOp32ItoR(x86IntRegType to, u32 from, int op); +extern void LogicalOp32ItoM(uptr to, u32 from, int op); #ifdef ARITHMETICIMM_RECOMPILE extern void LogicalOpRtoR(x86MMXRegType to, x86MMXRegType from, int op); extern void LogicalOpMtoR(x86MMXRegType to, u32 from, int op); #endif -void iDumpRegisters(u32 startpc, u32 temp); - } #endif diff --git a/pcsx2/x86/iR3000A.cpp b/pcsx2/x86/iR3000A.cpp index b043da755e..f0bc1d6240 100644 --- a/pcsx2/x86/iR3000A.cpp +++ b/pcsx2/x86/iR3000A.cpp @@ -328,6 +328,38 @@ void _psxDeleteReg(int reg, int flush) _deleteX86reg(X86TYPE_PSX, reg, flush ? 0 : 2); } +void _psxMoveGPRtoR(x86IntRegType to, int fromgpr) +{ + if( PSX_IS_CONST1(fromgpr) ) + MOV32ItoR( to, g_psxConstRegs[fromgpr] ); + else { + // check x86 + MOV32MtoR(to, (uptr)&psxRegs.GPR.r[ fromgpr ] ); + } +} + +void _psxMoveGPRtoM(u32 to, int fromgpr) +{ + if( PSX_IS_CONST1(fromgpr) ) + MOV32ItoM( to, g_psxConstRegs[fromgpr] ); + else { + // check x86 + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[ fromgpr ] ); + MOV32RtoM(to, EAX ); + } +} + +void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr) +{ + if( PSX_IS_CONST1(fromgpr) ) + MOV32ItoRmOffset( to, g_psxConstRegs[fromgpr], 0 ); + else { + // check x86 + MOV32MtoR(EAX, (uptr)&psxRegs.GPR.r[ fromgpr ] ); + MOV32RtoRm(to, EAX ); + } +} + void _psxFlushCall(int flushtype) { _freeX86regs(); diff --git a/pcsx2/x86/iR3000A.h b/pcsx2/x86/iR3000A.h index 329b1bcb71..462c78dc80 100644 --- a/pcsx2/x86/iR3000A.h +++ b/pcsx2/x86/iR3000A.h @@ -18,7 +18,7 @@ #ifndef _R3000A_SUPERREC_ #define _R3000A_SUPERREC_ -extern void __Log(const char *fmt, ...); +#include "BaseblockEx.h" // Cycle penalties for particuarly slow instructions. static const int psxInstCycles_Mult = 8; @@ -50,6 +50,11 @@ void _psxDeleteReg(int reg, int flush); void _psxFlushCall(int flushtype); void _psxOnWriteReg(int reg); + +void _psxMoveGPRtoR(x86IntRegType to, int fromgpr); +void _psxMoveGPRtoM(u32 to, int fromgpr); +void _psxMoveGPRtoRm(x86IntRegType to, int fromgpr); + void PSX_CHECK_SAVE_REG(int reg); extern u32 psxpc; // recompiler pc diff --git a/pcsx2/x86/iR5900.h b/pcsx2/x86/iR5900.h index 935e669bd2..ccff8811a0 100644 --- a/pcsx2/x86/iR5900.h +++ b/pcsx2/x86/iR5900.h @@ -22,6 +22,7 @@ #include "R5900.h" #include "VU.h" #include "iCore.h" +#include "BaseblockEx.h" // needed for recClear and stuff // Yay! These work now! (air) #define ARITHMETICIMM_RECOMPILE @@ -112,6 +113,11 @@ extern void (*recBSC_co[64])(); u32* _eeGetConstReg(int reg); // gets a memory pointer to the constant reg +// finds where the GPR is stored and moves lower 32 bits to EAX +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr); +void _eeMoveGPRtoM(u32 to, int fromgpr); +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr); + void _eeFlushAllUnused(); void _eeOnWriteReg(int reg, int signext); diff --git a/pcsx2/x86/ix86-32/iCore-32.cpp b/pcsx2/x86/ix86-32/iCore-32.cpp index 68c3bdc8ae..3f77c1341d 100644 --- a/pcsx2/x86/ix86-32/iCore-32.cpp +++ b/pcsx2/x86/ix86-32/iCore-32.cpp @@ -25,10 +25,12 @@ #include "iCore.h" #include "R3000A.h" +#include "iR5900.h" + #include using namespace std; -using namespace R5900; +using namespace ::R5900; namespace Dynarec { @@ -66,7 +68,8 @@ u32 _x86GetAddr(int type, int reg) return (u32)&g_recWriteback; case X86TYPE_VUJUMP: return (u32)&g_recWriteback; - default: assert(0); + + jNO_DEFAULT; } return 0; @@ -279,7 +282,7 @@ int _allocX86reg(int x86reg, int type, int reg, int mode) _deleteMMXreg(MMX_GPR+reg, 1); _deleteGPRtoXMMreg(reg, 1); - _eeMoveGPRtoR(x86reg, reg); + R5900::_eeMoveGPRtoR(x86reg, reg); _deleteMMXreg(MMX_GPR+reg, 0); _deleteGPRtoXMMreg(reg, 0); @@ -819,7 +822,7 @@ __forceinline void _callPushArg(u32 arg, uptr argmem) else if( IS_CONSTREG(arg) ) PUSH32I(argmem); else if( IS_GPRREG(arg) ) { SUB32ItoR(ESP, 4); - _eeMoveGPRtoRm(ESP, arg&0xff); + R5900::_eeMoveGPRtoRm(ESP, arg&0xff); } else if( IS_XMMREG(arg) ) { SUB32ItoR(ESP, 4); @@ -867,69 +870,6 @@ __forceinline void _callFunctionArg3(uptr fn, u32 arg1, u32 arg2, u32 arg3, uptr ADD32ItoR(ESP, 12); } -// EE -void _eeMoveGPRtoR(x86IntRegType to, int fromgpr) -{ - if( GPR_IS_CONST1(fromgpr) ) - MOV32ItoR( to, g_cpuConstRegs[fromgpr].UL[0] ); - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { - SSE2_MOVD_XMM_to_R(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE) ) { - MOVD32MMXtoR(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(to, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - } - } -} - -void _eeMoveGPRtoM(u32 to, int fromgpr) -{ - if( GPR_IS_CONST1(fromgpr) ) - MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { - SSEX_MOVD_XMM_to_M32(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { - MOVDMMXtoM(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - MOV32RtoM(to, EAX ); - } - } -} - -void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) -{ - if( GPR_IS_CONST1(fromgpr) ) - MOV32ItoRmOffset( to, g_cpuConstRegs[fromgpr].UL[0], 0 ); - else { - int mmreg; - - if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { - SSEX_MOVD_XMM_to_Rm(to, mmreg); - } - else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { - MOVD32MMXtoRm(to, mmreg); - SetMMXstate(); - } - else { - MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); - MOV32RtoRm(to, EAX ); - } - } -} - void _recPushReg(int mmreg) { if( IS_XMMREG(mmreg) ) { @@ -1070,6 +1010,8 @@ int _allocCheckGPRtoMMX(EEINST* pinst, int reg, int mode) return _checkMMXreg(MMX_GPR+reg, mode); } +// fixme - yay stupid? This sucks, and is used form iCOp2.cpp only. +// Surely there is a better way! void _recMove128MtoM(u32 to, u32 from) { MOV32MtoR(EAX, from); @@ -1082,6 +1024,7 @@ void _recMove128MtoM(u32 to, u32 from) MOV32RtoM(to+12, EDX); } +// fixme - see above function! void _recMove128RmOffsettoM(u32 to, u32 offset) { MOV32RmtoROffset(EAX, ECX, offset); @@ -1094,6 +1037,7 @@ void _recMove128RmOffsettoM(u32 to, u32 offset) MOV32RtoM(to+12, EDX); } +// fixme - see above function again! void _recMove128MtoRmOffset(u32 offset, u32 from) { MOV32MtoR(EAX, from); diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index 1da6d9ec06..8317923494 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -39,8 +39,8 @@ #include "VUmicro.h" #include "iVUzerorec.h" - #include "vtlb.h" + #include "SamplProf.h" // used to disable register freezing during cpuBranchTests (registers @@ -338,6 +338,68 @@ u32* _eeGetConstReg(int reg) return &cpuRegs.GPR.r[ reg ].UL[0]; } +void _eeMoveGPRtoR(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoR( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 && (xmmregs[mmreg].mode&MODE_WRITE)) { + SSE2_MOVD_XMM_to_R(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 && (mmxregs[mmreg].mode&MODE_WRITE) ) { + MOVD32MMXtoR(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(to, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + } + } +} + +void _eeMoveGPRtoM(u32 to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoM( to, g_cpuConstRegs[fromgpr].UL[0] ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_M32(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVDMMXtoM(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoM(to, EAX ); + } + } +} + +void _eeMoveGPRtoRm(x86IntRegType to, int fromgpr) +{ + if( GPR_IS_CONST1(fromgpr) ) + MOV32ItoRmOffset( to, g_cpuConstRegs[fromgpr].UL[0], 0 ); + else { + int mmreg; + + if( (mmreg = _checkXMMreg(XMMTYPE_GPRREG, fromgpr, MODE_READ)) >= 0 ) { + SSEX_MOVD_XMM_to_Rm(to, mmreg); + } + else if( (mmreg = _checkMMXreg(MMX_GPR+fromgpr, MODE_READ)) >= 0 ) { + MOVD32MMXtoRm(to, mmreg); + SetMMXstate(); + } + else { + MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ fromgpr ].UL[ 0 ] ); + MOV32RtoRm(to, EAX ); + } + } +} + int _flushXMMunused() { int i; @@ -1618,7 +1680,6 @@ void recRecompile( const u32 startpc ) g_cpuHasConstReg = g_cpuFlushedConstReg = 1; g_cpuPrevRegHasLive1 = g_cpuRegHasLive1 = 0xffffffff; g_cpuPrevRegHasSignExt = g_cpuRegHasSignExt = 0; - _recClearWritebacks(); assert( g_cpuConstRegs[0].UD[0] == 0 ); _initX86regs();