More code reorganization.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1605 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
f0bb8f430a
commit
614dc1069e
|
@ -35,12 +35,6 @@
|
|||
|
||||
void Console_Submit(const char *cmd)
|
||||
{
|
||||
CASE1("jits")
|
||||
{
|
||||
#ifdef _M_X64
|
||||
jit.PrintStats();
|
||||
#endif
|
||||
}
|
||||
CASE1("r")
|
||||
{
|
||||
Core::StartTrace(false);
|
||||
|
@ -57,7 +51,7 @@ void Console_Submit(const char *cmd)
|
|||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
|
||||
if (addr!=0)
|
||||
if (addr)
|
||||
{
|
||||
#ifdef LOGGING
|
||||
u32 EA =
|
||||
|
@ -75,7 +69,7 @@ void Console_Submit(const char *cmd)
|
|||
TCHAR temp[256];
|
||||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
if (addr!=0)
|
||||
if (addr)
|
||||
{
|
||||
g_symbolDB.PrintCalls(addr);
|
||||
}
|
||||
|
@ -89,7 +83,7 @@ void Console_Submit(const char *cmd)
|
|||
TCHAR temp[256];
|
||||
u32 addr;
|
||||
sscanf(cmd, "%s %08x", temp, &addr);
|
||||
if (addr!=0)
|
||||
if (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);
|
||||
|
||||
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);
|
||||
fputc(b,f);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "../HW/CPU.h"
|
||||
#include "../Host.h"
|
||||
#include "../PowerPC/SymbolDB.h"
|
||||
#include "../PowerPC/Jit64/Jit.h"
|
||||
#include "Debugger_BreakPoints.h"
|
||||
|
||||
CBreakPoints::TBreakPoints CBreakPoints::m_BreakPoints;
|
||||
|
@ -90,7 +91,7 @@ TMemCheck *CBreakPoints::GetMemCheck(u32 address)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((*iter).StartAddress==address)
|
||||
if ((*iter).StartAddress == address)
|
||||
return &(*iter);
|
||||
}
|
||||
}
|
||||
|
@ -99,16 +100,17 @@ TMemCheck *CBreakPoints::GetMemCheck(u32 address)
|
|||
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
|
||||
pt.bOn = true;
|
||||
pt.bTemporary = temp;
|
||||
pt.iAddress = _iAddress;
|
||||
pt.iAddress = em_address;
|
||||
|
||||
m_BreakPoints.push_back(pt);
|
||||
// jit.NotifyBreakpoint(em_address, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,11 +123,10 @@ void CBreakPoints::RemoveBreakPoint(u32 _iAddress)
|
|||
if ((*iter).iAddress == _iAddress)
|
||||
{
|
||||
m_BreakPoints.erase(iter);
|
||||
// jit.NotifyBreakpoint(em_address, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Host_UpdateBreakPointView();
|
||||
}
|
||||
|
||||
void CBreakPoints::ClearAllBreakPoints()
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
static bool IsTempBreakPoint(u32 _iAddress);
|
||||
|
||||
// AddBreakPoint
|
||||
static void AddBreakPoint(u32 _iAddress, bool temp=false);
|
||||
static void AddBreakPoint(u32 em_address, bool temp=false);
|
||||
|
||||
// Remove Breakpoint
|
||||
static void RemoveBreakPoint(u32 _iAddress);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -340,7 +340,7 @@ void icbi(UGeckoInstruction _inst)
|
|||
// VERY IMPORTANT when we start linking blocks
|
||||
// There are a TON of these so hopefully we can make this mechanism
|
||||
// fast in the JIT
|
||||
jit.InvalidateCodeRange(address, 0x20);
|
||||
jit.GetBlockCache()->InvalidateCodeRange(address, 0x20);
|
||||
}
|
||||
|
||||
void lbzux(UGeckoInstruction _inst)
|
||||
|
|
|
@ -196,20 +196,28 @@ namespace CPUCompare
|
|||
|
||||
trampolines.Init();
|
||||
AllocCodeSpace(CODE_SIZE);
|
||||
InitCache();
|
||||
|
||||
blocks.Init();
|
||||
asm_routines.Init();
|
||||
}
|
||||
|
||||
void Jit64::Shutdown()
|
||||
{
|
||||
FreeCodeSpace();
|
||||
ShutdownCache();
|
||||
|
||||
blocks.Shutdown();
|
||||
trampolines.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);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
|
@ -218,8 +226,14 @@ namespace CPUCompare
|
|||
MOV(32, M(&PC), Imm32(js.compilerPC));
|
||||
MOV(32, M(&NPC), Imm32(js.compilerPC + 4));
|
||||
}
|
||||
Interpreter::_interpreterInstruction instr = GetInterpreterOp(_inst);
|
||||
ABI_CallFunctionC((void*)instr, _inst.hex);
|
||||
Interpreter::_interpreterInstruction instr = GetInterpreterOp(inst);
|
||||
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)
|
||||
|
@ -286,11 +300,11 @@ namespace CPUCompare
|
|||
b->exitPtrs[exit_num] = GetWritableCodePtr();
|
||||
|
||||
// Link opportunity!
|
||||
int block = GetBlockNumberFromAddress(destination);
|
||||
int block = blocks.GetBlockNumberFromAddress(destination);
|
||||
if (block >= 0 && jo.enableBlocklink)
|
||||
{
|
||||
// It exists! Joy of joy!
|
||||
JMP(GetBlock(block)->checkedEntry, true);
|
||||
JMP(blocks.GetBlock(block)->checkedEntry, true);
|
||||
b->linkStatus[exit_num] = true;
|
||||
}
|
||||
else
|
||||
|
@ -323,6 +337,21 @@ namespace CPUCompare
|
|||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -71,37 +71,7 @@ public:
|
|||
|
||||
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:
|
||||
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
|
||||
{
|
||||
u32 compilerPC;
|
||||
|
@ -139,20 +109,14 @@ private:
|
|||
bool accurateSinglePrecision;
|
||||
};
|
||||
|
||||
|
||||
JitBlockCache blocks;
|
||||
TrampolineCache trampolines;
|
||||
GPRRegCache gpr;
|
||||
FPURegCache fpr;
|
||||
|
||||
u8 **blockCodePointers;
|
||||
|
||||
std::multimap<u32, int> links_to;
|
||||
|
||||
JitBlock *blocks;
|
||||
int numBlocks;
|
||||
|
||||
public:
|
||||
typedef void (*CompiledCode)();
|
||||
Jit64() {blocks.SetJit(this);}
|
||||
~Jit64() {}
|
||||
|
||||
JitState js;
|
||||
JitOptions jo;
|
||||
|
@ -162,40 +126,24 @@ public:
|
|||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
void PrintStats();
|
||||
|
||||
// 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);
|
||||
|
||||
JitBlockCache *GetBlockCache() { return &blocks; }
|
||||
|
||||
void ClearCache()
|
||||
{
|
||||
blocks.Clear();
|
||||
trampolines.ClearCodeSpace();
|
||||
}
|
||||
|
||||
// Run!
|
||||
|
||||
void EnterFastRun();
|
||||
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
|
||||
|
||||
// Utilities for use by opcodes
|
||||
|
|
|
@ -169,10 +169,8 @@ void AsmRoutineManager::Generate()
|
|||
|
||||
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(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();
|
||||
|
||||
CALL((void *)&CoreTiming::Advance);
|
||||
|
|
|
@ -204,7 +204,7 @@ const u8 *Jit64::BackPatch(u8 *codePtr, int accessType, u32 emAddress, CONTEXT *
|
|||
if (info.instructionSize < 3)
|
||||
PanicAlert("instruction too small");
|
||||
// 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 0;
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
//#define OPROFILE_REPORT
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Common.h"
|
||||
#include "../../Core.h"
|
||||
#include "MemoryUtil.h"
|
||||
|
@ -50,31 +48,23 @@
|
|||
#include <opagent.h>
|
||||
#endif
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
#ifdef OPROFILE_REPORT
|
||||
op_agent_t agent;
|
||||
#endif
|
||||
|
||||
using namespace Gen;
|
||||
|
||||
#define INVALID_EXIT 0xFFFFFFFF
|
||||
|
||||
enum
|
||||
|
||||
bool JitBlockCache::IsFull() const
|
||||
{
|
||||
TRAMPOLINE_SIZE = 1024*1024,
|
||||
};
|
||||
|
||||
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, "======================================");
|
||||
return GetNumBlocks() >= MAX_NUM_BLOCKS - 1;
|
||||
}
|
||||
|
||||
void Jit64::InitCache()
|
||||
void JitBlockCache::Init()
|
||||
{
|
||||
MAX_NUM_BLOCKS = 65536*2;
|
||||
if (Core::g_CoreStartupParameter.bJITUnlimitedCache)
|
||||
{
|
||||
MAX_NUM_BLOCKS = 65536*8;
|
||||
|
@ -86,10 +76,10 @@ using namespace Gen;
|
|||
blocks = new JitBlock[MAX_NUM_BLOCKS];
|
||||
blockCodePointers = new u8*[MAX_NUM_BLOCKS];
|
||||
|
||||
ClearCache();
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Jit64::ShutdownCache()
|
||||
void JitBlockCache::Shutdown()
|
||||
{
|
||||
delete [] blocks;
|
||||
delete [] blockCodePointers;
|
||||
|
@ -103,7 +93,7 @@ using namespace Gen;
|
|||
|
||||
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
|
||||
// is full and when saving and loading states.
|
||||
void Jit64::ClearCache()
|
||||
void JitBlockCache::Clear()
|
||||
{
|
||||
Core::DisplayMessage("Cleared code cache.", 3000);
|
||||
// Is destroying the blocks really necessary?
|
||||
|
@ -114,11 +104,9 @@ using namespace Gen;
|
|||
links_to.clear();
|
||||
numBlocks = 0;
|
||||
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++)
|
||||
{
|
||||
|
@ -129,23 +117,23 @@ using namespace Gen;
|
|||
}
|
||||
}
|
||||
|
||||
void Jit64::ResetCache()
|
||||
void JitBlockCache::Reset()
|
||||
{
|
||||
ShutdownCache();
|
||||
InitCache();
|
||||
Shutdown();
|
||||
Init();
|
||||
}
|
||||
|
||||
Jit64::JitBlock *Jit64::GetBlock(int no)
|
||||
JitBlock *JitBlockCache::GetBlock(int no)
|
||||
{
|
||||
return &blocks[no];
|
||||
}
|
||||
|
||||
int Jit64::GetNumBlocks()
|
||||
int JitBlockCache::GetNumBlocks() const
|
||||
{
|
||||
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
|
||||
if ( (s1 >= s2 && s1 <= e2) ||
|
||||
|
@ -162,18 +150,8 @@ using namespace Gen;
|
|||
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];
|
||||
b.invalid = false;
|
||||
b.originalAddress = emAddress;
|
||||
|
@ -185,10 +163,10 @@ using namespace Gen;
|
|||
b.linkStatus[0] = 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);
|
||||
|
||||
if (jo.enableBlocklink) {
|
||||
if (jit->jo.enableBlocklink) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (b.exitAddress[i] != INVALID_EXIT) {
|
||||
links_to.insert(std::pair<u32, int>(b.exitAddress[i], numBlocks));
|
||||
|
@ -211,26 +189,12 @@ using namespace Gen;
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Jit64::unknown_instruction(UGeckoInstruction _inst)
|
||||
{
|
||||
// CCPU::Break();
|
||||
PanicAlert("unknown_instruction Jit64 - Fix me ;)");
|
||||
_dbg_assert_(DYNA_REC, 0);
|
||||
}
|
||||
|
||||
u8 **Jit64::GetCodePointers()
|
||||
u8 **JitBlockCache::GetCodePointers()
|
||||
{
|
||||
return blockCodePointers;
|
||||
}
|
||||
|
||||
void Jit64::EnterFastRun()
|
||||
{
|
||||
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
|
||||
pExecAddr();
|
||||
//Will return when PowerPC::state changes
|
||||
}
|
||||
|
||||
int Jit64::GetBlockNumberFromAddress(u32 addr)
|
||||
int JitBlockCache::GetBlockNumberFromAddress(u32 addr)
|
||||
{
|
||||
if (!blocks)
|
||||
return -1;
|
||||
|
@ -256,7 +220,7 @@ using namespace Gen;
|
|||
}
|
||||
}
|
||||
|
||||
u32 Jit64::GetOriginalCode(u32 address)
|
||||
u32 JitBlockCache::GetOriginalCode(u32 address)
|
||||
{
|
||||
int num = GetBlockNumberFromAddress(address);
|
||||
if (num == -1)
|
||||
|
@ -265,7 +229,7 @@ using namespace Gen;
|
|||
return blocks[num].originalFirstOpcode;
|
||||
}
|
||||
|
||||
Jit64::CompiledCode Jit64::GetCompiledCode(u32 address)
|
||||
CompiledCode JitBlockCache::GetCompiledCode(u32 address)
|
||||
{
|
||||
int num = GetBlockNumberFromAddress(address);
|
||||
if (num == -1)
|
||||
|
@ -274,7 +238,7 @@ using namespace Gen;
|
|||
return (CompiledCode)blockCodePointers[num];
|
||||
}
|
||||
|
||||
Jit64::CompiledCode Jit64::GetCompiledCodeFromBlock(int blockNumber)
|
||||
CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int 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
|
||||
//Should probably be done
|
||||
|
||||
void Jit64::LinkBlockExits(int i)
|
||||
void JitBlockCache::LinkBlockExits(int i)
|
||||
{
|
||||
JitBlock &b = blocks[i];
|
||||
if (b.invalid)
|
||||
|
@ -310,10 +274,10 @@ using namespace Gen;
|
|||
|
||||
using namespace std;
|
||||
|
||||
void Jit64::LinkBlock(int i)
|
||||
void JitBlockCache::LinkBlock(int i)
|
||||
{
|
||||
LinkBlockExits(i);
|
||||
Jit64::JitBlock &b = blocks[i];
|
||||
JitBlock &b = blocks[i];
|
||||
std::map<u32, int>::iterator iter;
|
||||
pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp;
|
||||
// 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
|
||||
Jit64::JitBlock &b = blocks[blocknum];
|
||||
JitBlock &b = blocks[blocknum];
|
||||
b.invalid = 1;
|
||||
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;
|
||||
//This is slow but should be safe (zelda needs it for block linking)
|
||||
|
|
|
@ -17,8 +17,87 @@
|
|||
#ifndef _JITCACHE_H
|
||||
#define _JITCACHE_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
// USES_CR
|
||||
|
|
|
@ -41,16 +41,16 @@ struct BlockStat
|
|||
|
||||
void WriteProfileResults(const char *filename) {
|
||||
std::vector<BlockStat> stats;
|
||||
stats.reserve(jit.GetNumBlocks());
|
||||
stats.reserve(jit.GetBlockCache()->GetNumBlocks());
|
||||
u64 cost_sum = 0;
|
||||
#ifdef _WIN32
|
||||
u64 timecost_sum = 0;
|
||||
LARGE_INTEGER countsPerSec;
|
||||
QueryPerformanceFrequency(&countsPerSec);
|
||||
#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.
|
||||
#ifdef _WIN32
|
||||
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");
|
||||
for (unsigned int i = 0; i < stats.size(); i++)
|
||||
{
|
||||
const Jit64::JitBlock *block = jit.GetBlock(stats[i].blockNum);
|
||||
if (block) {
|
||||
const JitBlock *block = jit.GetBlockCache()->GetBlock(stats[i].blockNum);
|
||||
if (block)
|
||||
{
|
||||
std::string name = g_symbolDB.GetDescription(block->originalAddress);
|
||||
double percent = 100.0 * (double)stats[i].cost / (double)cost_sum;
|
||||
#ifdef _WIN32
|
||||
|
@ -90,4 +91,4 @@ void WriteProfileResults(const char *filename) {
|
|||
fclose(f);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -97,7 +97,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
|
|||
p.SetMode(PointerWrap::MODE_WRITE);
|
||||
DoState(p);
|
||||
|
||||
if(bCompressed) {
|
||||
if (bCompressed) {
|
||||
fwrite(&sz, sizeof(int), 1, f);
|
||||
} else {
|
||||
int zero = 0;
|
||||
|
@ -105,7 +105,7 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
|
|||
}
|
||||
|
||||
|
||||
if(bCompressed) {
|
||||
if (bCompressed) {
|
||||
if (lzo_init() != LZO_E_OK)
|
||||
PanicAlert("Internal LZO Error - lzo_init() failed");
|
||||
else {
|
||||
|
@ -163,15 +163,15 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
|
|||
|
||||
bCompressedState = (sz != 0);
|
||||
|
||||
if(bCompressedState) {
|
||||
if (bCompressedState) {
|
||||
if (lzo_init() != LZO_E_OK)
|
||||
PanicAlert("Internal LZO Error - lzo_init() failed");
|
||||
else {
|
||||
lzo_uint i = 0;
|
||||
buffer = new u8[sz];
|
||||
|
||||
for(;;) {
|
||||
if(fread(&cur_len, 1, sizeof(int), f) == 0)
|
||||
for (;;) {
|
||||
if (fread(&cur_len, 1, sizeof(int), f) == 0)
|
||||
break;
|
||||
fread(out, 1, cur_len, f);
|
||||
|
||||
|
@ -216,7 +216,8 @@ void State_Shutdown()
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -496,7 +496,9 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
|
|||
// creates the SCoreStartupParameter as a game is loaded
|
||||
GetMenuBar()->Check(event.GetId(),!event.IsChecked());
|
||||
wxMessageBox(_T("Please start a game before changing mode."));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Core::GetState() != Core::CORE_RUN)
|
||||
{
|
||||
switch (event.GetId())
|
||||
|
@ -504,9 +506,8 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
|
|||
case IDM_JITUNLIMITED:
|
||||
Core::g_CoreStartupParameter.bJITUnlimitedCache = event.IsChecked();
|
||||
jit.ClearCache(); // allow InitCache() even after the game has started
|
||||
jit.InitCache();
|
||||
GetMenuBar()->Enable(event.GetId(),!event.IsChecked());
|
||||
break;
|
||||
return; // avoid a second jit.ClearCache
|
||||
case IDM_JITOFF:
|
||||
Core::g_CoreStartupParameter.bJITOff = event.IsChecked(); break;
|
||||
case IDM_JITLSOFF:
|
||||
|
@ -531,15 +532,15 @@ void CCodeWindow::OnJITOff(wxCommandEvent& event)
|
|||
Core::g_CoreStartupParameter.bJITSystemRegistersOff = event.IsChecked(); break;
|
||||
}
|
||||
jit.ClearCache();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
//event.Skip(); // this doesn't work
|
||||
GetMenuBar()->Check(event.GetId(),!event.IsChecked());
|
||||
wxMessageBox(_T("Please pause the emulator before changing mode."));
|
||||
}
|
||||
}
|
||||
}
|
||||
// ==============
|
||||
|
||||
|
||||
void CCodeWindow::OnJitMenu(wxCommandEvent& event)
|
||||
{
|
||||
|
|
|
@ -138,16 +138,16 @@ void CJitWindow::Compare(u32 em_address)
|
|||
disassembler x64disasm;
|
||||
x64disasm.set_syntax_intel();
|
||||
|
||||
int block_num = jit.GetBlockNumberFromAddress(em_address);
|
||||
int block_num = jit.GetBlockCache()->GetBlockNumberFromAddress(em_address);
|
||||
if (block_num < 0)
|
||||
{
|
||||
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)
|
||||
break;
|
||||
}
|
||||
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))
|
||||
block_num = -1;
|
||||
}
|
||||
|
@ -158,13 +158,13 @@ void CJitWindow::Compare(u32 em_address)
|
|||
return;
|
||||
}
|
||||
}
|
||||
Jit64::JitBlock *block = jit.GetBlock(block_num);
|
||||
JitBlock *block = jit.GetBlockCache()->GetBlock(block_num);
|
||||
|
||||
// 800031f0
|
||||
// == Fill in x86 box
|
||||
|
||||
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;
|
||||
int size = block->codeSize;
|
||||
const u8 *end = code + size;
|
||||
|
|
Loading…
Reference in New Issue