JIT single stepping

Enable it by uncommenting the defines in JitBase.h.  For breakpoints to work in JIT mode, the block cache must be disabled.  The PPC instruction trace, regs, fpu regs, flags, generated x86 binary and generated x86 disasm are logged in the Dynamic Recompiler log.

Fixes issue 1052.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5314 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau 2010-04-10 15:41:44 +00:00
parent 4b5b074b81
commit be70b43a2b
21 changed files with 282 additions and 74 deletions

View File

@ -78,7 +78,7 @@ LogManager::LogManager() {
m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET");
m_Log[LogTypes::WII_IPC_WIIMOTE] = new LogContainer("WII_IPC_WIIMOTE","WII IPC WIIMOTE"); m_Log[LogTypes::WII_IPC_WIIMOTE] = new LogContainer("WII_IPC_WIIMOTE","WII IPC WIIMOTE");
m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay");
m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manger", "MemCard Manger"); m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX)); m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX));
@ -110,7 +110,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
va_list args) { va_list args) {
char temp[MAX_MSGLEN]; char temp[MAX_MSGLEN];
char msg[MAX_MSGLEN + 512]; char msg[MAX_MSGLEN * 2];
LogContainer *log = m_Log[type]; LogContainer *log = m_Log[type];
if (! log->isEnable() || level > log->getLevel()) if (! log->isEnable() || level > log->getLevel())

View File

@ -26,7 +26,7 @@
#include <stdio.h> #include <stdio.h>
#define MAX_MESSAGES 8000 #define MAX_MESSAGES 8000
#define MAX_MSGLEN 512 #define MAX_MSGLEN 1024
// pure virtual interface (well, except the destructor which we just leave empty). // pure virtual interface (well, except the destructor which we just leave empty).

View File

@ -22,6 +22,8 @@
#include "CoreTiming.h" #include "CoreTiming.h"
#include "StringUtil.h" #include "StringUtil.h"
#define MAX_SLICE_LENGTH 20000
namespace CoreTiming namespace CoreTiming
{ {
@ -53,7 +55,7 @@ Event *eventTsPool = 0;
int allocatedTsEvents = 0; int allocatedTsEvents = 0;
int downcount, slicelength; int downcount, slicelength;
int maxSliceLength = 20000; int maxSliceLength = MAX_SLICE_LENGTH;
s64 globalTimer; s64 globalTimer;
s64 idledCycles; s64 idledCycles;
@ -332,6 +334,10 @@ void SetMaximumSlice(int maximumSliceLength)
maxSliceLength = maximumSliceLength; maxSliceLength = maximumSliceLength;
} }
void ResetSliceLength()
{
maxSliceLength = MAX_SLICE_LENGTH;
}
void Advance() void Advance()
{ {

View File

@ -72,6 +72,7 @@ void ClearPendingEvents();
void LogPendingEvents(); void LogPendingEvents();
void SetMaximumSlice(int maximumSliceLength); void SetMaximumSlice(int maximumSliceLength);
void ResetSliceLength();
void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted)); void RegisterAdvanceCallback(void (*callback)(int cyclesExecuted));

View File

@ -522,7 +522,7 @@ union UReg_BAT_Up
{ {
unsigned VP : 1; unsigned VP : 1;
unsigned VS : 1; unsigned VS : 1;
unsigned BL : 11; unsigned BL : 11; // Block length (aka block size mask)
unsigned : 4; unsigned : 4;
unsigned BEPI : 15; unsigned BEPI : 15;
}; };
@ -540,7 +540,7 @@ union UReg_BAT_Lo
unsigned : 1; unsigned : 1;
unsigned WIMG : 4; unsigned WIMG : 4;
unsigned : 10; unsigned : 10;
unsigned BRPN : 15; unsigned BRPN : 15; // Physical Block Number
}; };
u32 Hex; u32 Hex;
@ -623,16 +623,16 @@ enum
SPR_IBAT1L = 531, SPR_IBAT1L = 531,
SPR_IBAT2U = 532, SPR_IBAT2U = 532,
SPR_IBAT2L = 533, SPR_IBAT2L = 533,
SPR_IBAT3L = 534, SPR_IBAT3U = 534,
SPR_IBAT3U = 535, SPR_IBAT3L = 535,
SPR_DBAT0U = 536, SPR_DBAT0U = 536,
SPR_DBAT0L = 537, SPR_DBAT0L = 537,
SPR_DBAT1U = 538, SPR_DBAT1U = 538,
SPR_DBAT1L = 539, SPR_DBAT1L = 539,
SPR_DBAT2U = 540, SPR_DBAT2U = 540,
SPR_DBAT2L = 541, SPR_DBAT2L = 541,
SPR_DBAT3L = 542, SPR_DBAT3U = 542,
SPR_DBAT3U = 543, SPR_DBAT3L = 543,
SPR_GQR0 = 912, SPR_GQR0 = 912,
SPR_HID0 = 1008, SPR_HID0 = 1008,
SPR_HID1 = 1009, SPR_HID1 = 1009,

View File

@ -175,7 +175,12 @@ void Jit64::Init()
where this cause problems, so I'm enabling this by default, since I seem to get perhaps as much as 20% more where this cause problems, so I'm enabling this by default, since I seem to get perhaps as much as 20% more
fps with this option enabled. If you suspect that this option cause problems you can also disable it from the fps with this option enabled. If you suspect that this option cause problems you can also disable it from the
debugging window. */ debugging window. */
#ifdef JIT_SINGLESTEP
jo.enableBlocklink = false;
SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = false;
#else
jo.enableBlocklink = true; jo.enableBlocklink = true;
#endif
#ifdef _M_X64 #ifdef _M_X64
jo.enableFastMem = SConfig::GetInstance().m_LocalCoreStartupParameter.bUseFastMem; jo.enableFastMem = SConfig::GetInstance().m_LocalCoreStartupParameter.bUseFastMem;
#else #else
@ -369,14 +374,44 @@ void STACKALIGN Jit64::Run()
void Jit64::SingleStep() void Jit64::SingleStep()
{ {
// NOT USED, NOT TESTED, PROBABLY NOT WORKING YET #ifndef JIT_NO_CACHE
// PanicAlert("Single"); CoreTiming::SetMaximumSlice(1);
/* #endif
JitBlock temp_block;
PPCAnalyst::CodeBuffer temp_codebuffer(1); // Only room for one instruction! Single step! CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
const u8 *code = DoJit(PowerPC::ppcState.pc, &temp_codebuffer, &temp_block); pExecAddr();
CompiledCode pExecAddr = (CompiledCode)code;
pExecAddr();*/ #ifndef JIT_NO_CACHE
CoreTiming::ResetSliceLength();
#endif
}
void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address)
{
char reg[50] = "";
char regs[500] = "";
char fregs[750] = "";
#ifdef JIT_LOG_GPR
for (int i = 0; i < 32; i++)
{
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
strncat(regs, reg, 500);
}
#endif
#ifdef JIT_LOG_FPR
for (int i = 0; i < 32; i++)
{
sprintf(reg, "f%02d: %016x ", i, riPS0(i));
strncat(fregs, reg, 750);
}
#endif
const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[0];
char ppcInst[256];
DisassembleGekko(op.inst.hex, em_address, ppcInst, 256);
NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x Cycles: %04d CR: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %s", em_address, js.st.numCycles, PowerPC::ppcState.cr, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, ppcInst);
} }
void STACKALIGN Jit64::Jit(u32 em_address) void STACKALIGN Jit64::Jit(u32 em_address)
@ -391,14 +426,31 @@ void STACKALIGN Jit64::Jit(u32 em_address)
} }
ClearCache(); ClearCache();
} }
#ifdef JIT_NO_CACHE
ClearCache();
if (PowerPC::breakpoints.IsAddressBreakPoint(em_address))
{
PowerPC::Pause();
if (PowerPC::breakpoints.IsTempBreakPoint(em_address))
PowerPC::breakpoints.Remove(em_address);
return;
}
#endif
int block_num = blocks.AllocateBlock(em_address); int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num); JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b)); blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
} }
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b) const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b)
{ {
int blockSize = code_buffer->GetSize();
#ifdef JIT_SINGLESTEP
blockSize = 1;
Trace(code_buffer, em_address);
#endif
if (em_address == 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);
@ -412,8 +464,9 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
//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(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buf); u32 nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buffer, blockSize);
PPCAnalyst::CodeOp *ops = code_buf->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
b->checkedEntry = start; b->checkedEntry = start;
@ -426,6 +479,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
SetJumpTarget(skip); SetJumpTarget(skip);
const u8 *normalEntry = GetCodePtr(); const u8 *normalEntry = GetCodePtr();
b->normalEntry = normalEntry;
if (ImHereDebug) if (ImHereDebug)
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
@ -473,7 +527,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
gpr.Start(js.gpa); gpr.Start(js.gpa);
fpr.Start(js.fpa); fpr.Start(js.fpa);
#ifdef JIT_SINGLESTEP
js.downcountAmount = js.st.numCycles;
#else
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address); js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
#endif
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++)
@ -512,12 +571,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
ABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0)); ABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
} }
// If starting from the breakpointed instruction, we don't break.
if (em_address != ops[i].address && PowerPC::breakpoints.IsAddressBreakPoint(ops[i].address))
{
}
if (!ops[i].skip) if (!ops[i].skip)
Jit64Tables::CompileInstruction(ops[i].inst); Jit64Tables::CompileInstruction(ops[i].inst);
@ -527,8 +580,19 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
break; break;
} }
#ifdef JIT_SINGLESTEP
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
WriteExit(nextPC, 0);
#endif
b->flags = js.block_flags; b->flags = js.block_flags;
b->codeSize = (u32)(GetCodePtr() - normalEntry); b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size; b->originalSize = size;
#ifdef JIT_LOG_X86
LogGeneratedX86(size, code_buffer, normalEntry, b);
#endif
return normalEntry; return normalEntry;
} }

View File

@ -106,6 +106,7 @@ public:
JitBlockCache *GetBlockCache() { return &blocks; } JitBlockCache *GetBlockCache() { return &blocks; }
void NotifyBreakpoint(u32 em_address, bool set); void NotifyBreakpoint(u32 em_address, bool set);
void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address);
void ClearCache(); void ClearCache();

View File

@ -114,6 +114,11 @@ void Jit64AsmRoutineManager::Generate()
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc)); MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
CALL((void *)&Jit); CALL((void *)&Jit);
#endif #endif
#ifdef JIT_NO_CACHE
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
FixupBranch notRunning = J_CC(CC_NZ);
#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
@ -126,6 +131,9 @@ void Jit64AsmRoutineManager::Generate()
MOV(32, M(&PC), R(EAX)); MOV(32, M(&PC), R(EAX));
JMP(dispatcher); JMP(dispatcher);
#ifdef JIT_NO_CACHE
SetJumpTarget(notRunning);
#endif
SetJumpTarget(bail); SetJumpTarget(bail);
doTiming = GetCodePtr(); doTiming = GetCodePtr();

View File

@ -262,7 +262,7 @@ void RegCache::KillImmediate(int preg)
void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty) void GPRRegCache::LoadToX64(int i, bool doLoad, bool makeDirty)
{ {
if (!regs[i].away && regs[i].location.IsImm()) if (!regs[i].away && regs[i].location.IsImm())
PanicAlert("Bad immedaite"); PanicAlert("Bad immediate");
if (!regs[i].away || (regs[i].away && regs[i].location.IsImm())) if (!regs[i].away || (regs[i].away && regs[i].location.IsImm()))
{ {
@ -375,7 +375,7 @@ void RegCache::Flush(FlushMode mode)
{ {
for (int i = 0; i < NUMXREGS; i++) { for (int i = 0; i < NUMXREGS; i++) {
if (xlocks[i]) if (xlocks[i])
PanicAlert("Somone forgot to unlock X64 reg %i.", i); PanicAlert("Someone forgot to unlock X64 reg %i.", i);
} }
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {

View File

@ -1662,6 +1662,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
//if (!RI.MakeProfile && RI.numSpills) //if (!RI.MakeProfile && RI.numSpills)
// printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills); // printf("Block: %x, numspills %d\n", Jit->js.blockStart, RI.numSpills);
Jit->WriteExit(jit->js.curBlock->exitAddress[0], 0);
Jit->UD2(); Jit->UD2();
} }

View File

@ -167,7 +167,12 @@ void JitIL::Init()
CODE_SIZE = 1024*1024*8*8; CODE_SIZE = 1024*1024*8*8;
jo.optimizeStack = true; jo.optimizeStack = true;
#ifdef JIT_SINGLESTEP
jo.enableBlocklink = false;
Core::g_CoreStartupParameter.bSkipIdle = false;
#else
jo.enableBlocklink = true; // Speed boost, but not 100% safe jo.enableBlocklink = true; // Speed boost, but not 100% safe
#endif
#ifdef _M_X64 #ifdef _M_X64
jo.enableFastMem = false; jo.enableFastMem = false;
#else #else
@ -346,14 +351,44 @@ void STACKALIGN JitIL::Run()
void JitIL::SingleStep() void JitIL::SingleStep()
{ {
// NOT USED, NOT TESTED, PROBABLY NOT WORKING YET #ifndef JIT_NO_CACHE
// PanicAlert("Single"); CoreTiming::SetMaximumSlice(1);
/* #endif
JitBlock temp_block;
PPCAnalyst::CodeBuffer temp_codebuffer(1); // Only room for one instruction! Single step! CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
const u8 *code = DoJit(PowerPC::ppcState.pc, &temp_codebuffer, &temp_block); pExecAddr();
CompiledCode pExecAddr = (CompiledCode)code;
pExecAddr();*/ #ifndef JIT_NO_CACHE
CoreTiming::ResetSliceLength();
#endif
}
void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address)
{
char reg[50] = "";
char regs[500] = "";
char fregs[750] = "";
#ifdef JIT_LOG_GPR
for (int i = 0; i < 32; i++)
{
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
strncat(regs, reg, 500);
}
#endif
#ifdef JIT_LOG_FPR
for (int i = 0; i < 32; i++)
{
sprintf(reg, "f%02d: %016x ", i, riPS0(i));
strncat(fregs, reg, 750);
}
#endif
const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[0];
char ppcInst[256];
DisassembleGekko(op.inst.hex, em_address, ppcInst, 256);
NOTICE_LOG(DYNA_REC, "JITIL PC: %08x Cycles: %04d CR: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %s", em_address, js.st.numCycles, PowerPC::ppcState.cr, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, ppcInst);
} }
void STACKALIGN JitIL::Jit(u32 em_address) void STACKALIGN JitIL::Jit(u32 em_address)
@ -368,13 +403,30 @@ void STACKALIGN JitIL::Jit(u32 em_address)
} }
ClearCache(); ClearCache();
} }
#ifdef JIT_NO_CACHE
ClearCache();
if (PowerPC::breakpoints.IsAddressBreakPoint(em_address))
{
PowerPC::Pause();
if (PowerPC::breakpoints.IsTempBreakPoint(em_address))
PowerPC::breakpoints.Remove(em_address);
return;
}
#endif
int block_num = blocks.AllocateBlock(em_address); int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num); JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b)); blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
} }
const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *buffer, JitBlock *b) const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b)
{ {
int blockSize = code_buffer->GetSize();
#ifdef JIT_SINGLESTEP
blockSize = 1;
Trace(code_buffer, em_address);
#endif
if (em_address == 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);
@ -387,8 +439,8 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *buffer, JitBlock
//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(em_address, &size, &js.st, &js.gpa, &js.fpa, buffer); b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buffer, blockSize);
PPCAnalyst::CodeOp *ops = 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
b->checkedEntry = start; b->checkedEntry = start;
@ -422,7 +474,11 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *buffer, JitBlock
// instruction processed by the JIT routines) // instruction processed by the JIT routines)
ibuild.Reset(); ibuild.Reset();
#ifdef JIT_SINGLESTEP
js.downcountAmount = js.st.numCycles;
#else
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address); js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
#endif
// Translate instructions // Translate instructions
for (int i = 0; i < (int)size; i++) for (int i = 0; i < (int)size; i++)
{ {
@ -452,5 +508,10 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *buffer, JitBlock
b->codeSize = (u32)(GetCodePtr() - normalEntry); b->codeSize = (u32)(GetCodePtr() - normalEntry);
b->originalSize = size; b->originalSize = size;
#ifdef JIT_LOG_X86
LogGeneratedX86(size, code_buffer, normalEntry, b);
#endif
return normalEntry; return normalEntry;
} }

View File

@ -85,6 +85,7 @@ public:
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b); const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b);
void NotifyBreakpoint(u32 em_address, bool set); void NotifyBreakpoint(u32 em_address, bool set);
void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address);
void ClearCache(); void ClearCache();
const u8 *GetDispatcher() { const u8 *GetDispatcher() {

View File

@ -78,8 +78,8 @@ void JitILAsmRoutineManager::Generate()
dispatcher = GetCodePtr(); dispatcher = GetCodePtr();
//This is the place for CPUCompare! //This is the place for CPUCompare!
//The result of slice decrementation should be in flags if somebody jumped here //The result of slice decrement should be in flags if somebody jumped here
FixupBranch bail = J_CC(CC_S); FixupBranch bail = J_CC(CC_BE);
SetJumpTarget(skipToRealDispatch); SetJumpTarget(skipToRealDispatch);
dispatcherNoCheck = GetCodePtr(); dispatcherNoCheck = GetCodePtr();
@ -116,6 +116,11 @@ void JitILAsmRoutineManager::Generate()
MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc)); MOV(32, R(ABI_PARAM1), M(&PowerPC::ppcState.pc));
CALL((void *)&Jit); CALL((void *)&Jit);
#endif #endif
#ifdef JIT_NO_CACHE
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
FixupBranch notRunning = J_CC(CC_NZ);
#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
@ -128,6 +133,10 @@ void JitILAsmRoutineManager::Generate()
MOV(32, M(&PC), R(EAX)); MOV(32, M(&PC), R(EAX));
JMP(dispatcher); JMP(dispatcher);
#ifdef JIT_NO_CACHE
SetJumpTarget(notRunning);
#endif
SetJumpTarget(bail); SetJumpTarget(bail);
doTiming = GetCodePtr(); doTiming = GetCodePtr();

View File

@ -29,3 +29,47 @@ u32 Helper_Mask(u8 mb, u8 me)
(((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1)))) (((u32)-1 >> mb) ^ ((me >= 31) ? 0 : (u32) -1 >> (me + 1))))
); );
} }
void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b)
{
char pDis[1000] = "";
for (int i = 0; i < size; i++)
{
char temp[256] = "";
const PPCAnalyst::CodeOp &op = code_buffer->codebuffer[i];
DisassembleGekko(op.inst.hex, op.address, temp, 256);
sprintf(pDis, "%08x %s", op.address, temp);
DEBUG_LOG(DYNA_REC,"IR_X86 PPC: %s\n", pDis);
}
disassembler x64disasm;
x64disasm.set_syntax_intel();
u64 disasmPtr = (u64)normalEntry;
const u8 *end = normalEntry + b->codeSize;
while ((u8*)disasmPtr < end)
{
char sptr[1000] = "";
#ifdef _M_X64
disasmPtr += x64disasm.disasm64(disasmPtr, disasmPtr, (u8*)disasmPtr, sptr);
#else
disasmPtr += x64disasm.disasm32(disasmPtr, disasmPtr, (u8*)disasmPtr, sptr);
#endif
DEBUG_LOG(DYNA_REC,"IR_X86 x86: %s", sptr);
}
if (b->codeSize <= 250)
{
char x86code[500] = "";
for (u8 i = 0; i <= b->codeSize; i++)
{
char opcHex[2] = "";
u8 opc = *(normalEntry + i);
sprintf(opcHex, "%02x", opc);
strncat(x86code, opcHex, 2);
}
DEBUG_LOG(DYNA_REC,"IR_X86 bin: %s\n\n\n", x86code);
}
}

View File

@ -18,11 +18,20 @@
#ifndef _JITBASE_H #ifndef _JITBASE_H
#define _JITBASE_H #define _JITBASE_H
//#define JIT_SINGLESTEP // Enables single stepping
//#define JIT_NO_CACHE // Disables the block cache and enables breakpoints
//#define JIT_LOG_X86 // Enables logging of the generated x86 code
//#define JIT_LOG_GPR // Enables logging of the PPC general purpose regs
//#define JIT_LOG_FPR // Enables logging of the PPC floating point regs
#include "JitCache.h" #include "JitCache.h"
#include "Jit_Util.h" // for EmuCodeBlock #include "Jit_Util.h" // for EmuCodeBlock
#include "JitBackpatch.h" // for EmuCodeBlock #include "JitBackpatch.h" // for EmuCodeBlock
#include "JitAsmCommon.h" #include "JitAsmCommon.h"
#include "PowerPCDisasm.h"
#include "disasm.h"
#define JIT_OPCODE 0 #define JIT_OPCODE 0
// TODO: In the future, inherit this from CPUCoreBase and have Interpreter // TODO: In the future, inherit this from CPUCoreBase and have Interpreter
@ -97,6 +106,6 @@ void Jit(u32 em_address);
// Merged routines that should be moved somewhere better // Merged routines that should be moved somewhere better
u32 Helper_Mask(u8 mb, u8 me); u32 Helper_Mask(u8 mb, u8 me);
void LogGeneratedX86(int size, PPCAnalyst::CodeBuffer *code_buffer, const u8 *normalEntry, JitBlock *b);
#endif #endif

View File

@ -284,7 +284,8 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
} }
// Does not yet perform inlining - although there are plans for that. // Does not yet perform inlining - although there are plans for that.
bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer) // Returns the exit address of the next PC
u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer, int blockSize)
{ {
memset(st, 0, sizeof(st)); memset(st, 0, sizeof(st));
UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4); UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4);
@ -295,7 +296,8 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
fpa->any = false; fpa->any = false;
u32 blockstart = address; u32 blockstart = address;
int maxsize = buffer->GetSize(); int maxsize = blockSize;
int num_inst = 0; int num_inst = 0;
int numFollows = 0; int numFollows = 0;
int numCycles = 0; int numCycles = 0;
@ -304,8 +306,9 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
bool foundExit = false; bool foundExit = false;
// Flatten! (Currently just copies, following branches is disabled) // Flatten! (Currently just copies, following branches is disabled)
for (int i = 0; i < maxsize; i++, num_inst++) for (int i = 0; i < maxsize; i++)
{ {
num_inst++;
memset(&code[i], 0, sizeof(CodeOp)); memset(&code[i], 0, sizeof(CodeOp));
code[i].address = address; code[i].address = address;
@ -322,7 +325,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
_assert_msg_(POWERPC, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst.hex); _assert_msg_(POWERPC, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst.hex);
bool follow = false; bool follow = false;
u32 destination; u32 destination;
if (inst.OPCD == 18) if (inst.OPCD == 18 && blockSize > 1)
{ {
//Is bx - should we inline? yes! //Is bx - should we inline? yes!
if (inst.AA) if (inst.AA)
@ -352,9 +355,8 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
address = destination; address = destination;
} }
} }
if (!foundExit && blockSize > 1)
_assert_msg_(POWERPC, foundExit, "Analyzer ERROR - Function %08x too big", blockstart); NOTICE_LOG(POWERPC, "Analyzer ERROR - Function %08x too big, size is 0x%08x", blockstart, address-blockstart);
num_inst++; // why?
st->numCycles = numCycles; st->numCycles = numCycles;
// Do analysis of the code, look for dependencies etc // Do analysis of the code, look for dependencies etc
@ -497,7 +499,8 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
} }
// Instruction Reordering Pass // Instruction Reordering Pass
if (blockSize > 1)
{
// Bubble down compares towards branches, so that they can be merged. // Bubble down compares towards branches, so that they can be merged.
// -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch. // -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch.
for (int i = 0; i < num_inst - 2; i++) for (int i = 0; i < num_inst - 2; i++)
@ -517,13 +520,13 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
} }
} }
} }
}
// Scan for CR0 dependency // Scan for CR0 dependency
// assume next block wants CR0 to be safe // assume next block wants CR0 to be safe
bool wantsCR0 = true; bool wantsCR0 = true;
bool wantsCR1 = true; bool wantsCR1 = true;
bool wantsPS1 = true; bool wantsPS1 = true;
for (int i = num_inst - 1; i; i--) for (int i = num_inst; i; i--)
{ {
if (code[i].outputCR0) if (code[i].outputCR0)
wantsCR0 = false; wantsCR0 = false;
@ -541,7 +544,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
*realsize = num_inst; *realsize = num_inst;
// ... // ...
return true; return address;
} }

View File

@ -92,7 +92,7 @@ public:
}; };
bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer); u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer, int blockSize);
void LogFunctionCall(u32 addr); void LogFunctionCall(u32 addr);
void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db); void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db);
bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0); bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0);

View File

@ -158,6 +158,7 @@ void Shutdown()
{ {
// Shutdown both execution engines. Doesn't matter which one is active. // Shutdown both execution engines. Doesn't matter which one is active.
jit->Shutdown(); jit->Shutdown();
state = CPU_POWERDOWN;
delete jit; delete jit;
jit = 0; jit = 0;
Interpreter::Shutdown(); Interpreter::Shutdown();

View File

@ -48,7 +48,6 @@ struct GC_ALIGNED64(PowerPCState)
u32 pc; // program counter u32 pc; // program counter
u32 npc; u32 npc;
u32 nextBlock;
u32 cr; // flags u32 cr; // flags
u8 cr_fast[8]; // Possibly reorder to 0, 2, 4, 8, 1, 3, 5, 7 so that we can make Compact and Expand super fast? u8 cr_fast[8]; // Possibly reorder to 0, 2, 4, 8, 1, 3, 5, 7 so that we can make Compact and Expand super fast?

View File

@ -692,7 +692,7 @@ void CCodeWindow::UpdateButtonStates()
} }
} }
ToolBar->EnableTool(IDM_STEP, Initialized && Stepping && UseInterpreter()); ToolBar->EnableTool(IDM_STEP, Initialized && Stepping);
if (ToolBar) ToolBar->Realize(); if (ToolBar) ToolBar->Realize();

View File

@ -179,7 +179,7 @@ void CJitWindow::Compare(u32 em_address)
PPCAnalyst::BlockStats st; PPCAnalyst::BlockStats st;
PPCAnalyst::BlockRegStats gpa; PPCAnalyst::BlockRegStats gpa;
PPCAnalyst::BlockRegStats fpa; PPCAnalyst::BlockRegStats fpa;
if (PPCAnalyst::Flatten(ppc_addr, &size, &st, &gpa, &fpa, &code_buffer)) if (PPCAnalyst::Flatten(ppc_addr, &size, &st, &gpa, &fpa, &code_buffer, size) != 0xffffffff)
{ {
sptr = (char*)xDis; sptr = (char*)xDis;
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)