/* Pcsx - Pc Psx Emulator * Copyright (C) 1999-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef __WIN32__ #pragma warning(disable:4244) #pragma warning(disable:4761) #endif #include #include #include #include "PsxCommon.h" #include "ix86.h" static u32 *recLUT; #define PC_REC(x) (recLUT[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 RECMEM_SIZE (8*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 int count; /* recompiler intruction count */ static int branch; /* set for branch */ static u32 target; /* branch target */ static void (*recBSC[64])(); static void (*recSPC[64])(); static void (*recREG[32])(); static void (*recCP0[32])(); static void (*recCP2[64])(); static void (*recCP2BSC[32])(); /* set a pending branch */ #define SetBranch() { \ branch = 1; \ psxRegs.code = PSXMu32(pc); \ pc+=4; count++; \ recBSC[psxRegs.code>>26](); \ \ MOV32MtoR(EAX, (u32)&target); \ MOV32RtoM((u32)&psxRegs.pc, EAX); \ CALLFunc((u32)psxBranchTest); \ } #define REC_FUNC(f) \ void psx##f(); \ static void rec##f() { \ MOV32ItoM((u32)&psxRegs.code, (u32)psxRegs.code); \ MOV32ItoM((u32)&psxRegs.pc, (u32)pc); \ CALLFunc((u32)psx##f); \ /* branch = 2; */\ } #define REC_SYS(f) \ void psx##f(); \ static void rec##f() { \ MOV32ItoM((u32)&psxRegs.code, (u32)psxRegs.code); \ MOV32ItoM((u32)&psxRegs.pc, (u32)pc); \ CALLFunc((u32)psx##f); \ branch = 2; \ } #define REC_BRANCH(f) \ void psx##f(); \ static void rec##f() { \ MOV32ItoM((u32)&psxRegs.code, (u32)psxRegs.code); \ MOV32ItoM((u32)&psxRegs.pc, (u32)pc); \ CALLFunc((u32)psx##f); \ branch = 2; \ count++; \ } static void recRecompile(); static int recInit() { int i; recLUT = (u32*) malloc(0x010000 * 4); recMem = (char*) malloc(RECMEM_SIZE); recRAM = (char*) malloc(0x200000); recROM = (char*) malloc(0x080000); if (recRAM == NULL || recROM == NULL || recMem == NULL || recLUT == NULL) { SysMessage("Error allocating memory"); return -1; } for (i=0; i<0x80; i++) recLUT[i + 0x0000] = (u32)&recRAM[(i & 0x1f) << 16]; memcpy(recLUT + 0x8000, recLUT, 0x80 * 4); memcpy(recLUT + 0xa000, recLUT, 0x80 * 4); for (i=0; i<0x08; i++) recLUT[i + 0xbfc0] = (u32)&recROM[i << 16]; return 0; } static void recReset() { memset(recRAM, 0, 0x200000); memset(recROM, 0, 0x080000); x86Init(recMem); branch = 0; } static void recShutdown() { if (recMem == NULL) return; free(recLUT); free(recMem); free(recRAM); free(recROM); } static void recError() { SysReset(); ClosePlugins(); SysMessage("Unrecoverable error while running recompiler\n"); SysRunGui(); } #define 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(); \ } \ (*recFunc)(); \ } static void DumpRegs() { 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"); } } static void recExecuteBios() { while (psxRegs.pc != 0x80030000) { execute(); } } 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... /********************************************************* * Arithmetic with immediate operand * * Format: OP rt, rs, immediate * *********************************************************/ /* REC_FUNC(ADDI); REC_FUNC(ADDIU); REC_FUNC(ANDI); REC_FUNC(ORI); REC_FUNC(XORI); REC_FUNC(SLTI); REC_FUNC(SLTIU); #if 0*/ static void recADDIU() { // Rt = Rs + Im if (!_Rt_) return; if (_Rs_) { if (_Rs_ == _Rt_) { ADD32ItoM((u32)&psxRegs.GPR.r[_Rt_], _Imm_); } else { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } else { MOV32ItoM((u32)&psxRegs.GPR.r[_Rt_], _Imm_); } } static void recADDI() { // Rt = Rs + Im recADDIU(); } static void recSLTI() { // Rt = Rs < Im (signed) if (!_Rt_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); CMP32ItoR(EAX, _Imm_); SETL8R (EAX); AND32ItoR(EAX, 0xff); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } static void recSLTIU() { // Rt = Rs < Im (unsigned) if (!_Rt_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); CMP32ItoR(EAX, _Imm_); SETB8R (EAX); AND32ItoR(EAX, 0xff); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } static void recANDI() { // Rt = Rs And Im if (!_Rt_) return; if (_Rs_ && _ImmU_) { if (_Rs_ == _Rt_) { AND32ItoM((u32)&psxRegs.GPR.r[_Rt_], _ImmU_); } else { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); AND32ItoR(EAX, _ImmU_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } else { XOR32RtoR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } static void recORI() { // Rt = Rs Or Im if (!_Rt_) return; if (_Rs_) { if (_Rs_ == _Rt_) { OR32ItoM((u32)&psxRegs.GPR.r[_Rt_], _ImmU_); } else { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_ImmU_) OR32ItoR (EAX, _ImmU_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } else { MOV32ItoM((u32)&psxRegs.GPR.r[_Rt_], _ImmU_); } } static void recXORI() { // Rt = Rs Xor Im if (!_Rt_) return; if (_Rs_) { if (_Rs_ == _Rt_) { XOR32ItoM((u32)&psxRegs.GPR.r[_Rt_], _ImmU_); } else { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); XOR32ItoR(EAX, _ImmU_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } else { MOV32ItoR(EAX, _ImmU_ ^ 0); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } } //#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; MOV32ItoM((u32)&psxRegs.GPR.r[_Rt_], psxRegs.code << 16); } //#endif //End of Load Higher ..... /********************************************************* * Register arithmetic * * Format: OP rd, rs, rt * *********************************************************/ /* 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); #if 0*/ static void recADDU() { // Rd = Rs + Rt if (!_Rd_) return; if (_Rs_ && _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); ADD32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); } else if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else { XOR32RtoR(EAX, EAX); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recADD() { // Rd = Rs + Rt recADDU(); } static void recSUBU() { // Rd = Rs - Rt if (!_Rd_) return; if (_Rs_ || _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); SUB32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else { XOR32RtoR(EAX, EAX); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recSUB() { // Rd = Rs - Rt recSUBU(); } static void recAND() { // Rd = Rs And Rt if (!_Rd_) return; if (_Rs_ && _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); AND32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else { XOR32RtoR(EAX, EAX); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recOR() { // Rd = Rs Or Rt if (!_Rd_) return; if (_Rs_ && _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); OR32MtoR (EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); } else if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else { XOR32RtoR(EAX, EAX); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recXOR() { // Rd = Rs Xor Rt if (!_Rd_) return; if (_Rs_ && _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); XOR32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); XOR32ItoR(EAX, 0); } else if (_Rt_) { XOR32RtoR(EAX, EAX); XOR32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); } else { XOR32RtoR(EAX, EAX); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recNOR() { // Rd = Rs Nor Rt if (!_Rd_) return; if (_Rs_ && _Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); OR32MtoR (EAX, (u32)&psxRegs.GPR.r[_Rt_]); NOT32R (EAX); } else if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); NOT32R (EAX); } else if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); NOT32R (EAX); } else { MOV32ItoR(EAX, ~0); } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recSLT() { // Rd = Rs < Rt (signed) if (!_Rd_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); CMP32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); SETL8R (EAX); AND32ItoR(EAX, 0xff); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recSLTU() { // Rd = Rs < Rt (unsigned) if (!_Rd_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); CMP32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); SBB32RtoR(EAX, EAX); NEG32R (EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } //#endif //End of * Register arithmetic /********************************************************* * Register mult/div & Register trap logic * * Format: OP rs, rt * *********************************************************/ /*REC_FUNC(MULT); REC_FUNC(MULTU); REC_FUNC(DIV); REC_FUNC(DIVU); #if 0*/ static void recMULT() { // Lo/Hi = Rs * Rt (signed) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); IMUL32M ((u32)&psxRegs.GPR.r[_Rt_]); MOV32RtoM((u32)&psxRegs.GPR.n.lo, EAX); MOV32RtoM((u32)&psxRegs.GPR.n.hi, EDX); } static void recMULTU() { // Lo/Hi = Rs * Rt (unsigned) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); MUL32M ((u32)&psxRegs.GPR.r[_Rt_]); MOV32RtoM((u32)&psxRegs.GPR.n.lo, EAX); MOV32RtoM((u32)&psxRegs.GPR.n.hi, EDX); } static void recDIV() { // Lo/Hi = Rs / Rt (signed) MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); CMP32ItoR(ECX, 0); j8Ptr[0] = JE8(0); MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); CDQ(); IDIV32R (ECX); MOV32RtoM((u32)&psxRegs.GPR.n.lo, EAX); MOV32RtoM((u32)&psxRegs.GPR.n.hi, EDX); x86SetJ8(j8Ptr[0]); } static void recDIVU() { // Lo/Hi = Rs / Rt (unsigned) MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rt_]); CMP32ItoR(ECX, 0); j8Ptr[0] = JE8(0); MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); XOR32RtoR(EDX, EDX); DIV32R (ECX); MOV32RtoM((u32)&psxRegs.GPR.n.lo, EAX); MOV32RtoM((u32)&psxRegs.GPR.n.hi, EDX); x86SetJ8(j8Ptr[0]); } //#endif //End of * Register mult/div & Register trap logic /*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); //#if 0 static void recLB() { // Rt = mem[Rs + Im] (signed) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemRead8); if (_Rt_) { MOVSX32R8toR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } ADD32ItoR(ESP, 4); } static void recLBU() { // Rt = mem[Rs + Im] (unsigned) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemRead8); if (_Rt_) { MOVZX32R8toR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } ADD32ItoR(ESP, 4); } static void recLH() { // Rt = mem[Rs + Im] (signed) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemRead16); if (_Rt_) { MOVSX32R16toR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } ADD32ItoR(ESP, 4); } static void recLHU() { // Rt = mem[Rs + Im] (unsigned) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemRead16); if (_Rt_) { MOVZX32R16toR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } ADD32ItoR(ESP, 4); } static void recLW() { // Rt = mem[Rs + Im] (unsigned) MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemRead32); if (_Rt_) { MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } ADD32ItoR(ESP, 4); } /* void recLWL() { } void recLWR() { } */ static void recSB() { // mem[Rs + Im] = Rt PUSH32M ((u32)&psxRegs.GPR.r[_Rt_]); MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemWrite8); ADD32ItoR(ESP, 8); } static void recSH() { // mem[Rs + Im] = Rt PUSH32M ((u32)&psxRegs.GPR.r[_Rt_]); MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemWrite16); ADD32ItoR(ESP, 8); } static void recSW() { // mem[Rs + Im] = Rt PUSH32M ((u32)&psxRegs.GPR.r[_Rt_]); MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); if (_Imm_) ADD32ItoR(EAX, _Imm_); PUSH32R (EAX); CALLFunc((u32)psxMemWrite32); ADD32ItoR(ESP, 8); } //#endif /* void recSWL() { } void recSWR() { } */ /*REC_FUNC(SLL); REC_FUNC(SRL); REC_FUNC(SRA); #if 0*/ static void recSLL() { // Rd = Rt << Sa if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Sa_) SHL32ItoR(EAX, _Sa_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } else { XOR32RtoR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } } static void recSRL() { // Rd = Rt >> Sa if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Sa_) SHR32ItoR(EAX, _Sa_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } else { XOR32RtoR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } } static void recSRA() { // Rd = Rt >> Sa if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Sa_) SAR32ItoR(EAX, _Sa_); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } else { XOR32RtoR(EAX, EAX); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } } //#endif /*REC_FUNC(SLLV); REC_FUNC(SRLV); REC_FUNC(SRAV); #if 0*/ static void recSLLV() { // Rd = Rt << Rs if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Rs_) { MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rs_]); SHL32CLtoR(EAX); } } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recSRLV() { // Rd = Rt >> Rs if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Rs_) { MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rs_]); SHR32CLtoR(EAX); } } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recSRAV() { // Rd = Rt >> Rs if (!_Rd_) return; if (_Rt_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); if (_Rs_) { MOV32MtoR(ECX, (u32)&psxRegs.GPR.r[_Rs_]); SAR32CLtoR(EAX); } } MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } //#endif /*REC_SYS(SYSCALL); REC_SYS(BREAK); #if 0*/ static void recSYSCALL() { MOV32ItoR(EAX, pc - 4); MOV32RtoM((u32)&psxRegs.pc, EAX); PUSH32I (branch == 1 ? 1 : 0); PUSH32I (0x20); CALLFunc ((u32)psxException); ADD32ItoR(ESP, 8); if (!branch) branch = 2; } static void recBREAK() { } //#endif /* REC_FUNC(MFHI); REC_FUNC(MTHI); REC_FUNC(MFLO); REC_FUNC(MTLO); #if 0*/ static void recMFHI() { // Rd = Hi if (!_Rd_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.n.hi); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recMTHI() { // Hi = Rs MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); MOV32RtoM((u32)&psxRegs.GPR.n.hi, EAX); } static void recMFLO() { // Rd = Lo if (!_Rd_) return; MOV32MtoR(EAX, (u32)&psxRegs.GPR.n.lo); MOV32RtoM((u32)&psxRegs.GPR.r[_Rd_], EAX); } static void recMTLO() { // Lo = Rs MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); MOV32RtoM((u32)&psxRegs.GPR.n.lo, EAX); } //#endif /*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); #if 0*/ static void recBLTZ() { // Branch if Rs < 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JL8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recBGEZ() { // Branch if Rs >= 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JGE8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recBLTZAL() { // Branch if Rs < 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JL8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); MOV32ItoM((u32)&psxRegs.GPR.r[31], pc + 4); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recBGEZAL() { // Branch if Rs >= 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JGE8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); MOV32ItoM((u32)&psxRegs.GPR.r[31], pc + 4); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recJ() { // j target MOV32ItoM((u32)&target, _Target_ * 4 + (pc & 0xf0000000)); SetBranch(); } static void recJAL() { // jal target MOV32ItoM((u32)&target, _Target_ * 4 + (pc & 0xf0000000)); MOV32ItoM((u32)&psxRegs.GPR.r[31], pc + 4); SetBranch(); } static void recJR() { // jr Rs MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); MOV32RtoM((u32)&target, EAX); SetBranch(); } static void recJALR() { // jalr Rs MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); MOV32RtoM((u32)&target, EAX); if (_Rd_) { MOV32ItoM((u32)&psxRegs.GPR.r[_Rd_], pc + 4); } SetBranch(); } static void recBEQ() { // Branch if Rs == Rt if (_Rs_ == _Rt_) { MOV32ItoM((u32)&target, _Imm_ * 4 + pc); } else { if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); } else { XOR32RtoR(EAX, EAX); } CMP32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); j8Ptr[0] = JE8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); } SetBranch(); } static void recBNE() { // Branch if Rs != Rt if (_Rs_) { MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rs_]); } else { XOR32RtoR(EAX, EAX); } CMP32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); j8Ptr[0] = JNE8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recBLEZ() { // Branch if Rs <= 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JLE8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); SetBranch(); } static void recBGTZ() { // Branch if Rs > 0 CMP32ItoM((u32)&psxRegs.GPR.r[_Rs_], 0); j8Ptr[0] = JG8(0); MOV32ItoM((u32)&target, pc+4); j8Ptr[1] = JMP8(0); x86SetJ8(j8Ptr[0]); MOV32ItoM((u32)&target, _Imm_ * 4 + pc); x86SetJ8(j8Ptr[1]); SetBranch(); } //#endif /*REC_FUNC(MFC0); REC_FUNC(MTC0); REC_FUNC(CFC0); REC_FUNC(CTC0); REC_FUNC(RFE); #if 0*/ static void recMFC0() { // Rt = Cop0->Rd if (!_Rt_) return; MOV32MtoR(EAX, (u32)&psxRegs.CP0.r[_Rd_]); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } static void recCFC0() { // Rt = Cop0->Rd if (!_Rt_) return; MOV32MtoR(EAX, (u32)&psxRegs.CP0.r[_Rd_]); MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } static void recMTC0() { // Cop0->Rd = Rt MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); MOV32RtoM((u32)&psxRegs.CP0.r[_Rd_], EAX); } static void recCTC0() { // Cop0->Rd = Rt MOV32MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); MOV32RtoM((u32)&psxRegs.CP0.r[_Rd_], EAX); } static void recRFE() { 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); } //#endif #define CP2_FUNC(f) \ void gte##f(); \ static void rec##f() { \ MOV32ItoM((u32)&psxRegs.code, (u32)psxRegs.code); \ MOV32ItoM((u32)&psxRegs.pc, (u32)pc); \ CALLFunc ((u32)gte##f); \ /* branch = 2; */\ } CP2_FUNC(MFC2); CP2_FUNC(MTC2); CP2_FUNC(CFC2); CP2_FUNC(CTC2); CP2_FUNC(LWC2); CP2_FUNC(SWC2); CP2_FUNC(RTPS); CP2_FUNC(OP); CP2_FUNC(NCLIP); CP2_FUNC(DPCS); CP2_FUNC(INTPL); CP2_FUNC(MVMVA); CP2_FUNC(NCDS); CP2_FUNC(NCDT); CP2_FUNC(CDP); CP2_FUNC(NCCS); CP2_FUNC(CC); CP2_FUNC(NCS); CP2_FUNC(NCT); CP2_FUNC(SQR); CP2_FUNC(DCPL); CP2_FUNC(DPCT); CP2_FUNC(AVSZ3); CP2_FUNC(AVSZ4); CP2_FUNC(RTPT); CP2_FUNC(GPF); CP2_FUNC(GPL); CP2_FUNC(NCCT); static void recHLE() { MOV32ItoR(EAX, (u32)psxHLEt[psxRegs.code & 0xff]); CALL32R(EAX); 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() { /* if x86Ptr reached the mem limit reset whole mem */ if (((u32)x86Ptr - (u32)recMem) >= (RECMEM_SIZE - 0x10000)) recReset(); PC_REC32(psxRegs.pc) = (u32)x86Ptr; pc = psxRegs.pc; for (count=0; count<500;) { char *p; p = (char *)PSXM(pc); if (p == NULL) recError(); psxRegs.code = *(u32 *)p; pc+=4; count++; recBSC[psxRegs.code>>26](); if (branch) { break; } } if (!branch) { MOV32ItoM((u32)&psxRegs.pc, pc); } /* store cycle */ ADD32ItoM((u32)&psxRegs.cycle, count); branch = 0; RET(); } R3000Acpu psxRec = { recInit, recReset, recExecute, recExecuteBlock, recClear, recShutdown };