diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj index fada6bf602..89ecd254a7 100644 --- a/Source/Core/DSPCore/DSPCore.vcproj +++ b/Source/Core/DSPCore/DSPCore.vcproj @@ -490,6 +490,10 @@ RelativePath=".\Src\Jit\DSPJitUtil.cpp" > + + extended) + return false; + if ((inst >> 12) != 0x3) + return false; + /* + if((inst & 0x00ff) == 0x00c0) { + fprintf(stderr,"blocking %04x\n", inst); + return true; + } + */ + return false; +} + +static bool checkMainExclude(UDSPInstruction inst) +{ + /* + if((inst & 0xfffc) == 0x1fcc) + return true; + */ + // if((inst & 0xfffc) == 0x1fcc) + // return true; + return false; +} DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) { @@ -112,35 +140,6 @@ void DSPEmitter::checkExceptions(u32 retval) SetJumpTarget(skipCheck); } -static bool checkExtendedExclude(UDSPInstruction inst) -{ - const DSPOPCTemplate *tinst = GetOpTemplate(inst); - - // Call extended - if (!tinst->extended) - return false; - if ((inst >> 12) != 0x3) - return false; -/* - if((inst & 0x00ff) == 0x00c0) { - fprintf(stderr,"blocking %04x\n", inst); - return true; - } -*/ - return false; -} - -static bool checkMainExclude(UDSPInstruction inst) -{ -/* - if((inst & 0xfffc) == 0x1fcc) - return true; -*/ -// if((inst & 0xfffc) == 0x1fcc) -// return true; - return false; -} - void DSPEmitter::Default(UDSPInstruction inst) { if (opTable[inst]->reads_pc) @@ -359,11 +358,11 @@ void DSPEmitter::Compile(int start_addr) ABI_PopAllCalleeSavedRegsAndAdjustStack(); if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) { - MOV(32,R(EAX),Imm32(DSP_IDLE_SKIP_CYCLES)); + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } else { - MOV(32,R(EAX),Imm32(blockSize[start_addr])); + MOV(16, R(EAX), Imm16(blockSize[start_addr])); } RET(); @@ -379,7 +378,7 @@ void DSPEmitter::Compile(int start_addr) { break; } - else + else if (!opcode->jitFunc) { //look at g_dsp.pc if we actually branched #ifdef _M_IX86 // All32 @@ -396,11 +395,11 @@ void DSPEmitter::Compile(int start_addr) ABI_PopAllCalleeSavedRegsAndAdjustStack(); if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) { - MOV(32,R(EAX),Imm32(DSP_IDLE_SKIP_CYCLES)); + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } else { - MOV(32,R(EAX),Imm32(blockSize[start_addr])); + MOV(16, R(EAX), Imm16(blockSize[start_addr])); } RET(); @@ -443,11 +442,11 @@ void DSPEmitter::Compile(int start_addr) ABI_PopAllCalleeSavedRegsAndAdjustStack(); if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP) { - MOV(32,R(EAX),Imm32(DSP_IDLE_SKIP_CYCLES)); + MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } else { - MOV(32,R(EAX),Imm32(blockSize[start_addr])); + MOV(16, R(EAX), Imm16(blockSize[start_addr])); } RET(); } @@ -473,13 +472,13 @@ void DSPEmitter::CompileDispatcher() // Cache pointers into registers #ifdef _M_IX86 - MOV(32, R(ESI), M(&cyclesLeft)); + MOV(16, R(ESI), M(&cyclesLeft)); MOV(32, R(EBX), ImmPtr(blocks)); #else // Using R12 here since it is callee save register on both // linux and windows 64. MOV(64, R(R12), ImmPtr(&cyclesLeft)); - MOV(32, R(R12), MatR(R12)); + MOV(16, R(R12), MatR(R12)); MOV(64, R(RBX), ImmPtr(blocks)); #endif @@ -510,9 +509,9 @@ void DSPEmitter::CompileDispatcher() // Decrement cyclesLeft #ifdef _M_IX86 - SUB(32, R(ESI), R(EAX)); + SUB(16, R(ESI), R(EAX)); #else - SUB(32, R(R12), R(EAX)); + SUB(16, R(R12), R(EAX)); #endif J_CC(CC_A, dispatcherLoop); diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index bbbfb5b196..22b4dd723d 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -249,12 +249,13 @@ public: // CALL this to start the dispatcher const u8 *enterDispatcher; u16 compilePC; + u16 startAddr; CompiledCode *blockLinks; + u16 *blockSize; private: CompiledCode *blocks; const u8 *blockLinkEntry; - u16 *blockSize; u16 compileSR; // The index of the last stored ext value (compile time). diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp index ca9ff78381..14fc9f025a 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp @@ -18,6 +18,7 @@ #include "../DSPMemoryMap.h" #include "../DSPEmitter.h" #include "../DSPStacks.h" +#include "../DSPAnalyzer.h" #include "DSPJitUtil.h" #include "x64Emitter.h" #include "ABI.h" @@ -146,31 +147,66 @@ void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter) //} } +void WriteBranchExit(DSPEmitter& emitter) +{ + // ABI_RestoreStack(0); + emitter.ABI_PopAllCalleeSavedRegsAndAdjustStack(); + if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP) + { + emitter.MOV(16, R(EAX), Imm16(0x1000)); + } + else + { + emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr])); + } + emitter.RET(); +} + void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) { u16 dest = dsp_imem_read(emitter.compilePC + 1); #ifdef _M_IX86 // All32 emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); - // Jump directly to the called block if it has already been compiled. - // TODO: Subtract cycles from cyclesLeft - if (emitter.blockLinks[dest]) - { - emitter.JMPptr(M(&emitter.blockLinks[dest])); - } + // Jump directly to the called block if it has already been compiled. (Not working) + //if (emitter.blockLinks[dest]) + //{ + // // Check if we have enough cycles to execute the next block + // emitter.MOV(16, R(ESI), M(&cyclesLeft)); + // emitter.CMP(16, R(ESI),Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + // FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + // emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); + // emitter.MOV(16, M(&cyclesLeft), R(ESI)); + // emitter.JMPptr(M(&emitter.blockLinks[dest])); + // emitter.ClearCallFlag(); + + // emitter.SetJumpTarget(notEnoughCycles); + //} #else emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), Imm16(dest)); - // Jump directly to the next block if it has already been compiled. - // TODO: Subtract cycles from cyclesLeft - if (emitter.blockLinks[dest]) - { - emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); - emitter.JMPptr(R(RAX)); - emitter.ClearCallFlag(); - } + // Jump directly to the next block if it has already been compiled. (Not working) + //if (emitter.blockLinks[dest]) + //{ + // // Check if we have enough cycles to execute the next block + // emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); + // emitter.MOV(16, R(RAX), MatR(R12)); + // emitter.CMP(16,R(RAX),Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + // FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + // emitter.SUB(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr])); + // emitter.MOV(16, MatR(R12), R(RAX)); + + // emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); + // emitter.JMPptr(R(RAX)); + // emitter.ClearCallFlag(); + + // emitter.SetJumpTarget(notEnoughCycles); + //} #endif + WriteBranchExit(emitter); } // Generic jmp implementation // Jcc addressA @@ -178,19 +214,16 @@ void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) // aaaa aaaa aaaa aaaa // Jump to addressA if condition cc has been met. Set program counter to // address represented by value that follows this "jmp" instruction. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::jcc(const UDSPInstruction opc) { - // Disabled as jcc has issues in games - Default(opc); return; -#if 0 #ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); #else MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); #endif ReJitConditional(opc, *this); -#endif } void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) @@ -208,13 +241,21 @@ void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter) emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), R(RSI)); #endif + WriteBranchExit(emitter); } // Generic jmpr implementation // JMPcc $R // 0001 0111 rrr0 cccc // Jump to address; set program counter to a value from register $R. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::jmprcc(const UDSPInstruction opc) { +#ifdef _M_IX86 // All32 + MOV(16, M(&g_dsp.pc), Imm16(compilePC + 1)); +#else + MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); + MOV(16, MatR(RAX), Imm16(compilePC + 1)); +#endif ReJitConditional(opc, *this); } @@ -227,24 +268,43 @@ void r_call(const UDSPInstruction opc, DSPEmitter& emitter) emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest)); // Jump directly to the called block if it has already been compiled. - // TODO: Subtract cycles from cyclesLeft if (emitter.blockLinks[dest]) { + // Check if we have enough cycles to execute the next block + emitter.MOV(16, R(ESI), M(&cyclesLeft)); + emitter.CMP(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(ESI), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(16, M(&cyclesLeft), R(ESI)); emitter.JMPptr(M(&emitter.blockLinks[dest])); + emitter.ClearCallFlag(); + + emitter.SetJumpTarget(notEnoughCycles); } #else emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), Imm16(dest)); // Jump directly to the called block if it has already been compiled. - // TODO: Subtract cycles from cyclesLeft if (emitter.blockLinks[dest]) { + // Check if we have enough cycles to execute the next block + emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft)); + emitter.MOV(16, R(RAX), MatR(R12)); + emitter.CMP(16,R(RAX), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(RAX), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(16, MatR(R12), R(RAX)); emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest]))); emitter.JMPptr(R(RAX)); emitter.ClearCallFlag(); + + emitter.SetJumpTarget(notEnoughCycles); } #endif + WriteBranchExit(emitter); } // Generic call implementation // CALLcc addressA @@ -253,13 +313,14 @@ void r_call(const UDSPInstruction opc, DSPEmitter& emitter) // Call function if condition cc has been met. Push program counter of // instruction following "call" to $st0. Set program counter to address // represented by value that follows this "call" instruction. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::call(const UDSPInstruction opc) { #ifdef _M_IX86 // All32 - MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1)); + MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2)); #else MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); - MOV(16, MatR(RAX), Imm16(compilePC + 1)); + MOV(16, MatR(RAX), Imm16(compilePC + 2)); #endif ReJitConditional(opc, *this); } @@ -279,6 +340,7 @@ void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), R(RSI)); #endif + WriteBranchExit(emitter); } // Generic callr implementation // CALLRcc $R @@ -286,6 +348,7 @@ void r_callr(const UDSPInstruction opc, DSPEmitter& emitter) // Call function if condition cc has been met. Push program counter of // instruction following "call" to call stack $st0. Set program counter to // register $R. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::callr(const UDSPInstruction opc) { #ifdef _M_IX86 // All32 @@ -306,11 +369,11 @@ void r_ifcc(const UDSPInstruction opc, DSPEmitter& emitter) emitter.MOV(16, MatR(RAX), Imm16(emitter.compilePC + 1)); #endif } - -// Generic jmpr implementation -// JMPcc $R -// 0001 0111 rrr0 cccc -// Jump to address; set program counter to a value from register $R. +// Generic if implementation +// IFcc +// 0000 0010 0111 cccc +// Execute following opcode if the condition has been met. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::ifcc(const UDSPInstruction opc) { #ifdef _M_IX86 // All32 @@ -320,6 +383,7 @@ void DSPEmitter::ifcc(const UDSPInstruction opc) MOV(16, MatR(RAX), Imm16((compilePC + 1) + opTable[compilePC + 1]->size)); #endif ReJitConditional(opc, *this); + WriteBranchExit(*this); } void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) @@ -331,6 +395,7 @@ void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); emitter.MOV(16, MatR(RAX), R(DX)); #endif + WriteBranchExit(emitter); } // Generic ret implementation @@ -338,6 +403,7 @@ void r_ret(const UDSPInstruction opc, DSPEmitter& emitter) // 0000 0010 1101 cccc // Return from subroutine if condition cc has been met. Pops stored PC // from call stack $st0 and sets $pc to this location. +// NOTE: Cannot use Default(opc) here because of the need to write branch exit void DSPEmitter::ret(const UDSPInstruction opc) { #ifdef _M_IX86 // All32 @@ -563,6 +629,7 @@ void DSPEmitter::bloop(const UDSPInstruction opc) MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); #endif + WriteBranchExit(*this); SetJumpTarget(exit); } @@ -607,5 +674,6 @@ void DSPEmitter::bloopi(const UDSPInstruction opc) MOV(64, R(RAX), ImmPtr(&(g_dsp.pc))); MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size)); #endif + WriteBranchExit(*this); } }