diff --git a/Source/Core/DSPCore/Src/DSPAnalyzer.h b/Source/Core/DSPCore/Src/DSPAnalyzer.h index 6ccd8f771f..aeb3b9e480 100644 --- a/Source/Core/DSPCore/Src/DSPAnalyzer.h +++ b/Source/Core/DSPCore/Src/DSPAnalyzer.h @@ -32,8 +32,7 @@ enum CODE_IDLE_SKIP = 2, CODE_LOOP_START = 4, CODE_LOOP_END = 8, - CODE_CALL = 16, - CODE_UPDATE_SR = 32, + CODE_UPDATE_SR = 16, }; // Easy to query array covering the whole of instruction memory. diff --git a/Source/Core/DSPCore/Src/DSPEmitter.cpp b/Source/Core/DSPCore/Src/DSPEmitter.cpp index b887f2d0d7..5835196a60 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.cpp +++ b/Source/Core/DSPCore/Src/DSPEmitter.cpp @@ -31,9 +31,6 @@ using namespace Gen; const u8 *stubEntryPoint; -u16 blocksCompiled; -u16 unresolvedCalls; -u16 unresolvedCallsThisBlock; DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) { @@ -59,8 +56,6 @@ DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1) blockLinks[i] = 0; blockSize[i] = 0; } - blocksCompiled = 0; - unresolvedCalls = 0; } DSPEmitter::~DSPEmitter() @@ -79,8 +74,6 @@ void DSPEmitter::ClearIRAM() { blockLinks[i] = 0; blockSize[i] = 0; } - blocksCompiled = 0; - unresolvedCalls = 0; } // Must go out of block if exception is detected @@ -196,41 +189,11 @@ void DSPEmitter::unknown_instruction(UDSPInstruction inst) PanicAlert("unknown_instruction %04x - Fix me ;)", inst); } -void DSPEmitter::ClearCallFlag() -{ - --unresolvedCallsThisBlock; -} - -void DSPEmitter::Compile(int start_addr) +void DSPEmitter::Compile(u16 start_addr) { // Remember the current block address for later startAddr = start_addr; - blocksCompiled++; - unresolvedCallsThisBlock = 0; - - // If the number of unresolved calls exceeds 8, there is a critical - // block that probably cannot be resolved. If this occurs, quit linking - // blocks. Currently occurs in the zelda ucode. - if (unresolvedCalls <= 8) - { - // After every 10 blocks, clear out the blocks that have unresolved - // calls, and reattempt relinking. - if (blocksCompiled >= 10 && unresolvedCalls > 0) - { - for(int i = 0x0000; i < MAX_BLOCKS; ++i) - { - if (DSPAnalyzer::code_flags[i] & DSPAnalyzer::CODE_CALL) - { - blocks[i] = (CompiledCode)stubEntryPoint; - blockLinks[i] = 0; - blockSize[i] = 0; - } - } - // Reset and reattempt relinking - blocksCompiled = 0; - unresolvedCalls = 0; - } - } + unresolvedJumps[start_addr].clear(); const u8 *entryPoint = AlignCode16(); ABI_PushAllCalleeSavedRegsAndAdjustStack(); @@ -288,19 +251,14 @@ void DSPEmitter::Compile(int start_addr) UDSPInstruction inst = dsp_imem_read(compilePC); const DSPOPCTemplate *opcode = GetOpTemplate(inst); - // Scan for CALL's to delay block link. TODO: Scan for J_CC after it is jitted. - if (opcode->jitFunc && - ((opcode->opcode >= 0x0290 && opcode->opcode <= 0x029f) || - (opcode->opcode >= 0x02b0 && opcode->opcode <= 0x02bf))) - { - ++unresolvedCallsThisBlock; - } - EmitInstruction(inst); blockSize[start_addr]++; compilePC += opcode->size; + // If the block was trying to link into itself, remove the link + unresolvedJumps[start_addr].remove(compilePC); + fixup_pc = true; // Handle loop condition, only if current instruction was flagged as a loop destination @@ -411,16 +369,26 @@ void DSPEmitter::Compile(int start_addr) // Mark this block as a linkable destination if it does not contain // any unresolved CALL's - if (unresolvedCallsThisBlock == 0) + if (unresolvedJumps[start_addr].empty()) { - DSPAnalyzer::code_flags[start_addr] &= ~DSPAnalyzer::CODE_CALL; blockLinks[start_addr] = (CompiledCode)blockLinkEntry; - } - else - { - DSPAnalyzer::code_flags[start_addr] |= DSPAnalyzer::CODE_CALL; - blockLinks[start_addr] = 0; - ++unresolvedCalls; + + for(u16 i = 0x0000; i < 0xffff; ++i) + { + if (!unresolvedJumps[i].empty()) + { + // Check if there were any blocks waiting for this block to be linkable + int size = unresolvedJumps[i].size(); + unresolvedJumps[i].remove(start_addr); + if (unresolvedJumps[i].size() < size) + { + // Mark the block to be recompiled again + blocks[i] = (CompiledCode)stubEntryPoint; + blockLinks[i] = 0; + blockSize[i] = 0; + } + } + } } if (blockSize[start_addr] == 0) diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index 7e6030dab3..56749b228b 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -18,6 +18,8 @@ #ifndef _DSPEMITTER_H #define _DSPEMITTER_H +#include + #include "DSPCommon.h" #include "x64Emitter.h" @@ -41,7 +43,7 @@ public: void CompileDispatcher(); const u8 *CompileStub(); - void Compile(int start_addr); + void Compile(u16 start_addr); void ClearCallFlag(); void Default(UDSPInstruction inst); @@ -252,6 +254,7 @@ public: u16 startAddr; CompiledCode *blockLinks; u16 *blockSize; + std::list unresolvedJumps[0x10000]; private: CompiledCode *blocks; diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp index 512b36e969..2cf41b61c5 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitBranch.cpp @@ -162,49 +162,58 @@ void WriteBranchExit(DSPEmitter& emitter) emitter.RET(); } +void WriteBlockLink(DSPEmitter& emitter, u16 dest) +{ + // Jump directly to the called block if it has already been compiled. + if (!(dest >= emitter.startAddr && dest <= emitter.compilePC)) + { + if (emitter.blockLinks[dest] != 0 ) + { +#ifdef _M_IX86 // All32 + // 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.SetJumpTarget(notEnoughCycles); +#else + // Check if we have enough cycles to execute the next block + emitter.CMP(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest])); + FixupBranch notEnoughCycles = emitter.J_CC(CC_BE); + + emitter.SUB(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr])); + emitter.MOV(64, R(RAX), ImmPtr((void *)emitter.blockLinks[dest])); + emitter.JMPptr(R(RAX)); + + emitter.SetJumpTarget(notEnoughCycles); +#endif + } + else + { + // The destination has not been compiled yet. Add it to the list + // of blocks that this block is waiting on. + emitter.unresolvedJumps[emitter.startAddr].push_back(dest); + } + } +} + void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter) { u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); #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. - 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. - 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); } @@ -261,48 +270,19 @@ void DSPEmitter::jmprcc(const UDSPInstruction opc) void r_call(const UDSPInstruction opc, DSPEmitter& emitter) { - u16 dest = dsp_imem_read(emitter.compilePC + 1); emitter.MOV(16, R(DX), Imm16(emitter.compilePC + 2)); emitter.dsp_reg_store_stack(DSP_STACK_C); + u16 dest = dsp_imem_read(emitter.compilePC + 1); + const DSPOPCTemplate *opcode = GetOpTemplate(opc); + + // If the block is unconditional, attempt to link block + if (opcode->uncond_branch) + WriteBlockLink(emitter, dest); #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. - 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. - 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); }