Fix 32-bit lmw/stmw (well, disable). Merge the two dispatchers.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1606 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-12-20 12:46:14 +00:00
parent 614dc1069e
commit 66853d6f1b
8 changed files with 86 additions and 136 deletions

View File

@ -7,8 +7,9 @@ class DebugInterface
{ {
protected: protected:
virtual ~DebugInterface() {} virtual ~DebugInterface() {}
public: public:
virtual void disasm(unsigned int /*address*/, char *dest, int max_size) {strcpy(dest, "NODEBUGGER");} virtual void disasm(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
virtual void getRawMemoryString(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");} virtual void getRawMemoryString(unsigned int /*address*/, char *dest, int /*max_size*/) {strcpy(dest, "NODEBUGGER");}
virtual int getInstructionSize(int /*instruction*/) {return 1;} virtual int getInstructionSize(int /*instruction*/) {return 1;}

View File

@ -255,6 +255,15 @@ namespace CPUCompare
// Yup, just don't do anything. // Yup, just don't do anything.
} }
void Jit64::NotifyBreakpoint(u32 em_address, bool set)
{
int block_num = blocks.GetBlockNumberFromStartAddress(em_address);
if (block_num >= 0)
{
blocks.DestroyBlock(block_num, false);
}
}
static const bool ImHereDebug = false; static const bool ImHereDebug = false;
static const bool ImHereLog = false; static const bool ImHereLog = false;
static std::map<u32, int> been_here; static std::map<u32, int> been_here;
@ -300,7 +309,7 @@ namespace CPUCompare
b->exitPtrs[exit_num] = GetWritableCodePtr(); b->exitPtrs[exit_num] = GetWritableCodePtr();
// Link opportunity! // Link opportunity!
int block = blocks.GetBlockNumberFromAddress(destination); int block = blocks.GetBlockNumberFromStartAddress(destination);
if (block >= 0 && jo.enableBlocklink) if (block >= 0 && jo.enableBlocklink)
{ {
// It exists! Joy of joy! // It exists! Joy of joy!
@ -353,17 +362,17 @@ namespace CPUCompare
return blocks.Jit(em_address); return blocks.Jit(em_address);
} }
const u8* Jit64::DoJit(u32 emaddress, JitBlock &b) const u8* Jit64::DoJit(u32 em_address, JitBlock &b)
{ {
if (emaddress == 0) if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
// if (emaddress == 0x800aa278) // if (em_address == 0x800aa278)
// DebugBreak(); // DebugBreak();
int size; int size;
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = emaddress; js.blockStart = em_address;
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
js.curBlock = &b; js.curBlock = &b;
js.blockSetsQuantizers = false; js.blockSetsQuantizers = false;
@ -373,7 +382,7 @@ namespace CPUCompare
//Analyze the block, collect all instructions it is made of (including inlining, //Analyze the block, collect all instructions it is made of (including inlining,
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions. //if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
PPCAnalyst::Flatten(emaddress, &size, &js.st, &js.gpa, &js.fpa, &code_buffer); PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, &code_buffer);
PPCAnalyst::CodeOp *ops = code_buffer.codebuffer; PPCAnalyst::CodeOp *ops = code_buffer.codebuffer;
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
@ -430,7 +439,7 @@ namespace CPUCompare
gpr.Start(js.gpa); gpr.Start(js.gpa);
fpr.Start(js.fpa); fpr.Start(js.fpa);
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(emaddress); js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
js.blockSize = size; js.blockSize = size;
// Translate instructions // Translate instructions
for (int i = 0; i < (int)size; i++) for (int i = 0; i < (int)size; i++)

View File

@ -128,11 +128,13 @@ public:
// Jit! // Jit!
const u8 *Jit(u32 emAddress); // calls blocks.Jit, which in turn calls DoJit below after setting up a block. const u8 *Jit(u32 em_address); // calls blocks.Jit, which in turn calls DoJit below after setting up a block.
const u8* DoJit(u32 emaddress, JitBlock &b); const u8* DoJit(u32 em_address, JitBlock &b);
JitBlockCache *GetBlockCache() { return &blocks; } JitBlockCache *GetBlockCache() { return &blocks; }
void NotifyBreakpoint(u32 em_address, bool set);
void ClearCache() void ClearCache()
{ {
blocks.Clear(); blocks.Clear();
@ -142,7 +144,7 @@ public:
// Run! // Run!
void EnterFastRun(); void EnterFastRun();
const u8 *BackPatch(u8 *codePtr, int accessType, u32 emAddress, CONTEXT *ctx); const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, CONTEXT *ctx);
#define JIT_OPCODE 0 #define JIT_OPCODE 0
@ -274,7 +276,7 @@ public:
extern Jit64 jit; extern Jit64 jit;
const u8 *Jit(u32 emaddress); const u8 *Jit(u32 em_address);
#endif #endif

View File

@ -64,16 +64,21 @@ AsmRoutineManager asm_routines;
// At this offset - 4, there is an int specifying the block number. // At this offset - 4, there is an int specifying the block number.
#ifdef _M_IX86
void AsmRoutineManager::Generate() void AsmRoutineManager::Generate()
{ {
enterCode = AlignCode16(); enterCode = AlignCode16();
#ifdef _M_IX86
PUSH(EBP); PUSH(EBP);
PUSH(EBX); PUSH(EBX);
PUSH(ESI); PUSH(ESI);
PUSH(EDI); PUSH(EDI);
#else
ABI_PushAllCalleeSavedRegsAndAdjustStack();
// Two statically allocated registers.
MOV(64, R(RBX), Imm64((u64)Memory::base));
MOV(64, R(R15), Imm64((u64)jit.GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough
#endif
//MOV(32, R(EBX), Imm32((u32)&Memory::base));
const u8 *outerLoop = GetCodePtr(); const u8 *outerLoop = GetCodePtr();
CALL(reinterpret_cast<void *>(&CoreTiming::Advance)); CALL(reinterpret_cast<void *>(&CoreTiming::Advance));
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
@ -84,22 +89,18 @@ void AsmRoutineManager::Generate()
//The result of slice decrementation should be in flags if somebody jumped here //The result of slice decrementation should be in flags if somebody jumped here
//Jump on negative, not carry!!! //Jump on negative, not carry!!!
FixupBranch bail = J_CC(CC_BE); FixupBranch bail = J_CC(CC_BE);
if (Core::bReadTrace || Core::bWriteTrace)
{
CALL(reinterpret_cast<void *>(&Core::SyncTrace));
// CMP(32, R(EAX),Imm32(0));
// bail2 = J_CC();
}
SetJumpTarget(skipToRealDispatch); SetJumpTarget(skipToRealDispatch);
//TEST(32,M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
//FixupBranch bail2 = J_CC(CC_NZ);
dispatcherNoCheck = GetCodePtr(); dispatcherNoCheck = GetCodePtr();
MOV(32, R(EAX), M(&PowerPC::ppcState.pc)); MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
dispatcherPcInEAX = GetCodePtr(); dispatcherPcInEAX = GetCodePtr();
#ifdef _M_IX86
AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK));
MOV(32, R(EBX), Imm32((u32)Memory::base)); MOV(32, R(EBX), Imm32((u32)Memory::base));
MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0)); MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0));
#else
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
#endif
TEST(32, R(EAX), Imm32(0xFC)); TEST(32, R(EAX), Imm32(0xFC));
FixupBranch notfound = J_CC(CC_NZ); FixupBranch notfound = J_CC(CC_NZ);
BSWAP(32, EAX); BSWAP(32, EAX);
@ -113,15 +114,24 @@ void AsmRoutineManager::Generate()
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1)); ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
} }
//grab from list and jump to it //grab from list and jump to it
MOV(32, R(EDX), ImmPtr(jit.GetCodePointers())); #ifdef _M_IX86
MOV(32, R(EDX), ImmPtr(jit.GetBlockCache()->GetCodePointers()));
JMPptr(MComplex(EDX, EAX, 4, 0)); JMPptr(MComplex(EDX, EAX, 4, 0));
#else
JMPptr(MComplex(R15, RAX, 8, 0));
#endif
SetJumpTarget(notfound); SetJumpTarget(notfound);
//Ok, no block, let's jit //Ok, no block, let's jit
#ifdef _M_IX86
ABI_AlignStack(4); ABI_AlignStack(4);
PUSH(32, M(&PowerPC::ppcState.pc)); PUSH(32, M(&PowerPC::ppcState.pc));
CALL(reinterpret_cast<void *>(&Jit)); CALL(reinterpret_cast<void *>(&Jit));
ABI_RestoreStack(4); ABI_RestoreStack(4);
#else
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
CALL((void *)&Jit);
#endif
JMP(dispatcherNoCheck); // no point in special casing this JMP(dispatcherNoCheck); // no point in special casing this
//FP blocks test for FPU available, jump here if false //FP blocks test for FPU available, jump here if false
@ -152,100 +162,21 @@ void AsmRoutineManager::Generate()
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF)); TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true); J_CC(CC_Z, outerLoop, true);
#ifdef _M_IX86
POP(EDI); POP(EDI);
POP(ESI); POP(ESI);
POP(EBX); POP(EBX);
POP(EBP); POP(EBP);
RET(); #else
GenerateCommon();
}
#elif defined(_M_X64)
void AsmRoutineManager::Generate()
{
enterCode = AlignCode16();
ABI_PushAllCalleeSavedRegsAndAdjustStack();
MOV(64, R(RBX), Imm64((u64)Memory::base));
MOV(64, R(R15), Imm64((u64)jit.GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough
const u8 *outerLoop = GetCodePtr();
CALL((void *)&CoreTiming::Advance);
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
dispatcher = GetCodePtr();
//The result of slice decrementation should be in flags if somebody jumped here
//Jump on negative, not carry!!!
FixupBranch bail = J_CC(CC_BE);
SetJumpTarget(skipToRealDispatch);
dispatcherNoCheck = GetCodePtr();
MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
dispatcherPcInEAX = GetCodePtr();
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
TEST(32, R(EAX), Imm32(0xFC));
FixupBranch notfound = J_CC(CC_NZ);
BSWAP(32, EAX);
//IDEA - we have 26 bits, why not just use offsets from base of code?
if (enableStatistics)
{
ADD(32, M(&blocksExecuted), Imm8(1));
}
if (enableDebug)
{
ADD(32, M(&PowerPC::ppcState.DebugCount), Imm8(1));
}
//grab from list and jump to it
JMPptr(MComplex(R15, RAX, 8, 0));
SetJumpTarget(notfound);
//Ok, no block, let's jit
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
CALL((void *)&Jit);
JMP(dispatcherNoCheck); // no point in special casing this, not the "fast path"
//FP blocks test for FPU available, jump here if false
fpException = AlignCode4();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
CALL((void *)&PowerPC::CheckExceptions);
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));
JMP(dispatcherNoCheck);
SetJumpTarget(bail);
doTiming = GetCodePtr();
TEST(32, M(&PC), Imm32(0xFFFFFFFF));
FixupBranch mojs = J_CC(CC_NZ);
INT3(); // if you hit this, PC == 0 - no good
SetJumpTarget(mojs);
CALL((void *)&CoreTiming::Advance);
testExceptions = GetCodePtr();
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
FixupBranch skipExceptions = J_CC(CC_Z);
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
CALL((void *)&PowerPC::CheckExceptions);
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));
SetJumpTarget(skipExceptions);
TEST(32, M((void*)&PowerPC::state), Imm32(0xFFFFFFFF));
J_CC(CC_Z, outerLoop, true);
//Landing pad for drec space //Landing pad for drec space
ABI_PopAllCalleeSavedRegsAndAdjustStack(); ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET(); RET();
#endif
RET();
GenerateCommon(); GenerateCommon();
} }
#endif
void AsmRoutineManager::GenFifoWrite(int size) void AsmRoutineManager::GenFifoWrite(int size)
{ {

View File

@ -194,7 +194,7 @@ using namespace Gen;
return blockCodePointers; return blockCodePointers;
} }
int JitBlockCache::GetBlockNumberFromAddress(u32 addr) int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr)
{ {
if (!blocks) if (!blocks)
return -1; return -1;
@ -222,22 +222,13 @@ using namespace Gen;
u32 JitBlockCache::GetOriginalCode(u32 address) u32 JitBlockCache::GetOriginalCode(u32 address)
{ {
int num = GetBlockNumberFromAddress(address); int num = GetBlockNumberFromStartAddress(address);
if (num == -1) if (num == -1)
return Memory::ReadUnchecked_U32(address); return Memory::ReadUnchecked_U32(address);
else else
return blocks[num].originalFirstOpcode; return blocks[num].originalFirstOpcode;
} }
CompiledCode JitBlockCache::GetCompiledCode(u32 address)
{
int num = GetBlockNumberFromAddress(address);
if (num == -1)
return 0;
else
return (CompiledCode)blockCodePointers[num];
}
CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int blockNumber) CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int blockNumber)
{ {
return (CompiledCode)blockCodePointers[blockNumber]; return (CompiledCode)blockCodePointers[blockNumber];
@ -261,7 +252,7 @@ using namespace Gen;
{ {
if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e]) if (b.exitAddress[e] != INVALID_EXIT && !b.linkStatus[e])
{ {
int destinationBlock = GetBlockNumberFromAddress(b.exitAddress[e]); int destinationBlock = GetBlockNumberFromStartAddress(b.exitAddress[e]);
if (destinationBlock != -1) if (destinationBlock != -1)
{ {
XEmitter emit(b.exitPtrs[e]); XEmitter emit(b.exitPtrs[e]);

View File

@ -14,6 +14,7 @@
// Official SVN repository and contact information can be found at // Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/ // http://code.google.com/p/dolphin-emu/
#ifndef _JITCACHE_H #ifndef _JITCACHE_H
#define _JITCACHE_H #define _JITCACHE_H
@ -70,34 +71,41 @@ class JitBlockCache
std::multimap<u32, int> links_to; std::multimap<u32, int> links_to;
int MAX_NUM_BLOCKS; int MAX_NUM_BLOCKS;
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
void LinkBlockExits(int i);
void LinkBlock(int i);
public: public:
JitBlockCache() {} JitBlockCache() {}
void SetJit(Jit64 *jit_) { jit = jit_; } void SetJit(Jit64 *jit_) { jit = jit_; }
const u8* Jit(u32 emaddress); const u8* Jit(u32 emaddress);
void Clear(); void Clear();
void Init(); void Init();
void Shutdown(); void Shutdown();
void Reset(); void Reset();
bool IsFull() const; bool IsFull() const;
// Code Cache // Code Cache
u32 GetOriginalCode(u32 address);
JitBlock *GetBlock(int no); JitBlock *GetBlock(int no);
void InvalidateCodeRange(u32 address, u32 length);
int GetBlockNumberFromAddress(u32 address);
CompiledCode GetCompiledCode(u32 address);
CompiledCode GetCompiledCodeFromBlock(int blockNumber);
int GetNumBlocks() const; int GetNumBlocks() const;
u8 **GetCodePointers(); u8 **GetCodePointers();
void DestroyBlocksWithFlag(BlockFlag death_flag);
void LinkBlocks(); // Fast way to get a block. Only works on the first ppc instruction of a block.
void LinkBlockExits(int i); int GetBlockNumberFromStartAddress(u32 address);
void LinkBlock(int i); // slower, but can get numbers from within blocks, not just the first instruction. WARNING! DOES NOT WORK WITH INLINING ENABLED (not yet a feature but will be soon)
int GetBlockNumberFromInternalAddress(u32 address);
u32 GetOriginalCode(u32 address);
CompiledCode GetCompiledCodeFromBlock(int blockNumber);
// DOES NOT WORK CORRECTLY WITH INLINING
void InvalidateCodeRange(u32 address, u32 length);
void DestroyBlock(int blocknum, bool invalidate); void DestroyBlock(int blocknum, bool invalidate);
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
// Not currently used
void DestroyBlocksWithFlag(BlockFlag death_flag);
}; };
#endif #endif

View File

@ -393,6 +393,9 @@
// A few games use these heavily in video codecs. // A few games use these heavily in video codecs.
void Jit64::lmw(UGeckoInstruction inst) void Jit64::lmw(UGeckoInstruction inst)
{ {
#ifdef _M_IX86
Default(inst); return;
#else
gpr.FlushLockX(ECX); gpr.FlushLockX(ECX);
MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16)); MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16));
if (inst.RA) if (inst.RA)
@ -407,10 +410,14 @@ void Jit64::lmw(UGeckoInstruction inst)
MOV(32, gpr.R(i), R(ECX)); MOV(32, gpr.R(i), R(ECX));
} }
gpr.UnlockAllX(); gpr.UnlockAllX();
#endif
} }
void Jit64::stmw(UGeckoInstruction inst) void Jit64::stmw(UGeckoInstruction inst)
{ {
#ifdef _M_IX86
Default(inst); return;
#else
gpr.FlushLockX(ECX); gpr.FlushLockX(ECX);
MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16)); MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16));
if (inst.RA) if (inst.RA)
@ -424,4 +431,5 @@ void Jit64::stmw(UGeckoInstruction inst)
MOV(32, MComplex(EBX, EAX, SCALE_1, (i - inst.RD) * 4), R(ECX)); MOV(32, MComplex(EBX, EAX, SCALE_1, (i - inst.RD) * 4), R(ECX));
} }
gpr.UnlockAllX(); gpr.UnlockAllX();
#endif
} }

View File

@ -138,11 +138,11 @@ void CJitWindow::Compare(u32 em_address)
disassembler x64disasm; disassembler x64disasm;
x64disasm.set_syntax_intel(); x64disasm.set_syntax_intel();
int block_num = jit.GetBlockCache()->GetBlockNumberFromAddress(em_address); int block_num = jit.GetBlockCache()->GetBlockNumberFromStartAddress(em_address);
if (block_num < 0) if (block_num < 0)
{ {
for (int i = 0; i < 500; i++) { for (int i = 0; i < 500; i++) {
block_num = jit.GetBlockCache()->GetBlockNumberFromAddress(em_address - 4 * i); block_num = jit.GetBlockCache()->GetBlockNumberFromStartAddress(em_address - 4 * i);
if (block_num >= 0) if (block_num >= 0)
break; break;
} }