LLE JIT: Changed the ASM dispatcher so that it jumps to the blocks instead of calling them. This removes the need to push and pop all of the registers at each block, speeding up the JIT. Changed the cycle counting to work off memory accesses instead of a register. Removed the C++ JIT dispatcher because it will no longer work with this new format.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6858 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
2cb5a1aa56
commit
7e9f02869a
|
@ -241,19 +241,14 @@ int DSPCore_RunCycles(int cycles)
|
||||||
{
|
{
|
||||||
if (jit)
|
if (jit)
|
||||||
{
|
{
|
||||||
// DSPCore_CheckExceptions();
|
|
||||||
// DSPCore_CheckExternalInterrupt();
|
|
||||||
cyclesLeft = cycles;
|
cyclesLeft = cycles;
|
||||||
|
|
||||||
CompiledCode pExecAddr = (CompiledCode)jit->enterDispatcher;
|
CompiledCode pExecAddr = (CompiledCode)jit->enterDispatcher;
|
||||||
pExecAddr();
|
pExecAddr();
|
||||||
|
|
||||||
// To use the C++ dispatcher, uncomment the line below and comment out the two lines above
|
|
||||||
//jit->RunForCycles(cyclesLeft);
|
|
||||||
return cyclesLeft;
|
return cyclesLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cycles > 0) {
|
while (cycles > 0)
|
||||||
|
{
|
||||||
reswitch:
|
reswitch:
|
||||||
switch (core_state)
|
switch (core_state)
|
||||||
{
|
{
|
||||||
|
|
|
@ -96,15 +96,10 @@ void DSPEmitter::checkExceptions(u32 retval)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DSPJitRegCache c(gpr);
|
DSPJitRegCache c(gpr);
|
||||||
|
|
||||||
SaveDSPRegs();
|
SaveDSPRegs();
|
||||||
ABI_CallFunction((void *)&DSPCore_CheckExceptions);
|
ABI_CallFunction((void *)&DSPCore_CheckExceptions);
|
||||||
|
|
||||||
// ABI_RestoreStack(0);
|
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
MOV(32, R(EAX), Imm32(retval));
|
MOV(32, R(EAX), Imm32(retval));
|
||||||
RET();
|
JMP(returnDispatcher, true);
|
||||||
|
|
||||||
gpr.flushRegs(c,false);
|
gpr.flushRegs(c,false);
|
||||||
|
|
||||||
SetJumpTarget(skipCheck);
|
SetJumpTarget(skipCheck);
|
||||||
|
@ -201,8 +196,6 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
unresolvedJumps[start_addr].clear();
|
unresolvedJumps[start_addr].clear();
|
||||||
|
|
||||||
const u8 *entryPoint = AlignCode16();
|
const u8 *entryPoint = AlignCode16();
|
||||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
// ABI_AlignStack(0);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Check for other exceptions
|
// Check for other exceptions
|
||||||
|
@ -276,7 +269,6 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
DSPJitRegCache c(gpr);
|
DSPJitRegCache c(gpr);
|
||||||
HandleLoop();
|
HandleLoop();
|
||||||
SaveDSPRegs();
|
SaveDSPRegs();
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
|
@ -285,7 +277,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
JMP(returnDispatcher, true);
|
||||||
gpr.flushRegs(c,false);
|
gpr.flushRegs(c,false);
|
||||||
|
|
||||||
SetJumpTarget(rLoopAddressExit);
|
SetJumpTarget(rLoopAddressExit);
|
||||||
|
@ -315,7 +307,6 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
DSPJitRegCache c(gpr);
|
DSPJitRegCache c(gpr);
|
||||||
//don't update g_dsp.pc -- the branch insn already did
|
//don't update g_dsp.pc -- the branch insn already did
|
||||||
SaveDSPRegs();
|
SaveDSPRegs();
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
|
@ -324,7 +315,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
JMP(returnDispatcher, true);
|
||||||
gpr.flushRegs(c,false);
|
gpr.flushRegs(c,false);
|
||||||
|
|
||||||
SetJumpTarget(rNoBranch);
|
SetJumpTarget(rNoBranch);
|
||||||
|
@ -382,8 +373,6 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveDSPRegs();
|
SaveDSPRegs();
|
||||||
|
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
|
@ -392,18 +381,16 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
MOV(16, R(EAX), Imm16(blockSize[start_addr]));
|
||||||
}
|
}
|
||||||
RET();
|
JMP(returnDispatcher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *DSPEmitter::CompileStub()
|
const u8 *DSPEmitter::CompileStub()
|
||||||
{
|
{
|
||||||
const u8 *entryPoint = AlignCode16();
|
const u8 *entryPoint = AlignCode16();
|
||||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
ABI_CallFunction((void *)&CompileCurrent);
|
ABI_CallFunction((void *)&CompileCurrent);
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
//MOVZX(32, 16, ECX, M(&g_dsp.pc));
|
//MOVZX(32, 16, ECX, M(&g_dsp.pc));
|
||||||
XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed
|
XOR(32, R(EAX), R(EAX)); // Return 0 cycles executed
|
||||||
RET();
|
JMP(returnDispatcher);
|
||||||
return entryPoint;
|
return entryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,18 +399,6 @@ void DSPEmitter::CompileDispatcher()
|
||||||
enterDispatcher = AlignCode16();
|
enterDispatcher = AlignCode16();
|
||||||
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
ABI_PushAllCalleeSavedRegsAndAdjustStack();
|
||||||
|
|
||||||
// Cache pointers into registers
|
|
||||||
#ifdef _M_IX86
|
|
||||||
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(16, R(R12), MatR(R12));
|
|
||||||
MOV(64, R(RBX), ImmPtr(blocks));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const u8 *dispatcherLoop = GetCodePtr();
|
const u8 *dispatcherLoop = GetCodePtr();
|
||||||
|
|
||||||
// Check for DSP halt
|
// Check for DSP halt
|
||||||
|
@ -444,16 +419,21 @@ void DSPEmitter::CompileDispatcher()
|
||||||
|
|
||||||
// Execute block. Cycles executed returned in EAX.
|
// Execute block. Cycles executed returned in EAX.
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
CALLptr(MComplex(EBX, ECX, SCALE_4, 0));
|
MOV(32, R(EBX), ImmPtr(blocks));
|
||||||
|
JMPptr(MComplex(EBX, ECX, SCALE_4, 0));
|
||||||
#else
|
#else
|
||||||
CALLptr(MComplex(RBX, RCX, SCALE_8, 0));
|
MOV(64, R(RBX), ImmPtr(blocks));
|
||||||
|
JMPptr(MComplex(RBX, RCX, SCALE_8, 0));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
returnDispatcher = GetCodePtr();
|
||||||
|
|
||||||
// Decrement cyclesLeft
|
// Decrement cyclesLeft
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
SUB(16, R(ESI), R(EAX));
|
SUB(16, M(&cyclesLeft), R(EAX));
|
||||||
#else
|
#else
|
||||||
SUB(16, R(R12), R(EAX));
|
MOV(64, R(R12), ImmPtr(&cyclesLeft));
|
||||||
|
SUB(16, MatR(R12), R(EAX));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
J_CC(CC_A, dispatcherLoop);
|
J_CC(CC_A, dispatcherLoop);
|
||||||
|
@ -464,35 +444,3 @@ void DSPEmitter::CompileDispatcher()
|
||||||
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
||||||
RET();
|
RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't use the % operator in the inner loop. It's slow.
|
|
||||||
int STACKALIGN DSPEmitter::RunForCycles(int cycles)
|
|
||||||
{
|
|
||||||
while (!(g_dsp.cr & CR_HALT))
|
|
||||||
{
|
|
||||||
// Compile the block if needed
|
|
||||||
u16 block_addr = g_dsp.pc;
|
|
||||||
int block_size = blockSize[block_addr];
|
|
||||||
if (!block_size)
|
|
||||||
{
|
|
||||||
CompileCurrent();
|
|
||||||
block_size = blockSize[block_addr];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the block if we have enough cycles
|
|
||||||
if (cycles > block_size)
|
|
||||||
{
|
|
||||||
cycles -= blocks[block_addr]();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DSP gave up the remaining cycles.
|
|
||||||
if (g_dsp.cr & CR_HALT || cycles < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return cycles;
|
|
||||||
}
|
|
||||||
|
|
|
@ -50,8 +50,6 @@ public:
|
||||||
|
|
||||||
void Default(UDSPInstruction inst);
|
void Default(UDSPInstruction inst);
|
||||||
|
|
||||||
int STACKALIGN RunForCycles(int cycles);
|
|
||||||
|
|
||||||
// CC Util
|
// CC Util
|
||||||
void Update_SR_Register64(Gen::X64Reg val = Gen::EAX);
|
void Update_SR_Register64(Gen::X64Reg val = Gen::EAX);
|
||||||
void Update_SR_Register64_Carry(Gen::X64Reg val = Gen::EAX);
|
void Update_SR_Register64_Carry(Gen::X64Reg val = Gen::EAX);
|
||||||
|
@ -253,6 +251,7 @@ public:
|
||||||
// CALL this to start the dispatcher
|
// CALL this to start the dispatcher
|
||||||
const u8 *enterDispatcher;
|
const u8 *enterDispatcher;
|
||||||
const u8 *stubEntryPoint;
|
const u8 *stubEntryPoint;
|
||||||
|
const u8 *returnDispatcher;
|
||||||
u16 compilePC;
|
u16 compilePC;
|
||||||
u16 startAddr;
|
u16 startAddr;
|
||||||
Block *blockLinks;
|
Block *blockLinks;
|
||||||
|
|
|
@ -122,7 +122,6 @@ static void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
|
||||||
static void WriteBranchExit(DSPEmitter& emitter)
|
static void WriteBranchExit(DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
emitter.SaveDSPRegs();
|
emitter.SaveDSPRegs();
|
||||||
emitter.ABI_PopAllCalleeSavedRegsAndAdjustStack();
|
|
||||||
if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
if (DSPAnalyzer::code_flags[emitter.startAddr] & DSPAnalyzer::CODE_IDLE_SKIP)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(EAX), Imm16(0x1000));
|
emitter.MOV(16, R(EAX), Imm16(0x1000));
|
||||||
|
@ -131,7 +130,7 @@ static void WriteBranchExit(DSPEmitter& emitter)
|
||||||
{
|
{
|
||||||
emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr]));
|
emitter.MOV(16, R(EAX), Imm16(emitter.blockSize[emitter.startAddr]));
|
||||||
}
|
}
|
||||||
emitter.RET();
|
emitter.JMP(emitter.returnDispatcher, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
|
static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
|
||||||
|
@ -152,10 +151,11 @@ static void WriteBlockLink(DSPEmitter& emitter, u16 dest)
|
||||||
emitter.MOV(16, M(&cyclesLeft), R(ESI));
|
emitter.MOV(16, M(&cyclesLeft), R(ESI));
|
||||||
#else
|
#else
|
||||||
// Check if we have enough cycles to execute the next block
|
// Check if we have enough cycles to execute the next block
|
||||||
emitter.CMP(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest]));
|
emitter.MOV(64, R(R12), ImmPtr(&cyclesLeft));
|
||||||
|
emitter.CMP(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr] + emitter.blockSize[dest]));
|
||||||
FixupBranch notEnoughCycles = emitter.J_CC(CC_BE);
|
FixupBranch notEnoughCycles = emitter.J_CC(CC_BE);
|
||||||
|
|
||||||
emitter.SUB(16, R(R12), Imm16(emitter.blockSize[emitter.startAddr]));
|
emitter.SUB(16, MatR(R12), Imm16(emitter.blockSize[emitter.startAddr]));
|
||||||
#endif
|
#endif
|
||||||
emitter.JMP(emitter.blockLinks[dest], true);
|
emitter.JMP(emitter.blockLinks[dest], true);
|
||||||
emitter.SetJumpTarget(notEnoughCycles);
|
emitter.SetJumpTarget(notEnoughCycles);
|
||||||
|
|
Loading…
Reference in New Issue