* 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

@ -386,7 +386,7 @@ void DSPEmitter::addr(const UDSPInstruction opc)
get_long_acc(dreg);
PUSH(64, R(RAX));
// s64 ax = (s16)g_dsp.r[sreg];
MOV(16, R(RDX), MDisp(R11, sreg * 2));
MOVSX(64, 16, RDX, MDisp(R11, sreg * 2));
// ax <<= 16;
SHL(64, R(RDX), Imm8(16));
// s64 res = acc + ax;
@ -414,7 +414,7 @@ void DSPEmitter::addr(const UDSPInstruction opc)
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::addr, opc);
MainOpFallback(opc);
#endif
}
@ -821,7 +821,7 @@ void DSPEmitter::lsl16(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(areg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::lsl16, opc);
MainOpFallback(opc);
#endif
}
@ -883,7 +883,7 @@ void DSPEmitter::lsl(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::lsl, opc);
MainOpFallback(opc);
#endif
}

View File

@ -0,0 +1,238 @@
// Copyright (C) 2010 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "../DSPMemoryMap.h"
#include "../DSPEmitter.h"
#include "../DSPStacks.h"
#include "x64Emitter.h"
#include "ABI.h"
using namespace Gen;
const int GetCodeSize(void(*jitCode)(const UDSPInstruction, DSPEmitter&), const UDSPInstruction opc, DSPEmitter &emitter)
{
u16 pc = g_dsp.pc;
const u8* ptr = emitter.GetCodePtr();
jitCode(opc, emitter);
//emitter.JMP(emitter.GetCodePtr());
int size = (int)(emitter.GetCodePtr() - ptr);
emitter.SetCodePtr((u8*)ptr);
g_dsp.pc = pc;
return size;
}
template <void(*jitCode)(const UDSPInstruction, DSPEmitter&)>
void ReJitConditional(const UDSPInstruction opc, DSPEmitter& emitter)
{
static const int codeSize = GetCodeSize(jitCode, opc, emitter);
//emitter.INT3();
const u8* codePtr = CheckCondition(emitter, opc & 0xf, codeSize);
const u8* afterSkip = emitter.GetCodePtr();
if (codePtr != NULL)
emitter.SetCodePtr((u8*)codePtr);
jitCode(opc, emitter);
//if (codePtr != NULL)
//{
// emitter.JMP(afterSkip + 4 + sizeof(void*));
// emitter.SetCodePtr((u8*)afterSkip);
// emitter.ADD(16, M(&g_dsp.pc), Imm8(1)); //4 bytes + pointer
//}
}
const u8* CheckCondition(DSPEmitter& emitter, u8 cond, u8 skipCodeSize)
{
if (cond == 0xf) // Always true.
return NULL;
//emitter.INT3();
FixupBranch skipCode2;
emitter.MOV(16, R(EAX), M(&g_dsp.r[DSP_REG_SR]));
switch(cond)
{
case 0x0: // GE - Greater Equal
case 0x1: // L - Less
case 0x2: // G - Greater
case 0x3: // LE - Less Equal
emitter.MOV(16, R(EDX), R(EAX));
emitter.SHR(16, R(EDX), Imm8(3)); //SR_SIGN flag
emitter.NOT(16, R(EDX));
emitter.SHR(16, R(EAX), Imm8(1)); //SR_OVERFLOW flag
emitter.NOT(16, R(EAX));
emitter.XOR(16, R(EAX), R(EDX));
emitter.TEST(16, R(EAX), Imm16(1));
if (cond < 0x2)
break;
//LE: problem in here, half the tests fail
skipCode2 = emitter.J_CC(CC_NE);
//skipCode2 = emitter.J_CC((CCFlags)(CC_NE - (cond & 1)));
emitter.MOV(16, R(EAX), M(&g_dsp.r[DSP_REG_SR]));
emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
break;
case 0x4: // NZ - Not Zero
case 0x5: // Z - Zero
emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
break;
case 0x6: // NC - Not carry
case 0x7: // C - Carry
emitter.TEST(16, R(EAX), Imm16(SR_CARRY));
break;
case 0x8: // ? - Not over s32
case 0x9: // ? - Over s32
emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32));
break;
case 0xa: // ?
case 0xb: // ?
{
//full of fail, both
emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS));
FixupBranch skipArithZero = emitter.J_CC(CC_E);
emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
FixupBranch setZero = emitter.J_CC(CC_NE);
emitter.MOV(16, R(EAX), Imm16(1));
FixupBranch toEnd = emitter.J();
emitter.SetJumpTarget(skipArithZero);
emitter.SetJumpTarget(setZero);
emitter.XOR(16, R(EAX), R(EAX));
emitter.SetJumpTarget(toEnd);
emitter.SETcc(CC_E, R(EAX));
emitter.TEST(8, R(EAX), R(EAX));
break;
//emitter.TEST(16, R(EAX), Imm16(SR_OVER_S32 | SR_TOP2BITS));
//skipCode2 = emitter.J_CC((CCFlags)(CC_E + (cond & 1)));
//emitter.TEST(16, R(EAX), Imm16(SR_ARITH_ZERO));
//break;
}
case 0xc: // LNZ - Logic Not Zero
case 0xd: // LZ - Logic Zero
emitter.TEST(16, R(EAX), Imm16(SR_LOGIC_ZERO));
break;
case 0xe: // 0 - Overflow
emitter.TEST(16, R(EAX), Imm16(SR_OVERFLOW));
break;
}
FixupBranch skipCode = cond == 0xe ? emitter.J_CC(CC_E) : emitter.J_CC((CCFlags)(CC_NE - (cond & 1)));
const u8* res = emitter.GetCodePtr();
emitter.NOP(skipCodeSize);
emitter.SetJumpTarget(skipCode);
if ((cond | 1) == 0x3) // || (cond | 1) == 0xb)
emitter.SetJumpTarget(skipCode2);
return res;
}
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));
#else
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
emitter.MOV(16, MDisp(RAX,0), Imm16(dest));
#endif
}
// Generic jmp implementation
// Jcc addressA
// 0000 0010 1001 cccc
// 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.
void DSPEmitter::jcc(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, MDisp(RAX,0), Imm16(compilePC + 1));
#endif
ReJitConditional<r_jcc>(opc, *this);
}
void r_jmprcc(const UDSPInstruction opc, DSPEmitter& emitter)
{
u8 reg = (opc >> 5) & 0x7;
//reg can only be DSP_REG_ARx and DSP_REG_IXx now,
//no need to handle DSP_REG_STx.
#ifdef _M_IX86 // All32
emitter.MOV(16, R(EAX), M(&g_dsp.r[reg]));
emitter.MOV(16, M(&g_dsp.pc), R(EAX));
#else
emitter.MOV(16, R(RSI), M(&g_dsp.r[reg]));
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
emitter.MOV(16, MDisp(RAX,0), R(RSI));
#endif
}
// Generic jmpr implementation
// JMPcc $R
// 0001 0111 rrr0 cccc
// Jump to address; set program counter to a value from register $R.
void DSPEmitter::jmprcc(const UDSPInstruction opc)
{
ReJitConditional<r_jmprcc>(opc, *this);
}
void r_call(const UDSPInstruction opc, DSPEmitter& emitter)
{
u16 dest = dsp_imem_read(emitter.compilePC + 1);
emitter.ABI_CallFunctionCC16(dsp_reg_store_stack, DSP_STACK_C, emitter.compilePC + 2);
#ifdef _M_IX86 // All32
emitter.MOV(16, M(&(g_dsp.pc)), Imm16(dest));
#else
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
emitter.MOV(16, MDisp(RAX,0), Imm16(dest));
#endif
}
// Generic call implementation
// CALLcc addressA
// 0000 0010 1011 cccc
// aaaa aaaa aaaa aaaa
// 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.
void DSPEmitter::call(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, MDisp(RAX,0), Imm16(compilePC + 1));
#endif
ReJitConditional<r_call>(opc, *this);
}
void r_callr(const UDSPInstruction opc, DSPEmitter& emitter)
{
u8 reg = (opc >> 5) & 0x7;
emitter.ABI_CallFunctionCC16(dsp_reg_store_stack, DSP_STACK_C, emitter.compilePC + 1);
#ifdef _M_IX86 // All32
emitter.MOV(16, R(EAX), M(&g_dsp.r[reg]));
emitter.MOV(16, M(&g_dsp.pc), R(EAX));
#else
emitter.MOV(16, R(RSI), M(&g_dsp.r[reg]));
emitter.MOV(64, R(RAX), ImmPtr(&(g_dsp.pc)));
emitter.MOV(16, MDisp(RAX,0), R(RSI));
#endif
}
// Generic callr implementation
// CALLRcc $R
// 0001 0111 rrr1 cccc
// 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.
void DSPEmitter::callr(const UDSPInstruction opc)
{
ReJitConditional<r_callr>(opc, *this);
}

View File

@ -321,12 +321,10 @@ void DSPEmitter::mrr(const UDSPInstruction opc)
dsp_conditional_extend_accum(dreg);
}
#if 0
// LRI $D, #I
// 0000 0000 100d dddd
// iiii iiii iiii iiii
// Load immediate value I to register $D.
// FIXME: Perform additional operation depending on destination register.
// Load immediate value I to register $D.
//
// DSPSpy discovery: This, and possibly other instructions that load a
// register, has a different behaviour in S40 mode if loaded to AC0.M: The
@ -335,11 +333,10 @@ void DSPEmitter::mrr(const UDSPInstruction opc)
void DSPEmitter::lri(const UDSPInstruction opc)
{
u8 reg = opc & DSP_REG_MASK;
u16 imm = dsp_fetch_code();
dsp_op_write_reg(reg, imm);
dsp_conditional_extend_accum(reg);
u16 imm = dsp_imem_read(compilePC+1);
dsp_op_write_reg_imm(reg, imm);
dsp_conditional_extend_accum_imm(reg, imm);
}
#endif
// LRIS $(0x18+D), #I
// 0000 1ddd iiii iiii

View File

@ -154,7 +154,7 @@ void DSPEmitter::clrp(const UDSPInstruction opc)
// g_dsp.r[DSP_REG_PRODM2] = 0x0010;
MOV(16, MDisp(R11, DSP_REG_PRODM2 * 2), Imm16(0x0010));
#else
ABI_CallFunctionC((void *)&DSPInterpreter::clrp, opc);
MainOpFallback(opc);
#endif
}
@ -171,7 +171,7 @@ void DSPEmitter::tstprod(const UDSPInstruction opc)
// Update_SR_Register64(prod);
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::tstprod, opc);
MainOpFallback(opc);
#endif
}
@ -194,7 +194,7 @@ void DSPEmitter::movp(const UDSPInstruction opc)
// Update_SR_Register64(acc);
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::movp, opc);
MainOpFallback(opc);
#endif
}
@ -217,7 +217,7 @@ void DSPEmitter::movnp(const UDSPInstruction opc)
// Update_SR_Register64(acc);
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::movnp, opc);
MainOpFallback(opc);
#endif
}
@ -239,7 +239,7 @@ void DSPEmitter::movpz(const UDSPInstruction opc)
// Update_SR_Register64(acc);
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::movpz, opc);
MainOpFallback(opc);
#endif
}
@ -282,7 +282,7 @@ void DSPEmitter::mulaxh(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulaxh, opc);
MainOpFallback(opc);
#endif
}
@ -307,7 +307,7 @@ void DSPEmitter::mul(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mul, opc);
MainOpFallback(opc);
#endif
}
@ -344,7 +344,7 @@ void DSPEmitter::mulac(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulac, opc);
MainOpFallback(opc);
#endif
}
@ -370,7 +370,7 @@ void DSPEmitter::mulmv(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulmv, opc);
MainOpFallback(opc);
#endif
}
@ -397,7 +397,7 @@ void DSPEmitter::mulmvz(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulmvz, opc);
MainOpFallback(opc);
#endif
}
@ -519,7 +519,7 @@ void DSPEmitter::mulc(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulc, opc);
MainOpFallback(opc);
#endif
}
@ -557,7 +557,7 @@ void DSPEmitter::mulcac(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulcac, opc);
MainOpFallback(opc);
#endif
}
@ -593,7 +593,7 @@ void DSPEmitter::mulcmv(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulcmv, opc);
MainOpFallback(opc);
#endif
}
@ -631,7 +631,7 @@ void DSPEmitter::mulcmvz(const UDSPInstruction opc)
// Update_SR_Register64(dsp_get_long_acc(rreg));
Update_SR_Register64();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::mulcmvz, opc);
MainOpFallback(opc);
#endif
}
@ -696,7 +696,7 @@ void DSPEmitter::maddc(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::maddc, opc);
MainOpFallback(opc);
#endif
}
@ -721,7 +721,7 @@ void DSPEmitter::msubc(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::msubc, opc);
MainOpFallback(opc);
#endif
}
@ -745,7 +745,7 @@ void DSPEmitter::madd(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::madd, opc);
MainOpFallback(opc);
#endif
}
@ -769,6 +769,6 @@ void DSPEmitter::msub(const UDSPInstruction opc)
// dsp_set_long_prod(prod);
set_long_prod();
#else
ABI_CallFunctionC((void *)&DSPInterpreter::msub, opc);
MainOpFallback(opc);
#endif
}