Index: pcsx2/x86/BaseblockEx.cpp =================================================================== --- pcsx2/x86/BaseblockEx.cpp (revision 685) +++ pcsx2/x86/BaseblockEx.cpp (working copy) @@ -16,6 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#define _SECURE_SCL 0 + #include "PrecompiledHeader.h" #include "BaseblockEx.h" @@ -77,10 +79,15 @@ int BASEBLOCKS::Get(u32 startpc) { switch(blocks.size()) { + case 0: + return -1; case 1: - return 0; - case 2: - return blocks.front()->startpc < startpc; + if (blocks.front()->startpc + blocks.front()->size*4 <= startpc) + return -1; + else + return 0; + /*case 2: + return blocks.front()->startpc < startpc;*/ default: { @@ -94,8 +101,12 @@ else imin = imid+1; } - assert( blocks[imin]->startpc == startpc ); - return imin; + //assert( blocks[imin]->startpc == startpc ); + if (startpc < blocks[imin]->startpc || + startpc >= blocks[imin]->startpc + blocks[imin]->size*4) + return -1; + else + return imin; } } } @@ -130,7 +141,11 @@ BASEBLOCKEX* GetBaseBlockEx(u32 startpc, int cpu) { - return s_vecBaseBlocksEx[cpu].blocks[s_vecBaseBlocksEx[cpu].Get(startpc)]; + int i = s_vecBaseBlocksEx[cpu].Get(startpc); + if (i < 0) + return 0; + else + return s_vecBaseBlocksEx[cpu].blocks[i]; } void RemoveBaseBlockEx(BASEBLOCKEX* pex, int cpu) Index: pcsx2/x86/BaseblockEx.h =================================================================== --- pcsx2/x86/BaseblockEx.h (revision 685) +++ pcsx2/x86/BaseblockEx.h (working copy) @@ -20,7 +20,6 @@ #define _BASEBLOCKEX_H_ // used to keep block information -#define BLOCKTYPE_STARTPC 4 // startpc offset #define BLOCKTYPE_DELAYSLOT 1 // if bit set, delay slot // Every potential jump point in the PS2's addressable memory has a BASEBLOCK @@ -28,17 +27,14 @@ // addressable memory. Yay! struct BASEBLOCK { - u32 m_pFnptr : 28; - u32 uType : 4; - u32 startpc; + u32 m_pFnptr; + u32 startpc : 30; + u32 uType : 2; - const uptr GetFnptr() const { return ((u32)m_pFnptr)<<4; } - void SetFnptr( uptr ptr ) - { - // 16 byte alignments only, please! - jASSUME( (ptr & 0xf) == 0 ); - m_pFnptr = ptr>>4; - } + const __inline uptr GetFnptr() const { return m_pFnptr; } + void __inline SetFnptr( uptr ptr ) { m_pFnptr = ptr; } + const __inline uptr GetStartPC() const { return startpc << 2; } + void __inline SetStartPC( uptr pc ) { startpc = pc >> 2; } }; // extra block info (only valid for start of fn) @@ -60,7 +56,10 @@ // This is an asinine macro that bases indexing on sizeof(BASEBLOCK) for no reason. (air) #define GET_BLOCKTYPE(b) ((b)->Type) -#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (sizeof(BASEBLOCK)/4)*((x) & 0xffff))) +// x * (sizeof(BASEBLOCK) / 4) sacrifices safety for speed compared to +// x / 4 * sizeof(BASEBLOCK) or a higher level approach. +#define PC_GETBLOCK_(x, reclut) ((BASEBLOCK*)(reclut[((u32)(x)) >> 16] + (x)*(sizeof(BASEBLOCK)/4))) +#define RECLUT_SETPAGE(reclut, page, p) do { reclut[page] = (uptr)(p) - ((page) << 14) * sizeof(BASEBLOCK); } while (0) // This is needed because of the retarded GETBLOCK macro above. C_ASSERT( sizeof(BASEBLOCK) == 8 ); Index: pcsx2/x86/iR3000A.cpp =================================================================== --- pcsx2/x86/iR3000A.cpp (revision 685) +++ pcsx2/x86/iR3000A.cpp (working copy) @@ -44,7 +44,7 @@ u32 g_psxMaxRecMem = 0; u32 s_psxrecblocks[] = {0}; -uptr *psxRecLUT; +uptr psxRecLUT[0x10000]; #define PSX_NUMBLOCKS (1<<12) #define MAPBASE 0x48000000 @@ -92,6 +92,8 @@ extern void (*rpsxBSC[64])(); void rpsxpropBSC(EEINST* prev, EEINST* pinst); +static void psxInitRecLUT(BASEBLOCK* base, int count); + #ifdef _DEBUG u32 psxdump = 0; #else @@ -101,9 +103,8 @@ #define PSX_GETBLOCK(x) PC_GETBLOCK_(x, psxRecLUT) #define PSXREC_CLEARM(mem) { \ - if ((mem) < g_psxMaxRecMem && psxRecLUT[(mem) >> 16]) { \ - BASEBLOCK* p = PSX_GETBLOCK(mem); \ - if( *(u32*)p ) psxRecClearMem(p); \ + if ((mem) < g_psxMaxRecMem && (psxRecLUT[(mem) >> 16] + mem)) { \ + psxRecClearMem(mem); \ } \ } \ @@ -114,7 +115,7 @@ // return pex; // otherwise, use the sorted list - return GetBaseBlockEx(p->startpc, 1); + return GetBaseBlockEx(p->GetStartPC(), 1); } //////////////////////////////////////////////////// @@ -546,9 +547,6 @@ if( recMem == NULL ) throw Exception::OutOfMemory( "R3000a Init > failed to allocate memory for the recompiler." ); - if( psxRecLUT == NULL ) - psxRecLUT = (uptr*) malloc(0x010000 * sizeof(uptr)); - // Goal: Allocate BASEBLOCKs for every possible branch target in IOP memory. // Any 4-byte aligned address makes a valid branch target as per MIPS design (all instructions are // always 4 bytes long). @@ -586,31 +584,33 @@ DbgCon::Status( "iR3000A > Resetting recompiler memory and structures!" ); - memzero_ptr<0x010000 * sizeof(uptr)>( psxRecLUT ); + memzero_ptr( psxRecLUT ); memset_8<0xcd,RECMEM_SIZE>( recMem ); - memzero_ptr( m_recBlockAlloc ); + memzero_ptr(recBlocks); + psxInitRecLUT((BASEBLOCK*)m_recBlockAlloc, + (((Ps2MemSize::IopRam + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); // We're only mapping 20 pages here in 4 places. // 0x80 comes from : (Ps2MemSize::IopRam / 0x10000) * 4 for (int i=0; i<0x80; i++) { - psxRecLUT[i + 0x0000] = (uptr)&recRAM[(i & 0x1f) << 14]; - psxRecLUT[i + 0x8000] = (uptr)&recRAM[(i & 0x1f) << 14]; - psxRecLUT[i + 0xa000] = (uptr)&recRAM[(i & 0x1f) << 14]; + RECLUT_SETPAGE(psxRecLUT, i + 0x0000, &recRAM[(i & 0x1f) << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0x8000, &recRAM[(i & 0x1f) << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0xa000, &recRAM[(i & 0x1f) << 14]); } for (int i=0; i<(Ps2MemSize::Rom / 0x10000); i++) { - psxRecLUT[i + 0x1fc0] = (uptr)&recROM[i << 14]; - psxRecLUT[i + 0x9fc0] = (uptr)&recROM[i << 14]; - psxRecLUT[i + 0xbfc0] = (uptr)&recROM[i << 14]; + RECLUT_SETPAGE(psxRecLUT, i + 0x1fc0, &recROM[i << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0x9fc0, &recROM[i << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0xbfc0, &recROM[i << 14]); } for (int i=0; i<(Ps2MemSize::Rom1 / 0x10000); i++) { - psxRecLUT[i + 0x1e00] = (uptr)&recROM1[i << 14]; - psxRecLUT[i + 0x9e00] = (uptr)&recROM1[i << 14]; - psxRecLUT[i + 0xbe00] = (uptr)&recROM1[i << 14]; + RECLUT_SETPAGE(psxRecLUT, i + 0x1e00, &recROM1[i << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0x9e00, &recROM1[i << 14]); + RECLUT_SETPAGE(psxRecLUT, i + 0xbe00, &recROM1[i << 14]); } if( s_pInstCache ) @@ -630,7 +630,6 @@ SafeSysMunmap(recMem, RECMEM_SIZE); safe_aligned_free( m_recBlockAlloc ); - safe_free(psxRecLUT); safe_free( s_pInstCache ); s_nInstCacheSize = 0; } @@ -644,7 +643,7 @@ pblock = PSX_GETBLOCK(psxRegs.pc); - if ( !pblock->GetFnptr() || (pblock->startpc&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { + if ( !pblock->GetFnptr() || (pblock->GetStartPC()&PSX_MEMMASK) != (psxRegs.pc&PSX_MEMMASK) ) { psxRecRecompile(psxRegs.pc); } @@ -691,86 +690,82 @@ static u32 g_temp; +// The address for all clear blocks, recompile the current pc then run +__declspec(naked) void psxJITCompile() +{ + __asm { + mov esi, dword ptr [psxRegs.pc] + push esi + call psxRecRecompile + add esp, 4 + mov ebx, esi + shr esi, 16 + mov ecx, dword ptr [psxRecLUT+esi*4] + jmp dword ptr [ecx+ebx*2] + } +} + // jumped to when invalid psxpc address +// EDX contains the jump addr to modify __declspec(naked) void psxDispatcher() { - // EDX contains the current psxpc to jump to, stack contains the jump addr to modify - __asm push edx + __asm { + mov eax, dword ptr [psxRegs.pc] + mov ebx, eax + shr eax, 16 + mov ecx, dword ptr [psxRecLUT+eax*4] + mov eax, dword ptr [ecx+ebx*2] + cmp eax, offset psxJITCompile + je notcompiled + lea ebx, [eax-4] + sub ebx, edx + mov dword ptr [edx], ebx + jmp eax - //jASSUME( psxRegs.pc <= PSX_MEMMASK ); - s_pDispatchBlock = PSX_GETBLOCK( psxRegs.pc ); + align 16 +notcompiled: + mov esi, edx + lea edi, [ecx+ebx*2] + push ebx + call psxRecRecompile + add esp, 4 - if( s_pDispatchBlock->startpc != psxRegs.pc ) - psxRecRecompile(psxRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_temp, eax - assert( g_temp ); -#endif - - // Modify the prev block's jump address, and jump to the new block: - __asm - { - shl eax,4 - pop ecx // x86Ptr[0] to mod - mov edx, eax - sub edx, ecx - sub edx, 4 - mov dword ptr [ecx], edx - + mov eax, dword ptr [edi] + lea ebx, [eax-4] + sub ebx, esi + mov dword ptr [esi], ebx jmp eax } } +// edx - baseblock->GetStartPC() +// stack - x86Ptr[0] __declspec(naked) void psxDispatcherClear() { - // EDX contains the current psxpc - __asm mov psxRegs.pc, edx - __asm push edx + __asm { + mov [psxRegs.pc], edx + mov ebx, edx + shr edx, 16 + mov ecx, dword ptr [psxRecLUT+edx*4] + mov eax, dword ptr [ecx+ebx*2] + cmp eax, psxJITCompile + je notcompiled + add esp, 4 + jmp eax - //jASSUME( psxRegs.pc <= PSX_MEMMASK ); - - // calc PSX_GETBLOCK - s_pDispatchBlock = PSX_GETBLOCK(psxRegs.pc); - - if( s_pDispatchBlock->startpc == psxRegs.pc ) { - assert( s_pDispatchBlock->GetFnptr() != 0 ); - - // already modded the code, jump to the new place - __asm - { - pop edx - add esp, 4 // ignore stack - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - //and eax, 0x0fffffff - shl eax,4 - jmp eax - } - } - - __asm - { + align 16 +notcompiled: + lea edi, [ecx+ebx*2] + push ebx call psxRecRecompile - add esp, 4 // pop old param - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] + add esp, 4 + mov eax, dword ptr [edi] - pop ecx // old fnptr - - //and eax, 0x0fffffff - shl eax,4 + pop ecx mov byte ptr [ecx], 0xe9 // jmp32 - mov edx, eax - sub edx, ecx - sub edx, 5 - mov dword ptr [ecx+1], edx + lea ebx, [eax-5] + sub ebx, ecx + mov dword ptr [ecx+1], ebx jmp eax } @@ -779,30 +774,24 @@ // called when jumping to variable psxpc address __declspec(naked) void psxDispatcherReg() { - //jASSUME( psxRegs.pc <= PSX_MEMMASK ); - s_pDispatchBlock = PSX_GETBLOCK( psxRegs.pc ); - - if( s_pDispatchBlock->startpc != psxRegs.pc ) - psxRecRecompile(psxRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] + __asm { + mov eax, dword ptr [psxRegs.pc] + mov ebx, eax + shr eax, 16 + mov ecx, dword ptr [psxRecLUT+eax*4] + jmp dword ptr [ecx+ebx*2] } +} +#endif // _MSC_VER -#ifdef _DEBUG - __asm mov g_temp, eax - assert( g_temp ); -#endif - - __asm - { - shl eax, 4 - jmp eax +static void psxInitRecLUT(BASEBLOCK* base, int count) +{ + for (int i = 0; i < count; i++) { + base[i].SetFnptr((uptr)psxJITCompile); + base[i].SetStartPC(0); + base[i].uType = 0; } } -#endif // _MSC_VER static void recExecute() { @@ -869,57 +858,45 @@ void rpsxMemConstClear(u32 mem) { // NOTE! This assumes recLUT never changes its mapping - if( !psxRecLUT[mem>>16] ) + if( !(psxRecLUT[mem>>16] + mem) ) return; CMP32ItoM((uptr)PSX_GETBLOCK(mem), 0); j8Ptr[6] = JE8(0); - _callFunctionArg1((uptr)psxRecClearMem, MEM_CONSTTAG, (uptr)PSX_GETBLOCK(mem)); + _callFunctionArg1((uptr)psxRecClearMem, MEM_CONSTTAG, mem); x86SetJ8(j8Ptr[6]); } -void psxRecClearMem(BASEBLOCK* p) +void psxRecClearMem(u32 pc) { BASEBLOCKEX* pexblock; BASEBLOCK* pstart; - int lastdelay; - - assert( p != NULL ); + BASEBLOCK* p; + + p= PSX_GETBLOCK(pc); + pc = p->GetStartPC(); + if (!pc) + return; + pexblock = GetBaseBlockEx(pc, 1); + if (!pexblock) + return; + pstart = PSX_GETBLOCK(pexblock->startpc); - if( p->uType & BLOCKTYPE_DELAYSLOT ) { - psxRecClearMem(p-1); - if( p->GetFnptr() == 0 ) - return; - } - - assert( p->GetFnptr() != 0 ); - assert( p->startpc ); + for (int i = 0; i < pexblock->size; i++) { + x86Ptr[0] = (u8*)pstart[i].GetFnptr(); + if (x86Ptr[0] == (u8*)psxJITCompile) + continue; - x86Ptr[0] = (u8*)p->GetFnptr(); - - // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which - MOV32ItoR(EDX, p->startpc); - assert( (uptr)x86Ptr[0] <= 0xffffffff ); - PUSH32I((uptr)x86Ptr[0]); - JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr[0] + 5 )); - assert( x86Ptr[0] == (u8*)p->GetFnptr() + IOP_MIN_BLOCK_BYTES ); - - pstart = PSX_GETBLOCK(p->startpc); - pexblock = PSX_GETBLOCKEX(pstart); - assert( pexblock->startpc == pstart->startpc ); - - // don't delete if last is delay - lastdelay = pexblock->size; - if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { - assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); - if( pstart[pexblock->size-1].GetFnptr() != 0 ) { - pstart[pexblock->size-1].uType = 0; - --lastdelay; - } + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, pexblock->startpc + i*4); + assert( (uptr)x86Ptr[0] <= 0xffffffff ); + PUSH32I((uptr)x86Ptr[0]); // will be replaced by JMP32 + JMP32((uptr)psxDispatcherClear - ( (uptr)x86Ptr[0] + 5 )); + assert( x86Ptr[0] == (u8*)p->GetFnptr() + IOP_MIN_BLOCK_BYTES ); } - memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + psxInitRecLUT(pstart, pexblock->size); RemoveBaseBlockEx(pexblock, 1); pexblock->size = 0; @@ -1073,8 +1050,8 @@ { BASEBLOCK* pblock = PSX_GETBLOCK(temppc); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - if( psxpc == pblock->startpc ) + if( pblock->GetFnptr() != (uptr)psxJITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { + if( psxpc == pblock->GetStartPC() ) return 0; } @@ -1088,11 +1065,11 @@ BASEBLOCK* pblock = PSX_GETBLOCK(psxpc); // need *ppblock != s_pCurBlock because of branches - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pblock->GetFnptr() != (uptr)psxJITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { - if( !delayslot && psxpc == pblock->startpc ) { + if( !delayslot && psxpc == pblock->GetStartPC() ) { // code already in place, so jump to it and exit recomp - assert( PSX_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + assert( PSX_GETBLOCKEX(pblock)->startpc == pblock->GetStartPC() ); _psxFlushCall(FLUSH_EVERYTHING); MOV32ItoM((uptr)&psxRegs.pc, psxpc); @@ -1110,10 +1087,10 @@ } else { - if( !(delayslot && pblock->startpc == psxpc) ) { + if( !(delayslot && pblock->GetStartPC() == psxpc) ) { u8* oldX86 = x86Ptr[0]; - //__Log("clear block %x\n", pblock->startpc); - psxRecClearMem(pblock); + //__Log("clear block %x\n", pblock->GetStartPC()); + psxRecClearMem(psxpc); x86Ptr[0] = oldX86; if( delayslot ) SysPrintf("delay slot %x\n", psxpc); @@ -1246,13 +1223,13 @@ s_pCurBlock = PSX_GETBLOCK(startpc); - if( s_pCurBlock->GetFnptr() ) { + if( s_pCurBlock->GetFnptr() != (uptr)psxJITCompile ) { // clear if already taken - assert( s_pCurBlock->startpc < startpc ); - psxRecClearMem(s_pCurBlock); + assert( s_pCurBlock->GetStartPC() < startpc ); + psxRecClearMem(startpc); } - if( s_pCurBlock->startpc == startpc ) { + if( s_pCurBlock->GetStartPC() == startpc ) { s_pCurBlockEx = PSX_GETBLOCKEX(s_pCurBlock); assert( s_pCurBlockEx->startpc == startpc ); } @@ -1282,7 +1259,7 @@ psxbranch = 0; - s_pCurBlock->startpc = startpc; + s_pCurBlock->SetStartPC(startpc); s_pCurBlock->SetFnptr( (uptr)x86Ptr[0] ); s_psxBlockCycles = 0; @@ -1305,9 +1282,9 @@ while(1) { BASEBLOCK* pblock = PSX_GETBLOCK(i); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pblock->GetFnptr() != (uptr)psxJITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { - if( i == pblock->startpc ) { + if( i == pblock->GetStartPC() ) { // branch = 3 willbranch3 = 1; s_nEndBlock = i; @@ -1407,16 +1384,25 @@ assert( (psxpc-startpc)>>2 <= 0xffff ); s_pCurBlockEx->size = (psxpc-startpc)>>2; + for(i = 1; i <= (u32)s_pCurBlockEx->size-1; ++i) { + if (!s_pCurBlock[i].GetStartPC()) + s_pCurBlock[i].SetStartPC( startpc ); + } + +// This is just wrong, right? How can setting a jump to any point in this block +// to jump to the beginning of the block possibly be right? +#ifdef ZERO_TOLERANCE for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; + s_pCurBlock[i].SetStartPC( p_CurBlock->startpc ); } // don't overwrite if delay slot if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; + s_pCurBlock[i].SetFnptr(0); + s_pCurBlock[i].SetStartPC(0); } +#endif // set the block ptr AddBaseBlockEx(s_pCurBlockEx, 1); @@ -1472,23 +1458,23 @@ s_pCurBlock = PSX_GETBLOCK(psxpc); assert( ptr != NULL ); - if( s_pCurBlock->startpc != psxpc ){ + if( s_pCurBlock->GetStartPC() != psxpc ){ psxRecRecompile(psxpc); } // could have reset - if( pcurblock->startpc == startpc ) { - assert( pcurblock->GetFnptr() ); - assert( s_pCurBlock->startpc == nEndBlock ); + if( pcurblock->GetStartPC() == startpc ) { + assert( pcurblock->GetFnptr() != (uptr)psxJITCompile ); + assert( s_pCurBlock->GetStartPC() == nEndBlock ); *ptr = (u32)((uptr)s_pCurBlock->GetFnptr() - ( (uptr)ptr + 4 )); } else { psxRecRecompile(startpc); - assert( pcurblock->GetFnptr() != 0 ); + assert( pcurblock->GetFnptr() != (uptr)psxJITCompile ); } } else - assert( s_pCurBlock->GetFnptr() != 0 ); + assert( s_pCurBlock->GetFnptr() != (uptr)psxJITCompile ); } R3000Acpu psxRec = { Index: pcsx2/x86/iR3000A.h =================================================================== --- pcsx2/x86/iR3000A.h (revision 685) +++ pcsx2/x86/iR3000A.h (working copy) @@ -38,7 +38,7 @@ #define PSX_HI XMMGPR_HI #define PSX_LO XMMGPR_LO -extern uptr *psxRecLUT; +extern uptr psxRecLUT[]; u8 _psxLoadWritesRs(u32 tempcode); u8 _psxIsLoadStore(u32 tempcode); @@ -70,7 +70,7 @@ void psxSetBranchReg(u32 reg); void psxSetBranchImm( u32 imm ); void psxRecompileNextInstruction(int delayslot); -void psxRecClearMem(BASEBLOCK* p); +void psxRecClearMem(u32 p); //////////////////////////////////////////////////////////////////// // IOP Constant Propagation Defines, Vars, and API - From here down! Index: pcsx2/x86/iR5900.h =================================================================== --- pcsx2/x86/iR5900.h (revision 685) +++ pcsx2/x86/iR5900.h (working copy) @@ -51,7 +51,7 @@ extern u32 pc; extern int branch; -extern uptr* recLUT; +extern uptr recLUT[]; extern u32 maxrecmem; extern u32 pc; // recompiler pc (also used by the SuperVU! .. why? (air)) @@ -92,7 +92,7 @@ // Used to clear recompiled code blocks during memory/dma write operations. -void recClearMem(BASEBLOCK* p); +void recClearMem(u32 pc); void REC_CLEARM( u32 mem ); // used when processing branches Index: pcsx2/x86/ix86-32/iR5900-32.cpp =================================================================== --- pcsx2/x86/ix86-32/iR5900-32.cpp (revision 685) +++ pcsx2/x86/ix86-32/iR5900-32.cpp (working copy) @@ -52,7 +52,7 @@ bool g_EEFreezeRegs = false; u32 maxrecmem = 0; -uptr *recLUT = NULL; +uptr recLUT[0x10000]; u32 s_nBlockCycles = 0; // cycles of current block recompiling //u8* dyna_block_discard_recmem=0; @@ -112,15 +112,16 @@ #endif static void iBranchTest(u32 newpc, bool noDispatch=false); +static void InitRecLUT(BASEBLOCK* base, int count); -BASEBLOCKEX* PC_GETBLOCKEX(BASEBLOCK* p) +BASEBLOCKEX* PC_GETBLOCKEX(u32 pc) { // BASEBLOCKEX* pex = *(BASEBLOCKEX**)(p+1); // if( pex >= recBlocks && pex < recBlocks+EE_NUMBLOCKS ) // return pex; // otherwise, use the sorted list - return GetBaseBlockEx(p->startpc, 0); + return GetBaseBlockEx(pc, 0); } //////////////////////////////////////////////////// @@ -480,9 +481,6 @@ if ( !( cpucaps.hasStreamingSIMD2Extensions ) ) throw Exception::HardwareDeficiency( _( "Processor doesn't support SSE2" ) ); - if( recLUT == NULL ) - recLUT = (uptr*) _aligned_malloc( 0x010000 * sizeof(uptr), 16 ); - if( recMem == NULL ) { // Note: the VUrec depends on being able to grab an allocatione below the 0x10000000 line, @@ -539,7 +537,11 @@ memset_8<0xcd, REC_CACHEMEM>(recMem); memzero_ptr( m_recBlockAlloc ); + memzero_ptr(recBlocks); + InitRecLUT((BASEBLOCK*)m_recBlockAlloc, + (((Ps2MemSize::Base + Ps2MemSize::Rom + Ps2MemSize::Rom1) / 4))); + if( s_pInstCache ) memset( s_pInstCache, 0, sizeof(EEINST)*s_nInstCacheSize ); @@ -552,32 +554,34 @@ __asm__("emms"); #endif - memzero_ptr<0x010000 * sizeof(uptr)>( recLUT ); + memzero_ptr( recLUT ); for ( int i = 0x0000; i < 0x0200; i++ ) { - recLUT[ i + 0x0000 ] = (uptr)&recRAM[ i << 14 ]; - recLUT[ i + 0x2000 ] = (uptr)&recRAM[ i << 14 ]; - recLUT[ i + 0x3000 ] = (uptr)&recRAM[ i << 14 ]; + RECLUT_SETPAGE(recLUT, i + 0x0000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0x2000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0x3000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0x8000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xa000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xb000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xc000, &recRAM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xd000, &recRAM[ i << 14 ]); } for ( int i = 0x0000; i < 0x0040; i++ ) { - recLUT[ i + 0x1fc0 ] = (uptr)&recROM[ i << 14 ]; - recLUT[ i + 0x9fc0 ] = (uptr)&recROM[ i << 14 ]; - recLUT[ i + 0xbfc0 ] = (uptr)&recROM[ i << 14 ]; + RECLUT_SETPAGE(recLUT, i + 0x1fc0, &recROM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0x9fc0, &recROM[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xbfc0, &recROM[ i << 14 ]); } for ( int i = 0x0000; i < 0x0004; i++ ) { - recLUT[ i + 0x1e00 ] = (uptr)&recROM1[ i << 14 ]; - recLUT[ i + 0x9e00 ] = (uptr)&recROM1[ i << 14 ]; - recLUT[ i + 0xbe00 ] = (uptr)&recROM1[ i << 14 ]; + RECLUT_SETPAGE(recLUT, i + 0x1e00, &recROM1[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0x9e00, &recROM1[ i << 14 ]); + RECLUT_SETPAGE(recLUT, i + 0xbe00, &recROM1[ i << 14 ]); } - memcpy_fast( recLUT + 0x8000, recLUT, 0x2000 * sizeof(uptr) ); - memcpy_fast( recLUT + 0xa000, recLUT, 0x2000 * sizeof(uptr) ); - // drk||Raziel says this is useful but I'm not sure why. Something to do with forward jumps. // Anyways, it causes random crashing for some reasom, possibly because of memory // corrupition elsewhere in the recs. I can't reproduce the problem here though, @@ -604,7 +608,6 @@ ResetBaseBlockEx(0); SafeSysMunmap( recMem, REC_CACHEMEM ); - safe_aligned_free( recLUT ); safe_aligned_free( m_recBlockAlloc ); recRAM = recROM = recROM1 = NULL; recBlocks = NULL; @@ -645,110 +648,96 @@ #ifdef _MSC_VER +// The address for all clear blocks, recompile the current pc then run +__declspec(naked) void JITCompile() +{ + __asm { + mov esi, dword ptr [cpuRegs.pc] + push esi + call recRecompile + add esp, 4 + mov ebx, esi + shr esi, 16 + mov ecx, dword ptr [recLUT+esi*4] + jmp dword ptr [ecx+ebx*2] + } +} + // jumped to when invalid pc address // EDX contains the jump addr to modify static __naked void Dispatcher() { - // EDX contains the jump addr to modify - __asm push edx - - // calc PC_GETBLOCK - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock->startpc != cpuRegs.pc ) - recRecompile(cpuRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_EEDispatchTemp, eax - assert( g_EEDispatchTemp ); -#endif - - // Modify the prev block's jump address, and jump to the new block: __asm { - shl eax, 4 - pop ecx // x86Ptr[0] to mod - mov edx, eax - sub edx, ecx - sub edx, 4 - mov dword ptr [ecx], edx + mov eax, dword ptr [cpuRegs.pc] + mov ebx, eax + shr eax, 16 + mov ecx, dword ptr [recLUT+eax*4] + mov eax, dword ptr [ecx+ebx*2] + cmp eax, offset JITCompile + je notcompiled + lea ebx, [eax-4] + sub ebx, edx + mov dword ptr [edx], ebx + jmp eax + align 16 +notcompiled: + mov esi, edx + lea edi, [ecx+ebx*2] + push ebx + call recRecompile + add esp, 4 + + mov eax, dword ptr [edi] + lea ebx, [eax-4] + sub ebx, esi + mov dword ptr [esi], ebx jmp eax } } -// edx - baseblock->startpc +// edx - baseblock->GetStartPC() // stack - x86Ptr[0] static __naked void DispatcherClear() { - // EDX contains the current pc - __asm mov cpuRegs.pc, edx - __asm push edx - - // calc PC_GETBLOCK - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock != NULL && s_pDispatchBlock->startpc == cpuRegs.pc ) - { - assert( s_pDispatchBlock->GetFnptr() != 0 ); - - // already modded the code, jump to the new place - __asm { - pop edx - mov eax, s_pDispatchBlock - add esp, 4 // ignore stack - mov eax, dword ptr [eax] - shl eax, 4 - jmp eax - } - } - __asm { + mov [cpuRegs.pc], edx + mov ebx, edx + shr edx, 16 + mov ecx, dword ptr [recLUT+edx*4] + mov eax, dword ptr [ecx+ebx*2] + cmp eax, offset JITCompile + je notcompiled + add esp, 4 + jmp eax + + align 16 +notcompiled: + lea edi, [ecx+ebx*2] + push ebx call recRecompile - add esp, 4 // pop old param - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] + add esp, 4 + mov eax, dword ptr [edi] - pop ecx // old fnptr - - shl eax, 4 + pop ecx mov byte ptr [ecx], 0xe9 // jmp32 - mov edx, eax - sub edx, ecx - sub edx, 5 - mov dword ptr [ecx+1], edx + lea ebx, [eax-5] + sub ebx, ecx + mov dword ptr [ecx+1], ebx jmp eax } } // called when jumping to variable pc address -static __naked void DispatcherReg() +static void __naked DispatcherReg() { - s_pDispatchBlock = PC_GETBLOCK(cpuRegs.pc); - - if( s_pDispatchBlock->startpc != cpuRegs.pc ) - recRecompile(cpuRegs.pc); - - __asm - { - mov eax, s_pDispatchBlock - mov eax, dword ptr [eax] - } - -#ifdef _DEBUG - __asm mov g_EEDispatchTemp, eax - assert( g_EEDispatchTemp ); -#endif - __asm { - shl eax, 4 - jmp eax + mov eax, dword ptr [cpuRegs.pc] + mov ebx, eax + shr eax, 16 + mov ecx, dword ptr [recLUT+eax*4] + jmp dword ptr [ecx+ebx*2] } } @@ -852,6 +841,15 @@ } #endif +static void InitRecLUT(BASEBLOCK* base, int count) +{ + for (int i = 0; i < count; i++) { + base[i].SetFnptr((uptr)JITCompile); + base[i].SetStartPC(0); + base[i].uType = 0; + } +} + namespace R5900 { namespace Dynarec { namespace OpcodeImpl { @@ -899,11 +897,20 @@ static const int EE_MIN_BLOCK_BYTES = 15; -void recClearMem(BASEBLOCK* p) +void recClearMem(u32 pc) { BASEBLOCKEX* pexblock; BASEBLOCK* pstart; - int lastdelay; + BASEBLOCK* p; + + p= PC_GETBLOCK(pc); + pc = p->GetStartPC(); + if (!pc) + return; + pexblock = PC_GETBLOCKEX(pc); + if (!pexblock) + return; + pstart = PC_GETBLOCK(pexblock->startpc); // necessary since recompiler doesn't call femms/emms #ifdef __INTEL_COMPILER @@ -918,49 +925,20 @@ __asm__("emms"); #endif #endif - - assert( p != NULL ); - if( p->uType & BLOCKTYPE_DELAYSLOT ) { - recClearMem(p-1); - if( p->GetFnptr() == 0 ) - return; - } + for (int i = 0; i < pexblock->size; i++) { + x86Ptr[0] = (u8*)pstart[i].GetFnptr(); + if (x86Ptr[0] == (u8*)JITCompile) + continue; - assert( p->GetFnptr() != 0 ); - assert( p->startpc ); - - x86Ptr[0] = (u8*)p->GetFnptr(); - - // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which - MOV32ItoR(EDX, p->startpc); - PUSH32I((u32)x86Ptr[0]); // will be replaced by JMP32 - JMP32((u32)DispatcherClear - ( (u32)x86Ptr[0] + 5 )); - assert( x86Ptr[0] == (u8*)p->GetFnptr() + EE_MIN_BLOCK_BYTES ); - - pstart = PC_GETBLOCK(p->startpc); - pexblock = PC_GETBLOCKEX(pstart); - assert( pexblock->startpc == pstart->startpc ); - - if( pexblock->startpc != pstart->startpc ) { - // some bug with ffx after beating a big snake in sewers - RemoveBaseBlockEx(pexblock, 0); - pexblock->size = 0; - pexblock->startpc = 0; - return; - } - - // don't delete if last is delay - lastdelay = pexblock->size; - if( pstart[pexblock->size-1].uType & BLOCKTYPE_DELAYSLOT ) { - assert( pstart[pexblock->size-1].GetFnptr() != pstart->GetFnptr() ); - if( pstart[pexblock->size-1].GetFnptr() != 0 ) { - pstart[pexblock->size-1].uType = 0; - --lastdelay; - } + // there is a small problem: mem can be ored with 0xa<<28 or 0x8<<28, and don't know which + MOV32ItoR(EDX, pexblock->startpc + i*4); + PUSH32I((u32)x86Ptr[0]); // will be replaced by JMP32 + JMP32((u32)DispatcherClear - ( (u32)x86Ptr[0] + 5 )); + assert( x86Ptr[0] == (u8*)p->GetFnptr() + EE_MIN_BLOCK_BYTES ); } - memset(pstart, 0, lastdelay*sizeof(BASEBLOCK)); + InitRecLUT(pstart, pexblock->size); RemoveBaseBlockEx(pexblock, 0); pexblock->size = 0; @@ -969,9 +947,8 @@ void REC_CLEARM( u32 mem ) { - if ((mem) < maxrecmem && recLUT[(mem) >> 16]) { - BASEBLOCK* p = PC_GETBLOCK(mem); - if( *(u32*)p ) recClearMem(p); + if ((mem) < maxrecmem && (recLUT[(mem) >> 16] + mem)) { + recClearMem(mem); } } @@ -1283,8 +1260,8 @@ { BASEBLOCK* pblock = PC_GETBLOCK(temppc); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { - if( pc == pblock->startpc ) + if( pblock->GetFnptr() != (uptr)JITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { + if( pc == pblock->GetStartPC() ) return 0; } @@ -1299,11 +1276,11 @@ BASEBLOCK* pblock = PC_GETBLOCK(pc); // need *ppblock != s_pCurBlock because of branches - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pblock->GetFnptr() != (uptr)JITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { - if( !delayslot && pc == pblock->startpc ) { + if( !delayslot && pc == pblock->GetStartPC() ) { // code already in place, so jump to it and exit recomp - assert( PC_GETBLOCKEX(pblock)->startpc == pblock->startpc ); + assert( PC_GETBLOCKEX(pc)->startpc == pblock->GetStartPC() ); iFlushCall(FLUSH_EVERYTHING); MOV32ItoM((uptr)&cpuRegs.pc, pc); @@ -1321,10 +1298,10 @@ } else { - if( !(delayslot && pblock->startpc == pc) ) { + if( !(delayslot && pblock->GetStartPC() == pc) ) { u8* oldX86 = x86Ptr[0]; - //__Log("clear block %x\n", pblock->startpc); - recClearMem(pblock); + //__Log("clear block %x\n", pblock->GetStartPC()); + recClearMem(pc); x86Ptr[0] = oldX86; if( delayslot ) Console::Notice("delay slot %x", params pc); @@ -1332,8 +1309,10 @@ } } +#if 1 if( delayslot ) pblock->uType = BLOCKTYPE_DELAYSLOT; +#endif s_pCode = (int *)PSM( pc ); assert(s_pCode); @@ -1541,14 +1520,14 @@ s_pCurBlock = PC_GETBLOCK(startpc); - if( s_pCurBlock->GetFnptr() ) { + if( s_pCurBlock->GetFnptr() != (uptr)JITCompile ) { // clear if already taken - assert( s_pCurBlock->startpc < startpc ); - recClearMem(s_pCurBlock); + assert( s_pCurBlock->GetStartPC() < startpc ); + recClearMem(startpc); } - if( s_pCurBlock->startpc == startpc ) { - s_pCurBlockEx = PC_GETBLOCKEX(s_pCurBlock); + if( s_pCurBlock->GetStartPC() == startpc ) { + s_pCurBlockEx = PC_GETBLOCKEX(startpc); assert( s_pCurBlockEx->startpc == startpc ); } else { @@ -1575,7 +1554,7 @@ x86Align(16); recPtr = x86Ptr[0]; s_pCurBlock->SetFnptr( (uptr)x86Ptr[0] ); - s_pCurBlock->startpc = startpc; + s_pCurBlock->SetStartPC(startpc); branch = 0; @@ -1612,9 +1591,9 @@ while(1) { BASEBLOCK* pblock = PC_GETBLOCK(i); - if( pblock->GetFnptr() != 0 && pblock->startpc != s_pCurBlock->startpc ) { + if( pblock->GetFnptr() != (uptr)JITCompile && pblock->GetStartPC() != s_pCurBlock->GetStartPC() ) { - if( i == pblock->startpc ) { + if( i == pblock->GetStartPC() ) { // branch = 3 willbranch3 = 1; s_nEndBlock = i; @@ -1943,16 +1922,26 @@ assert( (pc-startpc)>>2 <= 0xffff ); s_pCurBlockEx->size = (pc-startpc)>>2; + for(i = 1; i <= (u32)s_pCurBlockEx->size-1; ++i) { + if (!s_pCurBlock[i].GetStartPC()) + s_pCurBlock[i].SetStartPC( startpc ); + } + + +// This is just wrong, right? How can setting a jump to any point in this block +// to jump to the beginning of the block possibly be right? +#ifdef ZERO_TOLERANCE for(i = 1; i < (u32)s_pCurBlockEx->size-1; ++i) { s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; + s_pCurBlock[i].SetStartPC( p_CurBlock->startpc ); } // don't overwrite if delay slot if( i < (u32)s_pCurBlockEx->size && !(s_pCurBlock[i].uType & BLOCKTYPE_DELAYSLOT) ) { - s_pCurBlock[i].SetFnptr( s_pCurBlock->GetFnptr() ); - s_pCurBlock[i].startpc = s_pCurBlock->startpc; + s_pCurBlock[i].SetFnptr(0); + s_pCurBlock[i].SetStartPC(0); } +#endif // set the block ptr AddBaseBlockEx(s_pCurBlockEx, 0); @@ -2021,18 +2010,18 @@ u32 nEndBlock = s_nEndBlock; s_pCurBlock = PC_GETBLOCK(pc); assert( ptr != NULL ); - - if( s_pCurBlock->startpc != pc ) + + if( s_pCurBlock->GetStartPC() != pc ) recRecompile(pc); - if( pcurblock->startpc == startpc ) { - assert( pcurblock->GetFnptr() ); - assert( s_pCurBlock->startpc == nEndBlock ); + if( pcurblock->GetStartPC() == startpc ) { + assert( pcurblock->GetFnptr() != (uptr)JITCompile ); + assert( s_pCurBlock->GetStartPC() == nEndBlock ); *ptr = s_pCurBlock->GetFnptr() - ( (u32)ptr + 4 ); } else { recRecompile(startpc); - assert( pcurblock->GetFnptr() != 0 ); + assert( pcurblock->GetFnptr() != (uptr)JITCompile ); } } }