More code reorganization.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1605 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
hrydgard 2008-12-20 12:10:59 +00:00
parent f0bb8f430a
commit 614dc1069e
16 changed files with 203 additions and 199 deletions

View File

@ -35,12 +35,6 @@
void Console_Submit(const char *cmd) void Console_Submit(const char *cmd)
{ {
CASE1("jits")
{
#ifdef _M_X64
jit.PrintStats();
#endif
}
CASE1("r") CASE1("r")
{ {
Core::StartTrace(false); Core::StartTrace(false);
@ -57,7 +51,7 @@ void Console_Submit(const char *cmd)
u32 addr; u32 addr;
sscanf(cmd, "%s %08x", temp, &addr); sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0) if (addr)
{ {
#ifdef LOGGING #ifdef LOGGING
u32 EA = u32 EA =
@ -75,7 +69,7 @@ void Console_Submit(const char *cmd)
TCHAR temp[256]; TCHAR temp[256];
u32 addr; u32 addr;
sscanf(cmd, "%s %08x", temp, &addr); sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0) if (addr)
{ {
g_symbolDB.PrintCalls(addr); g_symbolDB.PrintCalls(addr);
} }
@ -89,7 +83,7 @@ void Console_Submit(const char *cmd)
TCHAR temp[256]; TCHAR temp[256];
u32 addr; u32 addr;
sscanf(cmd, "%s %08x", temp, &addr); sscanf(cmd, "%s %08x", temp, &addr);
if (addr!=0) if (addr)
{ {
g_symbolDB.PrintCallers(addr); g_symbolDB.PrintCallers(addr);
} }
@ -111,7 +105,7 @@ void Console_Submit(const char *cmd)
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename); sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
FILE *f = fopen(filename, "wb"); FILE *f = fopen(filename, "wb");
for (u32 i=start; i<end; i++) for (u32 i = start; i < end; i++)
{ {
u8 b = Memory::ReadUnchecked_U8(i); u8 b = Memory::ReadUnchecked_U8(i);
fputc(b,f); fputc(b,f);

View File

@ -28,6 +28,7 @@
#include "../HW/CPU.h" #include "../HW/CPU.h"
#include "../Host.h" #include "../Host.h"
#include "../PowerPC/SymbolDB.h" #include "../PowerPC/SymbolDB.h"
#include "../PowerPC/Jit64/Jit.h"
#include "Debugger_BreakPoints.h" #include "Debugger_BreakPoints.h"
CBreakPoints::TBreakPoints CBreakPoints::m_BreakPoints; CBreakPoints::TBreakPoints CBreakPoints::m_BreakPoints;
@ -90,7 +91,7 @@ TMemCheck *CBreakPoints::GetMemCheck(u32 address)
} }
else else
{ {
if ((*iter).StartAddress==address) if ((*iter).StartAddress == address)
return &(*iter); return &(*iter);
} }
} }
@ -99,16 +100,17 @@ TMemCheck *CBreakPoints::GetMemCheck(u32 address)
return 0; return 0;
} }
void CBreakPoints::AddBreakPoint(u32 _iAddress, bool temp) void CBreakPoints::AddBreakPoint(u32 em_address, bool temp)
{ {
if (!IsAddressBreakPoint(_iAddress)) // only add new addresses if (!IsAddressBreakPoint(em_address)) // only add new addresses
{ {
TBreakPoint pt; // breakpoint settings TBreakPoint pt; // breakpoint settings
pt.bOn = true; pt.bOn = true;
pt.bTemporary = temp; pt.bTemporary = temp;
pt.iAddress = _iAddress; pt.iAddress = em_address;
m_BreakPoints.push_back(pt); m_BreakPoints.push_back(pt);
// jit.NotifyBreakpoint(em_address, true);
} }
} }
@ -121,11 +123,10 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
if ((*iter).iAddress == _iAddress) if ((*iter).iAddress == _iAddress)
{ {
m_BreakPoints.erase(iter); m_BreakPoints.erase(iter);
// jit.NotifyBreakpoint(em_address, false);
break; break;
} }
} }
Host_UpdateBreakPointView();
} }
void CBreakPoints::ClearAllBreakPoints() void CBreakPoints::ClearAllBreakPoints()

View File

@ -72,7 +72,7 @@ public:
static bool IsTempBreakPoint(u32 _iAddress); static bool IsTempBreakPoint(u32 _iAddress);
// AddBreakPoint // AddBreakPoint
static void AddBreakPoint(u32 _iAddress, bool temp=false); static void AddBreakPoint(u32 em_address, bool temp=false);
// Remove Breakpoint // Remove Breakpoint
static void RemoveBreakPoint(u32 _iAddress); static void RemoveBreakPoint(u32 _iAddress);

View File

@ -757,9 +757,9 @@ bool AreMemoryBreakpointsActivated()
} }
u32 Read_Instruction(const u32 _Address) u32 Read_Instruction(const u32 em_address)
{ {
return jit.GetOriginalCode(_Address); return jit.GetBlockCache()->GetOriginalCode(em_address);
} }
u32 Read_Opcode(const u32 _Address) u32 Read_Opcode(const u32 _Address)

View File

@ -340,7 +340,7 @@ void icbi(UGeckoInstruction _inst)
// VERY IMPORTANT when we start linking blocks // VERY IMPORTANT when we start linking blocks
// There are a TON of these so hopefully we can make this mechanism // There are a TON of these so hopefully we can make this mechanism
// fast in the JIT // fast in the JIT
jit.InvalidateCodeRange(address, 0x20); jit.GetBlockCache()->InvalidateCodeRange(address, 0x20);
} }
void lbzux(UGeckoInstruction _inst) void lbzux(UGeckoInstruction _inst)

View File

@ -196,20 +196,28 @@ namespace CPUCompare
trampolines.Init(); trampolines.Init();
AllocCodeSpace(CODE_SIZE); AllocCodeSpace(CODE_SIZE);
InitCache();
blocks.Init();
asm_routines.Init(); asm_routines.Init();
} }
void Jit64::Shutdown() void Jit64::Shutdown()
{ {
FreeCodeSpace(); FreeCodeSpace();
ShutdownCache();
blocks.Shutdown();
trampolines.Shutdown(); trampolines.Shutdown();
asm_routines.Shutdown(); asm_routines.Shutdown();
} }
void Jit64::WriteCallInterpreter(UGeckoInstruction _inst) void Jit64::EnterFastRun()
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
//Will return when PowerPC::state changes
}
void Jit64::WriteCallInterpreter(UGeckoInstruction inst)
{ {
gpr.Flush(FLUSH_ALL); gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL);
@ -218,8 +226,14 @@ namespace CPUCompare
MOV(32, M(&PC), Imm32(js.compilerPC)); MOV(32, M(&PC), Imm32(js.compilerPC));
MOV(32, M(&NPC), Imm32(js.compilerPC + 4)); MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
} }
Interpreter::_interpreterInstruction instr = GetInterpreterOp(_inst); Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
ABI_CallFunctionC((void*)instr, _inst.hex); ABI_CallFunctionC((void*)instr, inst.hex);
}
void Jit64::unknown_instruction(UGeckoInstruction inst)
{
// CCPU::Break();
PanicAlert("unknown_instruction %08x - Fix me ;)", inst.hex);
} }
void Jit64::Default(UGeckoInstruction _inst) void Jit64::Default(UGeckoInstruction _inst)
@ -286,11 +300,11 @@ namespace CPUCompare
b->exitPtrs[exit_num] = GetWritableCodePtr(); b->exitPtrs[exit_num] = GetWritableCodePtr();
// Link opportunity! // Link opportunity!
int block = GetBlockNumberFromAddress(destination); int block = blocks.GetBlockNumberFromAddress(destination);
if (block >= 0 && jo.enableBlocklink) if (block >= 0 && jo.enableBlocklink)
{ {
// It exists! Joy of joy! // It exists! Joy of joy!
JMP(GetBlock(block)->checkedEntry, true); JMP(blocks.GetBlock(block)->checkedEntry, true);
b->linkStatus[exit_num] = true; b->linkStatus[exit_num] = true;
} }
else else
@ -323,6 +337,21 @@ namespace CPUCompare
MOV(32, M(&PC), Imm32(js.compilerPC + 4)); MOV(32, M(&PC), Imm32(js.compilerPC + 4));
JMP(asm_routines.testExceptions, true); JMP(asm_routines.testExceptions, true);
} }
const u8 *Jit64::Jit(u32 em_address)
{
if (GetSpaceLeft() < 0x10000 || blocks.IsFull())
{
LOG(DYNA_REC, "JIT cache full - clearing.")
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
{
PanicAlert("What? JIT cache still full - clearing.");
}
ClearCache();
}
return blocks.Jit(em_address);
}
const u8* Jit64::DoJit(u32 emaddress, JitBlock &b) const u8* Jit64::DoJit(u32 emaddress, JitBlock &b)
{ {

View File

@ -71,37 +71,7 @@ public:
class Jit64 : public Gen::XCodeBlock class Jit64 : public Gen::XCodeBlock
{ {
public:
// TODO(ector) - optimize this struct for size
struct JitBlock
{
u32 exitAddress[2]; // 0xFFFFFFFF == unknown
u8 *exitPtrs[2]; // to be able to rewrite the exit jump
bool linkStatus[2];
u32 originalAddress;
u32 originalFirstOpcode; //to be able to restore
u32 codeSize;
u32 originalSize;
int runCount; // for profiling.
#ifdef _WIN32
// we don't really need to save start and stop
// TODO (mb2): ticStart and ticStop -> "local var" mean "in block" ... low priority ;)
LARGE_INTEGER ticStart; // for profiling - time.
LARGE_INTEGER ticStop; // for profiling - time.
LARGE_INTEGER ticCounter; // for profiling - time.
#endif
const u8 *checkedEntry;
bool invalid;
int flags;
};
private: private:
enum BlockFlag
{
BLOCK_USE_GQR0 = 0x1, BLOCK_USE_GQR1 = 0x2, BLOCK_USE_GQR2 = 0x4, BLOCK_USE_GQR3 = 0x8,
BLOCK_USE_GQR4 = 0x10, BLOCK_USE_GQR5 = 0x20, BLOCK_USE_GQR6 = 0x40, BLOCK_USE_GQR7 = 0x80,
};
struct JitState struct JitState
{ {
u32 compilerPC; u32 compilerPC;
@ -139,20 +109,14 @@ private:
bool accurateSinglePrecision; bool accurateSinglePrecision;
}; };
JitBlockCache blocks;
TrampolineCache trampolines; TrampolineCache trampolines;
GPRRegCache gpr; GPRRegCache gpr;
FPURegCache fpr; FPURegCache fpr;
u8 **blockCodePointers;
std::multimap<u32, int> links_to;
JitBlock *blocks;
int numBlocks;
public: public:
typedef void (*CompiledCode)(); Jit64() {blocks.SetJit(this);}
~Jit64() {}
JitState js; JitState js;
JitOptions jo; JitOptions jo;
@ -162,40 +126,24 @@ public:
void Init(); void Init();
void Shutdown(); void Shutdown();
void PrintStats();
// Jit! // Jit!
const u8* Jit(u32 emaddress); const u8 *Jit(u32 emAddress); // 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 emaddress, JitBlock &b);
JitBlockCache *GetBlockCache() { return &blocks; }
void ClearCache()
{
blocks.Clear();
trampolines.ClearCodeSpace();
}
// 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 emAddress, CONTEXT *ctx);
// Code Cache
u32 GetOriginalCode(u32 address);
JitBlock *GetBlock(int no);
void InvalidateCodeRange(u32 address, u32 length);
int GetBlockNumberFromAddress(u32 address);
CompiledCode GetCompiledCode(u32 address);
CompiledCode GetCompiledCodeFromBlock(int blockNumber);
int GetCodeSize();
int GetNumBlocks();
u8 **GetCodePointers();
void DestroyBlocksWithFlag(BlockFlag death_flag);
void LinkBlocks();
void LinkBlockExits(int i);
void LinkBlock(int i);
void ClearCache();
void InitCache();
void ShutdownCache();
void ResetCache();
void DestroyBlock(int blocknum, bool invalidate);
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
#define JIT_OPCODE 0 #define JIT_OPCODE 0
// Utilities for use by opcodes // Utilities for use by opcodes

View File

@ -169,10 +169,8 @@ void AsmRoutineManager::Generate()
ABI_PushAllCalleeSavedRegsAndAdjustStack(); ABI_PushAllCalleeSavedRegsAndAdjustStack();
if (!jit.GetCodePointers() || !Memory::base)
PanicAlert("Memory::base and jit.GetCodePointers() must return valid values");
MOV(64, R(RBX), Imm64((u64)Memory::base)); MOV(64, R(RBX), Imm64((u64)Memory::base));
MOV(64, R(R15), Imm64((u64)jit.GetCodePointers())); //It's below 2GB so 32 bits are good enough MOV(64, R(R15), Imm64((u64)jit.GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough
const u8 *outerLoop = GetCodePtr(); const u8 *outerLoop = GetCodePtr();
CALL((void *)&CoreTiming::Advance); CALL((void *)&CoreTiming::Advance);

View File

@ -204,7 +204,7 @@ const u8 *Jit64::BackPatch(u8 *codePtr, int accessType, u32 emAddress, CONTEXT *
if (info.instructionSize < 3) if (info.instructionSize < 3)
PanicAlert("instruction too small"); PanicAlert("instruction too small");
// We entered here with a BSWAP-ed EAX. We'll have to swap it back. // We entered here with a BSWAP-ed EAX. We'll have to swap it back.
ctx->Rax = Common::swap32(ctx->Rax); ctx->Rax = Common::swap32((u32)ctx->Rax);
return codePtr - 2; return codePtr - 2;
} }
return 0; return 0;

View File

@ -24,8 +24,6 @@
//#define OPROFILE_REPORT //#define OPROFILE_REPORT
#include <map>
#include "Common.h" #include "Common.h"
#include "../../Core.h" #include "../../Core.h"
#include "MemoryUtil.h" #include "MemoryUtil.h"
@ -50,31 +48,23 @@
#include <opagent.h> #include <opagent.h>
#endif #endif
using namespace Gen;
#ifdef OPROFILE_REPORT #ifdef OPROFILE_REPORT
op_agent_t agent; op_agent_t agent;
#endif #endif
using namespace Gen;
#define INVALID_EXIT 0xFFFFFFFF #define INVALID_EXIT 0xFFFFFFFF
enum
bool JitBlockCache::IsFull() const
{ {
TRAMPOLINE_SIZE = 1024*1024, return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
};
int MAX_NUM_BLOCKS = 65536*2;
void Jit64::PrintStats()
{
LOG(DYNA_REC, "JIT Statistics =======================");
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
LOG(DYNA_REC, "======================================");
} }
void Jit64::InitCache() void JitBlockCache::Init()
{ {
MAX_NUM_BLOCKS = 65536*2;
if (Core::g_CoreStartupParameter.bJITUnlimitedCache) if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
{ {
MAX_NUM_BLOCKS = 65536*8; MAX_NUM_BLOCKS = 65536*8;
@ -86,10 +76,10 @@ using namespace Gen;
blocks = new JitBlock[MAX_NUM_BLOCKS]; blocks = new JitBlock[MAX_NUM_BLOCKS];
blockCodePointers = new u8*[MAX_NUM_BLOCKS]; blockCodePointers = new u8*[MAX_NUM_BLOCKS];
ClearCache(); Clear();
} }
void Jit64::ShutdownCache() void JitBlockCache::Shutdown()
{ {
delete [] blocks; delete [] blocks;
delete [] blockCodePointers; delete [] blockCodePointers;
@ -103,7 +93,7 @@ using namespace Gen;
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache // This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
// is full and when saving and loading states. // is full and when saving and loading states.
void Jit64::ClearCache() void JitBlockCache::Clear()
{ {
Core::DisplayMessage("Cleared code cache.", 3000); Core::DisplayMessage("Cleared code cache.", 3000);
// Is destroying the blocks really necessary? // Is destroying the blocks really necessary?
@ -114,11 +104,9 @@ using namespace Gen;
links_to.clear(); links_to.clear();
numBlocks = 0; numBlocks = 0;
memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS);
trampolines.ClearCodeSpace();
} }
void Jit64::DestroyBlocksWithFlag(BlockFlag death_flag) void JitBlockCache::DestroyBlocksWithFlag(BlockFlag death_flag)
{ {
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++)
{ {
@ -129,23 +117,23 @@ using namespace Gen;
} }
} }
void Jit64::ResetCache() void JitBlockCache::Reset()
{ {
ShutdownCache(); Shutdown();
InitCache(); Init();
} }
Jit64::JitBlock *Jit64::GetBlock(int no) JitBlock *JitBlockCache::GetBlock(int no)
{ {
return &blocks[no]; return &blocks[no];
} }
int Jit64::GetNumBlocks() int JitBlockCache::GetNumBlocks() const
{ {
return numBlocks; return numBlocks;
} }
bool Jit64::RangeIntersect(int s1, int e1, int s2, int e2) const bool JitBlockCache::RangeIntersect(int s1, int e1, int s2, int e2) const
{ {
// check if any endpoint is inside the other range // check if any endpoint is inside the other range
if ( (s1 >= s2 && s1 <= e2) || if ( (s1 >= s2 && s1 <= e2) ||
@ -162,18 +150,8 @@ using namespace Gen;
return jit.Jit(emAddress); return jit.Jit(emAddress);
} }
const u8 *Jit64::Jit(u32 emAddress) const u8 *JitBlockCache::Jit(u32 emAddress)
{ {
if (GetSpaceLeft() < 0x10000 || numBlocks >= MAX_NUM_BLOCKS - 1)
{
LOG(DYNA_REC, "JIT cache full - clearing.")
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
{
PanicAlert("What? JIT cache still full - clearing.");
}
ClearCache();
}
JitBlock &b = blocks[numBlocks]; JitBlock &b = blocks[numBlocks];
b.invalid = false; b.invalid = false;
b.originalAddress = emAddress; b.originalAddress = emAddress;
@ -185,10 +163,10 @@ using namespace Gen;
b.linkStatus[0] = false; b.linkStatus[0] = false;
b.linkStatus[1] = false; b.linkStatus[1] = false;
blockCodePointers[numBlocks] = (u8*)DoJit(emAddress, b); //cast away const blockCodePointers[numBlocks] = (u8*)jit->DoJit(emAddress, b); //cast away const
Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emAddress); Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | numBlocks, emAddress);
if (jo.enableBlocklink) { if (jit->jo.enableBlocklink) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (b.exitAddress[i] != INVALID_EXIT) { if (b.exitAddress[i] != INVALID_EXIT) {
links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks)); links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks));
@ -211,26 +189,12 @@ using namespace Gen;
return 0; return 0;
} }
void Jit64::unknown_instruction(UGeckoInstruction _inst) u8 **JitBlockCache::GetCodePointers()
{
// CCPU::Break();
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
_dbg_assert_(DYNA_REC, 0);
}
u8 **Jit64::GetCodePointers()
{ {
return blockCodePointers; return blockCodePointers;
} }
void Jit64::EnterFastRun() int JitBlockCache::GetBlockNumberFromAddress(u32 addr)
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
//Will return when PowerPC::state changes
}
int Jit64::GetBlockNumberFromAddress(u32 addr)
{ {
if (!blocks) if (!blocks)
return -1; return -1;
@ -256,7 +220,7 @@ using namespace Gen;
} }
} }
u32 Jit64::GetOriginalCode(u32 address) u32 JitBlockCache::GetOriginalCode(u32 address)
{ {
int num = GetBlockNumberFromAddress(address); int num = GetBlockNumberFromAddress(address);
if (num == -1) if (num == -1)
@ -265,7 +229,7 @@ using namespace Gen;
return blocks[num].originalFirstOpcode; return blocks[num].originalFirstOpcode;
} }
Jit64::CompiledCode Jit64::GetCompiledCode(u32 address) CompiledCode JitBlockCache::GetCompiledCode(u32 address)
{ {
int num = GetBlockNumberFromAddress(address); int num = GetBlockNumberFromAddress(address);
if (num == -1) if (num == -1)
@ -274,7 +238,7 @@ using namespace Gen;
return (CompiledCode)blockCodePointers[num]; return (CompiledCode)blockCodePointers[num];
} }
Jit64::CompiledCode Jit64::GetCompiledCodeFromBlock(int blockNumber) CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int blockNumber)
{ {
return (CompiledCode)blockCodePointers[blockNumber]; return (CompiledCode)blockCodePointers[blockNumber];
} }
@ -285,7 +249,7 @@ using namespace Gen;
//Can be faster by doing a queue for blocks to link up, and only process those //Can be faster by doing a queue for blocks to link up, and only process those
//Should probably be done //Should probably be done
void Jit64::LinkBlockExits(int i) void JitBlockCache::LinkBlockExits(int i)
{ {
JitBlock &b = blocks[i]; JitBlock &b = blocks[i];
if (b.invalid) if (b.invalid)
@ -310,10 +274,10 @@ using namespace Gen;
using namespace std; using namespace std;
void Jit64::LinkBlock(int i) void JitBlockCache::LinkBlock(int i)
{ {
LinkBlockExits(i); LinkBlockExits(i);
Jit64::JitBlock &b = blocks[i]; JitBlock &b = blocks[i];
std::map<u32, int>::iterator iter; std::map<u32, int>::iterator iter;
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp; pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
// equal_range(b) returns pair<iterator,iterator> representing the range // equal_range(b) returns pair<iterator,iterator> representing the range
@ -327,10 +291,10 @@ using namespace Gen;
} }
} }
void Jit64::DestroyBlock(int blocknum, bool invalidate) void JitBlockCache::DestroyBlock(int blocknum, bool invalidate)
{ {
u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i
Jit64::JitBlock &b = blocks[blocknum]; JitBlock &b = blocks[blocknum];
b.invalid = 1; b.invalid = 1;
if (codebytes == Memory::ReadFast32(b.originalAddress)) if (codebytes == Memory::ReadFast32(b.originalAddress))
{ {
@ -363,9 +327,9 @@ using namespace Gen;
} }
void Jit64::InvalidateCodeRange(u32 address, u32 length) void JitBlockCache::InvalidateCodeRange(u32 address, u32 length)
{ {
if (!jo.enableBlocklink) if (!jit->jo.enableBlocklink)
return; return;
return; return;
//This is slow but should be safe (zelda needs it for block linking) //This is slow but should be safe (zelda needs it for block linking)

View File

@ -17,8 +17,87 @@
#ifndef _JITCACHE_H #ifndef _JITCACHE_H
#define _JITCACHE_H #define _JITCACHE_H
#include <map>
#include "../Gekko.h" #include "../Gekko.h"
// Will soon introduce the JitBlockCache class here. #ifdef _WIN32
#include <windows.h>
#endif
enum BlockFlag
{
BLOCK_USE_GQR0 = 0x1, BLOCK_USE_GQR1 = 0x2, BLOCK_USE_GQR2 = 0x4, BLOCK_USE_GQR3 = 0x8,
BLOCK_USE_GQR4 = 0x10, BLOCK_USE_GQR5 = 0x20, BLOCK_USE_GQR6 = 0x40, BLOCK_USE_GQR7 = 0x80,
};
// TODO(ector) - optimize this struct for size
struct JitBlock
{
u32 exitAddress[2]; // 0xFFFFFFFF == unknown
u8 *exitPtrs[2]; // to be able to rewrite the exit jump
bool linkStatus[2];
u32 originalAddress;
u32 originalFirstOpcode; //to be able to restore
u32 codeSize;
u32 originalSize;
int runCount; // for profiling.
#ifdef _WIN32
// we don't really need to save start and stop
// TODO (mb2): ticStart and ticStop -> "local var" mean "in block" ... low priority ;)
LARGE_INTEGER ticStart; // for profiling - time.
LARGE_INTEGER ticStop; // for profiling - time.
LARGE_INTEGER ticCounter; // for profiling - time.
#endif
const u8 *checkedEntry;
bool invalid;
int flags;
};
class Jit64;
typedef void (*CompiledCode)();
class JitBlockCache
{
Jit64 *jit;
u8 **blockCodePointers;
JitBlock *blocks;
int numBlocks;
std::multimap<u32, int> links_to;
int MAX_NUM_BLOCKS;
public:
JitBlockCache() {}
void SetJit(Jit64 *jit_) { jit = jit_; }
const u8* Jit(u32 emaddress);
void Clear();
void Init();
void Shutdown();
void Reset();
bool IsFull() const;
// Code Cache
u32 GetOriginalCode(u32 address);
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;
u8 **GetCodePointers();
void DestroyBlocksWithFlag(BlockFlag death_flag);
void LinkBlocks();
void LinkBlockExits(int i);
void LinkBlock(int i);
void DestroyBlock(int blocknum, bool invalidate);
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
};
#endif #endif

View File

@ -131,18 +131,6 @@
} }
} }
/*
if (js.next_inst.OPCD == 16) { // bcx
if (!js.next_inst.LK && (js.next_inst.BO & BO_DONT_DECREMENT_FLAG))
{
// it's clear there's plenty of opportunity.
//PanicAlert("merge");
}
}
*/
// unsigned
void Jit64::cmpXX(UGeckoInstruction inst) void Jit64::cmpXX(UGeckoInstruction inst)
{ {
// USES_CR // USES_CR

View File

@ -41,16 +41,16 @@ struct BlockStat
void WriteProfileResults(const char *filename) { void WriteProfileResults(const char *filename) {
std::vector<BlockStat> stats; std::vector<BlockStat> stats;
stats.reserve(jit.GetNumBlocks()); stats.reserve(jit.GetBlockCache()->GetNumBlocks());
u64 cost_sum = 0; u64 cost_sum = 0;
#ifdef _WIN32 #ifdef _WIN32
u64 timecost_sum = 0; u64 timecost_sum = 0;
LARGE_INTEGER countsPerSec; LARGE_INTEGER countsPerSec;
QueryPerformanceFrequency(&countsPerSec); QueryPerformanceFrequency(&countsPerSec);
#endif #endif
for (int i = 0; i < jit.GetNumBlocks(); i++) for (int i = 0; i < jit.GetBlockCache()->GetNumBlocks(); i++)
{ {
const Jit64::JitBlock *block = jit.GetBlock(i); const JitBlock *block = jit.GetBlockCache()->GetBlock(i);
u64 cost = (block->originalSize / 4) * block->runCount; // rough heuristic. mem instructions should cost more. u64 cost = (block->originalSize / 4) * block->runCount; // rough heuristic. mem instructions should cost more.
#ifdef _WIN32 #ifdef _WIN32
u64 timecost = block->ticCounter.QuadPart; // Indeed ;) u64 timecost = block->ticCounter.QuadPart; // Indeed ;)
@ -73,8 +73,9 @@ void WriteProfileResults(const char *filename) {
fprintf(f, "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); fprintf(f, "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n");
for (unsigned int i = 0; i < stats.size(); i++) for (unsigned int i = 0; i < stats.size(); i++)
{ {
const Jit64::JitBlock *block = jit.GetBlock(stats[i].blockNum); const JitBlock *block = jit.GetBlockCache()->GetBlock(stats[i].blockNum);
if (block) { if (block)
{
std::string name = g_symbolDB.GetDescription(block->originalAddress); std::string name = g_symbolDB.GetDescription(block->originalAddress);
double percent = 100.0 * (double)stats[i].cost / (double)cost_sum; double percent = 100.0 * (double)stats[i].cost / (double)cost_sum;
#ifdef _WIN32 #ifdef _WIN32
@ -90,4 +91,4 @@ void WriteProfileResults(const char *filename) {
fclose(f); fclose(f);
} }
} } // namespace

View File

@ -97,7 +97,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
p.SetMode(PointerWrap::MODE_WRITE); p.SetMode(PointerWrap::MODE_WRITE);
DoState(p); DoState(p);
if(bCompressed) { if (bCompressed) {
fwrite(&sz, sizeof(int), 1, f); fwrite(&sz, sizeof(int), 1, f);
} else { } else {
int zero = 0; int zero = 0;
@ -105,7 +105,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
} }
if(bCompressed) { if (bCompressed) {
if (lzo_init() != LZO_E_OK) if (lzo_init() != LZO_E_OK)
PanicAlert("Internal LZO Error - lzo_init() failed"); PanicAlert("Internal LZO Error - lzo_init() failed");
else { else {
@ -163,15 +163,15 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
bCompressedState = (sz != 0); bCompressedState = (sz != 0);
if(bCompressedState) { if (bCompressedState) {
if (lzo_init() != LZO_E_OK) if (lzo_init() != LZO_E_OK)
PanicAlert("Internal LZO Error - lzo_init() failed"); PanicAlert("Internal LZO Error - lzo_init() failed");
else { else {
lzo_uint i = 0; lzo_uint i = 0;
buffer = new u8[sz]; buffer = new u8[sz];
for(;;) { for (;;) {
if(fread(&cur_len, 1, sizeof(int), f) == 0) if (fread(&cur_len, 1, sizeof(int), f) == 0)
break; break;
fread(out, 1, cur_len, f); fread(out, 1, cur_len, f);
@ -216,7 +216,8 @@ void State_Shutdown()
// nothing to do, here for consistency. // nothing to do, here for consistency.
} }
std::string MakeStateFilename(int state_number) { std::string MakeStateFilename(int state_number)
{
return StringFromFormat(FULL_STATESAVES_DIR "%s.s%02i", Core::GetStartupParameter().GetUniqueID().c_str(), state_number); return StringFromFormat(FULL_STATESAVES_DIR "%s.s%02i", Core::GetStartupParameter().GetUniqueID().c_str(), state_number);
} }

View File

@ -496,7 +496,9 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
// creates the SCoreStartupParameter as a game is loaded // creates the SCoreStartupParameter as a game is loaded
GetMenuBar()->Check(event.GetId(),!event.IsChecked()); GetMenuBar()->Check(event.GetId(),!event.IsChecked());
wxMessageBox(_T("Please start a game before changing mode.")); wxMessageBox(_T("Please start a game before changing mode."));
} else { }
else
{
if (Core::GetState() != Core::CORE_RUN) if (Core::GetState() != Core::CORE_RUN)
{ {
switch (event.GetId()) switch (event.GetId())
@ -504,9 +506,8 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
case IDM_JITUNLIMITED: case IDM_JITUNLIMITED:
Core::g_CoreStartupParameter.bJITUnlimitedCache = event.IsChecked(); Core::g_CoreStartupParameter.bJITUnlimitedCache = event.IsChecked();
jit.ClearCache(); // allow InitCache() even after the game has started jit.ClearCache(); // allow InitCache() even after the game has started
jit.InitCache();
GetMenuBar()->Enable(event.GetId(),!event.IsChecked()); GetMenuBar()->Enable(event.GetId(),!event.IsChecked());
break; return; // avoid a second jit.ClearCache
case IDM_JITOFF: case IDM_JITOFF:
Core::g_CoreStartupParameter.bJITOff = event.IsChecked(); break; Core::g_CoreStartupParameter.bJITOff = event.IsChecked(); break;
case IDM_JITLSOFF: case IDM_JITLSOFF:
@ -531,15 +532,15 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
Core::g_CoreStartupParameter.bJITSystemRegistersOff = event.IsChecked(); break; Core::g_CoreStartupParameter.bJITSystemRegistersOff = event.IsChecked(); break;
} }
jit.ClearCache(); jit.ClearCache();
} else { }
else
{
//event.Skip(); // this doesn't work //event.Skip(); // this doesn't work
GetMenuBar()->Check(event.GetId(),!event.IsChecked()); GetMenuBar()->Check(event.GetId(),!event.IsChecked());
wxMessageBox(_T("Please pause the emulator before changing mode.")); wxMessageBox(_T("Please pause the emulator before changing mode."));
} }
} }
} }
// ==============
void CCodeWindow::OnJitMenu(wxCommandEvent& event) void CCodeWindow::OnJitMenu(wxCommandEvent& event)
{ {

View File

@ -138,16 +138,16 @@ void CJitWindow::Compare(u32 em_address)
disassembler x64disasm; disassembler x64disasm;
x64disasm.set_syntax_intel(); x64disasm.set_syntax_intel();
int block_num = jit.GetBlockNumberFromAddress(em_address); int block_num = jit.GetBlockCache()->GetBlockNumberFromAddress(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.GetBlockNumberFromAddress(em_address - 4 * i); block_num = jit.GetBlockCache()->GetBlockNumberFromAddress(em_address - 4 * i);
if (block_num >= 0) if (block_num >= 0)
break; break;
} }
if (block_num >= 0) { if (block_num >= 0) {
Jit64::JitBlock *block = jit.GetBlock(block_num); JitBlock *block = jit.GetBlockCache()->GetBlock(block_num);
if (!(block->originalAddress <= em_address && block->originalSize + block->originalAddress >= em_address)) if (!(block->originalAddress <= em_address && block->originalSize + block->originalAddress >= em_address))
block_num = -1; block_num = -1;
} }
@ -158,13 +158,13 @@ void CJitWindow::Compare(u32 em_address)
return; return;
} }
} }
Jit64::JitBlock *block = jit.GetBlock(block_num); JitBlock *block = jit.GetBlockCache()->GetBlock(block_num);
// 800031f0 // 800031f0
// == Fill in x86 box // == Fill in x86 box
memset(xDis, 0, 65536); memset(xDis, 0, 65536);
const u8 *code = (const u8 *)jit.GetCompiledCodeFromBlock(block_num); const u8 *code = (const u8 *)jit.GetBlockCache()->GetCompiledCodeFromBlock(block_num);
u64 disasmPtr = (u64)code; u64 disasmPtr = (u64)code;
int size = block->codeSize; int size = block->codeSize;
const u8 *end = code + size; const u8 *end = code + size;