* Optimised the updating of g_dsp.pc in the compile loop (code by kiesel-stein)
* Added JIT version of LRI (code by kiesel-stein)
* Added JIT versions of the branch instructions (code by Jack Frost)
* DSP_SendAIBuffer fix (code by Mylek)
* Marked instructions that update g_dsp.pc in the DSP table and updated PC based on the table (speed up)
* Fixed the signed bits not being set properly in the addr instruction
* Created a MainOpFallback function to use interpreted versions of the instructions if necessary (code by kiesel-stein)
* Disabled the jit versions of subarn and addarn as they are slowing down NSMBW

The above work in both x86 and x64 modes.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6582 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau
2010-12-15 01:42:32 +00:00
parent 76d9209ad4
commit f67afb4fca
14 changed files with 599 additions and 290 deletions

View File

@ -73,7 +73,8 @@ void DSPEmitter::ClearIRAM() {
}
// Must go out of block if exception is detected
void DSPEmitter::checkExceptions(u32 retval) {
void DSPEmitter::checkExceptions(u32 retval)
{
// Check for interrupts and exceptions
#ifdef _M_IX86 // All32
TEST(8, M(&g_dsp.exceptions), Imm8(0xff));
@ -82,17 +83,43 @@ void DSPEmitter::checkExceptions(u32 retval) {
TEST(8, MDisp(RAX,0), Imm8(0xff));
#endif
FixupBranch skipCheck = J_CC(CC_Z);
#ifdef _M_IX86 // All32
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC));
#else
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
MOV(16, MDisp(RAX,0), Imm16(compilePC));
#endif
ABI_CallFunction((void *)&DSPCore_CheckExceptions);
// ABI_RestoreStack(0);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
MOV(32,R(EAX),Imm32(retval));
RET();
SetJumpTarget(skipCheck);
}
void DSPEmitter::MainOpFallback(UDSPInstruction inst)
{
if (opTable[inst]->reads_pc)
{
// Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block.
// Fallbacks to interpreter need this for fetching immediate values
#ifdef _M_IX86 // All32
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC + 1));
#else
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
MOV(16, MDisp(RAX,0), Imm16(compilePC + 1));
#endif
}
// Fall back to interpreter
ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst);
}
void DSPEmitter::EmitInstruction(UDSPInstruction inst)
{
const DSPOPCTemplate *tinst = GetOpTemplate(inst);
@ -123,8 +150,7 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst)
// Main instruction
if (!opTable[inst]->jitFunc) {
// Fall back to interpreter
ABI_CallFunctionC16((void*)opTable[inst]->intFunc, inst);
MainOpFallback(inst);
}
else
{
@ -178,32 +204,27 @@ void DSPEmitter::Compile(int start_addr)
*/
ABI_CallFunction((void *)&DSPCore_CheckExternalInterrupt);
int addr = start_addr;
compilePC = start_addr;
bool fixup_pc = false;
blockSize[start_addr] = 0;
while (addr < start_addr + MAX_BLOCK_SIZE)
while (compilePC < start_addr + MAX_BLOCK_SIZE)
{
checkExceptions(blockSize[start_addr]);
UDSPInstruction inst = dsp_imem_read(addr);
UDSPInstruction inst = dsp_imem_read(compilePC);
const DSPOPCTemplate *opcode = GetOpTemplate(inst);
// Increment PC - we shouldn't need to do this for every instruction. only for branches and end of block.
// Fallbacks to interpreter need this for fetching immediate values
#ifdef _M_IX86 // All32
ADD(16, M(&(g_dsp.pc)), Imm16(1));
#else
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
ADD(16, MDisp(RAX,0), Imm16(1));
#endif
EmitInstruction(inst);
blockSize[start_addr]++;
addr += opcode->size;
compilePC += opcode->size;
fixup_pc = true;
// Handle loop condition, only if current instruction was flagged as a loop destination
// by the analyzer.
if (DSPAnalyzer::code_flags[addr-1] & DSPAnalyzer::CODE_LOOP_END)
if (DSPAnalyzer::code_flags[compilePC-1] & DSPAnalyzer::CODE_LOOP_END)
{
#ifdef _M_IX86 // All32
MOVZX(32, 16, EAX, M(&(g_dsp.r[DSP_REG_ST2])));
@ -222,6 +243,17 @@ void DSPEmitter::Compile(int start_addr)
CMP(32, R(EAX), Imm32(0));
FixupBranch rLoopCounterExit = J_CC(CC_LE);
if (!opcode->branch)
{
//branch insns update the g_dsp.pc
#ifdef _M_IX86 // All32
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC));
#else
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
MOV(16, MDisp(RAX,0), Imm16(compilePC));
#endif
}
// These functions branch and therefore only need to be called in the
// end of each block and in this order
ABI_CallFunction((void *)&DSPInterpreter::HandleLoop);
@ -243,6 +275,8 @@ void DSPEmitter::Compile(int start_addr)
if (opcode->branch)
{
//don't update g_dsp.pc -- the branch insn already did
fixup_pc = false;
if (opcode->uncond_branch)
{
break;
@ -256,9 +290,10 @@ void DSPEmitter::Compile(int start_addr)
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
MOV(16, R(AX), MDisp(RAX,0));
#endif
CMP(16, R(AX), Imm16(addr));
CMP(16, R(AX), Imm16(compilePC));
FixupBranch rNoBranch = J_CC(CC_Z);
//don't update g_dsp.pc -- the branch insn already did
// ABI_RestoreStack(0);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
if (DSPAnalyzer::code_flags[start_addr] & DSPAnalyzer::CODE_IDLE_SKIP)
@ -276,12 +311,21 @@ void DSPEmitter::Compile(int start_addr)
}
// End the block if we're before an idle skip address
if (DSPAnalyzer::code_flags[addr] & DSPAnalyzer::CODE_IDLE_SKIP)
if (DSPAnalyzer::code_flags[compilePC] & DSPAnalyzer::CODE_IDLE_SKIP)
{
break;
}
}
if (fixup_pc) {
#ifdef _M_IX86 // All32
MOV(16, M(&(g_dsp.pc)), Imm16(compilePC));
#else
MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
MOV(16, MDisp(RAX,0), Imm16(compilePC));
#endif
}
blocks[start_addr] = (CompiledCode)entryPoint;
if (blockSize[start_addr] == 0)
{