mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
LLE JIT:
* Fixed a bug in the JCC instruction. * Changed the cycle count from u32 to u16. * Added cycle counting to the block linker. * Optimised the branch exit slightly. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6681 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
fc1db5eaa0
commit
8ccdba7273
@ -490,6 +490,10 @@
|
|||||||
RelativePath=".\Src\Jit\DSPJitUtil.cpp"
|
RelativePath=".\Src\Jit\DSPJitUtil.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\Jit\DSPJitUtil.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Src\assemble.cpp"
|
RelativePath=".\Src\assemble.cpp"
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
SDSP g_dsp;
|
SDSP g_dsp;
|
||||||
DSPBreakpoints dsp_breakpoints;
|
DSPBreakpoints dsp_breakpoints;
|
||||||
DSPCoreState core_state = DSPCORE_STOP;
|
DSPCoreState core_state = DSPCORE_STOP;
|
||||||
int cyclesLeft = 0;
|
u16 cyclesLeft = 0;
|
||||||
DSPEmitter *jit = NULL;
|
DSPEmitter *jit = NULL;
|
||||||
Common::Event step_event;
|
Common::Event step_event;
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ struct SDSP
|
|||||||
extern SDSP g_dsp;
|
extern SDSP g_dsp;
|
||||||
extern DSPBreakpoints dsp_breakpoints;
|
extern DSPBreakpoints dsp_breakpoints;
|
||||||
extern DSPEmitter *jit;
|
extern DSPEmitter *jit;
|
||||||
extern int cyclesLeft;
|
extern u16 cyclesLeft;
|
||||||
|
|
||||||
bool DSPCore_Init(const char *irom_filename, const char *coef_filename,
|
bool DSPCore_Init(const char *irom_filename, const char *coef_filename,
|
||||||
bool bUsingJIT);
|
bool bUsingJIT);
|
||||||
|
@ -26,14 +26,42 @@
|
|||||||
#include "ABI.h"
|
#include "ABI.h"
|
||||||
|
|
||||||
#define MAX_BLOCK_SIZE 250
|
#define MAX_BLOCK_SIZE 250
|
||||||
#define DSP_IDLE_SKIP_CYCLES 1000
|
#define DSP_IDLE_SKIP_CYCLES 0x1000
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
const u8 *stubEntryPoint;
|
const u8 *stubEntryPoint;
|
||||||
u16 blocksCompiled;
|
u16 blocksCompiled;
|
||||||
u16 unresolvedCalls;
|
u16 unresolvedCalls;
|
||||||
int startAddr;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1)
|
DSPEmitter::DSPEmitter() : storeIndex(-1), storeIndex2(-1)
|
||||||
{
|
{
|
||||||
@ -112,35 +140,6 @@ void DSPEmitter::checkExceptions(u32 retval)
|
|||||||
SetJumpTarget(skipCheck);
|
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)
|
void DSPEmitter::Default(UDSPInstruction inst)
|
||||||
{
|
{
|
||||||
if (opTable[inst]->reads_pc)
|
if (opTable[inst]->reads_pc)
|
||||||
@ -359,11 +358,11 @@ void DSPEmitter::Compile(int start_addr)
|
|||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
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
|
else
|
||||||
{
|
{
|
||||||
MOV(32,R(EAX),Imm32(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
@ -379,7 +378,7 @@ void DSPEmitter::Compile(int start_addr)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else
|
else if (!opcode->jitFunc)
|
||||||
{
|
{
|
||||||
//look at g_dsp.pc if we actually branched
|
//look at g_dsp.pc if we actually branched
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
@ -396,11 +395,11 @@ void DSPEmitter::Compile(int start_addr)
|
|||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
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
|
else
|
||||||
{
|
{
|
||||||
MOV(32,R(EAX),Imm32(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
RET();
|
||||||
|
|
||||||
@ -443,11 +442,11 @@ void DSPEmitter::Compile(int start_addr)
|
|||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
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
|
else
|
||||||
{
|
{
|
||||||
MOV(32,R(EAX),Imm32(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
@ -473,13 +472,13 @@ void DSPEmitter::CompileDispatcher()
|
|||||||
|
|
||||||
// Cache pointers into registers
|
// Cache pointers into registers
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
MOV(32, R(ESI), M(&cyclesLeft));
|
MOV(16, R(ESI), M(&cyclesLeft));
|
||||||
MOV(32, R(EBX), ImmPtr(blocks));
|
MOV(32, R(EBX), ImmPtr(blocks));
|
||||||
#else
|
#else
|
||||||
// Using R12 here since it is callee save register on both
|
// Using R12 here since it is callee save register on both
|
||||||
// linux and windows 64.
|
// linux and windows 64.
|
||||||
MOV(64, R(R12), ImmPtr(&cyclesLeft));
|
MOV(64, R(R12), ImmPtr(&cyclesLeft));
|
||||||
MOV(32, R(R12), MatR(R12));
|
MOV(16, R(R12), MatR(R12));
|
||||||
MOV(64, R(RBX), ImmPtr(blocks));
|
MOV(64, R(RBX), ImmPtr(blocks));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -510,9 +509,9 @@ void DSPEmitter::CompileDispatcher()
|
|||||||
|
|
||||||
// Decrement cyclesLeft
|
// Decrement cyclesLeft
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
SUB(32, R(ESI), R(EAX));
|
SUB(16, R(ESI), R(EAX));
|
||||||
#else
|
#else
|
||||||
SUB(32, R(R12), R(EAX));
|
SUB(16, R(R12), R(EAX));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
J_CC(CC_A, dispatcherLoop);
|
J_CC(CC_A, dispatcherLoop);
|
||||||
|
@ -249,12 +249,13 @@ public:
|
|||||||
// CALL this to start the dispatcher
|
// CALL this to start the dispatcher
|
||||||
const u8 *enterDispatcher;
|
const u8 *enterDispatcher;
|
||||||
u16 compilePC;
|
u16 compilePC;
|
||||||
|
u16 startAddr;
|
||||||
CompiledCode *blockLinks;
|
CompiledCode *blockLinks;
|
||||||
|
u16 *blockSize;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CompiledCode *blocks;
|
CompiledCode *blocks;
|
||||||
const u8 *blockLinkEntry;
|
const u8 *blockLinkEntry;
|
||||||
u16 *blockSize;
|
|
||||||
u16 compileSR;
|
u16 compileSR;
|
||||||
|
|
||||||
// The index of the last stored ext value (compile time).
|
// The index of the last stored ext value (compile time).
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "../DSPMemoryMap.h"
|
#include "../DSPMemoryMap.h"
|
||||||
#include "../DSPEmitter.h"
|
#include "../DSPEmitter.h"
|
||||||
#include "../DSPStacks.h"
|
#include "../DSPStacks.h"
|
||||||
|
#include "../DSPAnalyzer.h"
|
||||||
#include "DSPJitUtil.h"
|
#include "DSPJitUtil.h"
|
||||||
#include "x64Emitter.h"
|
#include "x64Emitter.h"
|
||||||
#include "ABI.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)
|
void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
u16 dest = dsp_imem_read(emitter.compilePC + 1);
|
u16 dest = dsp_imem_read(emitter.compilePC + 1);
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
||||||
|
|
||||||
// Jump directly to the called block if it has already been compiled.
|
// Jump directly to the called block if it has already been compiled. (Not working)
|
||||||
// TODO: Subtract cycles from cyclesLeft
|
//if (emitter.blockLinks[dest])
|
||||||
if (emitter.blockLinks[dest])
|
//{
|
||||||
{
|
// // Check if we have enough cycles to execute the next block
|
||||||
emitter.JMPptr(M(&emitter.blockLinks[dest]));
|
// 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
|
#else
|
||||||
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
emitter.MOV(16, MatR(RAX), Imm16(dest));
|
emitter.MOV(16, MatR(RAX), Imm16(dest));
|
||||||
|
|
||||||
// Jump directly to the next block if it has already been compiled.
|
// Jump directly to the next block if it has already been compiled. (Not working)
|
||||||
// TODO: Subtract cycles from cyclesLeft
|
//if (emitter.blockLinks[dest])
|
||||||
if (emitter.blockLinks[dest])
|
//{
|
||||||
{
|
// // Check if we have enough cycles to execute the next block
|
||||||
emitter.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
// emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft));
|
||||||
emitter.JMPptr(R(RAX));
|
// emitter.MOV(16, R(RAX), MatR(R12));
|
||||||
emitter.ClearCallFlag();
|
// 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
|
#endif
|
||||||
|
WriteBranchExit(emitter);
|
||||||
}
|
}
|
||||||
// Generic jmp implementation
|
// Generic jmp implementation
|
||||||
// Jcc addressA
|
// Jcc addressA
|
||||||
@ -178,19 +214,16 @@ void r_jcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
|||||||
// aaaa aaaa aaaa aaaa
|
// aaaa aaaa aaaa aaaa
|
||||||
// Jump to addressA if condition cc has been met. Set program counter to
|
// Jump to addressA if condition cc has been met. Set program counter to
|
||||||
// address represented by value that follows this "jmp" instruction.
|
// 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)
|
void DSPEmitter::jcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
// Disabled as jcc has issues in games
|
|
||||||
Default(opc); return;
|
|
||||||
#if 0
|
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1));
|
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2));
|
||||||
#else
|
#else
|
||||||
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
MOV(16, MatR(RAX), Imm16(compilePC + 1));
|
MOV(16, MatR(RAX), Imm16(compilePC + 2));
|
||||||
#endif
|
#endif
|
||||||
ReJitConditional<r_jcc>(opc, *this);
|
ReJitConditional<r_jcc>(opc, *this);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter)
|
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(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
emitter.MOV(16, MatR(RAX), R(RSI));
|
emitter.MOV(16, MatR(RAX), R(RSI));
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(emitter);
|
||||||
}
|
}
|
||||||
// Generic jmpr implementation
|
// Generic jmpr implementation
|
||||||
// JMPcc $R
|
// JMPcc $R
|
||||||
// 0001 0111 rrr0 cccc
|
// 0001 0111 rrr0 cccc
|
||||||
// Jump to address; set program counter to a value from register $R.
|
// 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)
|
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<r_jmprcc>(opc, *this);
|
ReJitConditional<r_jmprcc>(opc, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,24 +268,43 @@ void r_call(const UDSPInstruction opc, DSPEmitter& emitter)
|
|||||||
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
|
||||||
|
|
||||||
// Jump directly to the called block if it has already been compiled.
|
// Jump directly to the called block if it has already been compiled.
|
||||||
// TODO: Subtract cycles from cyclesLeft
|
|
||||||
if (emitter.blockLinks[dest])
|
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.JMPptr(M(&emitter.blockLinks[dest]));
|
||||||
|
emitter.ClearCallFlag();
|
||||||
|
|
||||||
|
emitter.SetJumpTarget(notEnoughCycles);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
emitter.MOV(16, MatR(RAX), Imm16(dest));
|
emitter.MOV(16, MatR(RAX), Imm16(dest));
|
||||||
|
|
||||||
// Jump directly to the called block if it has already been compiled.
|
// Jump directly to the called block if it has already been compiled.
|
||||||
// TODO: Subtract cycles from cyclesLeft
|
|
||||||
if (emitter.blockLinks[dest])
|
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.MOV(64, R(RAX), ImmPtr((void *)(emitter.blockLinks[dest])));
|
||||||
emitter.JMPptr(R(RAX));
|
emitter.JMPptr(R(RAX));
|
||||||
emitter.ClearCallFlag();
|
emitter.ClearCallFlag();
|
||||||
|
|
||||||
|
emitter.SetJumpTarget(notEnoughCycles);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(emitter);
|
||||||
}
|
}
|
||||||
// Generic call implementation
|
// Generic call implementation
|
||||||
// CALLcc addressA
|
// 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
|
// Call function if condition cc has been met. Push program counter of
|
||||||
// instruction following "call" to $st0. Set program counter to address
|
// instruction following "call" to $st0. Set program counter to address
|
||||||
// represented by value that follows this "call" instruction.
|
// 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)
|
void DSPEmitter::call(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1));
|
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 2));
|
||||||
#else
|
#else
|
||||||
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
MOV(16, MatR(RAX), Imm16(compilePC + 1));
|
MOV(16, MatR(RAX), Imm16(compilePC + 2));
|
||||||
#endif
|
#endif
|
||||||
ReJitConditional<r_call>(opc, *this);
|
ReJitConditional<r_call>(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(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
emitter.MOV(16, MatR(RAX), R(RSI));
|
emitter.MOV(16, MatR(RAX), R(RSI));
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(emitter);
|
||||||
}
|
}
|
||||||
// Generic callr implementation
|
// Generic callr implementation
|
||||||
// CALLRcc $R
|
// 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
|
// Call function if condition cc has been met. Push program counter of
|
||||||
// instruction following "call" to call stack $st0. Set program counter to
|
// instruction following "call" to call stack $st0. Set program counter to
|
||||||
// register $R.
|
// register $R.
|
||||||
|
// NOTE: Cannot use Default(opc) here because of the need to write branch exit
|
||||||
void DSPEmitter::callr(const UDSPInstruction opc)
|
void DSPEmitter::callr(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86 // All32
|
#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));
|
emitter.MOV(16, MatR(RAX), Imm16(emitter.compilePC + 1));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
// Generic if implementation
|
||||||
// Generic jmpr implementation
|
// IFcc
|
||||||
// JMPcc $R
|
// 0000 0010 0111 cccc
|
||||||
// 0001 0111 rrr0 cccc
|
// Execute following opcode if the condition has been met.
|
||||||
// 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::ifcc(const UDSPInstruction opc)
|
void DSPEmitter::ifcc(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86 // All32
|
#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));
|
MOV(16, MatR(RAX), Imm16((compilePC + 1) + opTable[compilePC + 1]->size));
|
||||||
#endif
|
#endif
|
||||||
ReJitConditional<r_ifcc>(opc, *this);
|
ReJitConditional<r_ifcc>(opc, *this);
|
||||||
|
WriteBranchExit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void r_ret(const UDSPInstruction opc, DSPEmitter& emitter)
|
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(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
emitter.MOV(16, MatR(RAX), R(DX));
|
emitter.MOV(16, MatR(RAX), R(DX));
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic ret implementation
|
// Generic ret implementation
|
||||||
@ -338,6 +403,7 @@ void r_ret(const UDSPInstruction opc, DSPEmitter& emitter)
|
|||||||
// 0000 0010 1101 cccc
|
// 0000 0010 1101 cccc
|
||||||
// Return from subroutine if condition cc has been met. Pops stored PC
|
// Return from subroutine if condition cc has been met. Pops stored PC
|
||||||
// from call stack $st0 and sets $pc to this location.
|
// 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)
|
void DSPEmitter::ret(const UDSPInstruction opc)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86 // All32
|
#ifdef _M_IX86 // All32
|
||||||
@ -563,6 +629,7 @@ void DSPEmitter::bloop(const UDSPInstruction opc)
|
|||||||
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size));
|
MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size));
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(*this);
|
||||||
SetJumpTarget(exit);
|
SetJumpTarget(exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,5 +674,6 @@ void DSPEmitter::bloopi(const UDSPInstruction opc)
|
|||||||
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
|
||||||
MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size));
|
MOV(16, MatR(RAX), Imm16(loop_pc + opTable[loop_pc]->size));
|
||||||
#endif
|
#endif
|
||||||
|
WriteBranchExit(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user