mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
small build fix in debug mode, misc cleanup
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1604 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@@ -189,6 +189,7 @@ namespace CPUCompare
|
||||
jo.fpAccurateFlags = true;
|
||||
jo.optimizeGatherPipe = true;
|
||||
jo.fastInterrupts = false;
|
||||
jo.accurateSinglePrecision = true;
|
||||
|
||||
gpr.SetEmitter(this);
|
||||
fpr.SetEmitter(this);
|
||||
@@ -328,6 +329,9 @@ namespace CPUCompare
|
||||
if (emaddress == 0)
|
||||
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
|
||||
|
||||
// if (emaddress == 0x800aa278)
|
||||
// DebugBreak();
|
||||
|
||||
int size;
|
||||
js.isLastInstruction = false;
|
||||
js.blockStart = emaddress;
|
||||
@@ -433,7 +437,8 @@ namespace CPUCompare
|
||||
CALL(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0));
|
||||
}
|
||||
|
||||
PPCTables::CompileInstruction(ops[i].inst);
|
||||
if (!ops[i].skip)
|
||||
PPCTables::CompileInstruction(ops[i].inst);
|
||||
|
||||
gpr.SanityCheck();
|
||||
fpr.SanityCheck();
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
// See comments in Jit.cpp.
|
||||
// ========================
|
||||
|
||||
// Mystery: Capcom vs SNK 800aa278
|
||||
|
||||
// CR flags approach:
|
||||
// * Store that "N+Z flag contains CR0" or "S+Z flag contains CR3".
|
||||
// * All flag altering instructions flush this
|
||||
// * A flush simply does a conditional write to the appropriate CRx.
|
||||
// * If flag available, branch code can become absolutely trivial.
|
||||
|
||||
#ifndef _JIT_H
|
||||
#define _JIT_H
|
||||
|
||||
@@ -128,6 +136,7 @@ private:
|
||||
bool enableFastMem;
|
||||
bool optimizeGatherPipe;
|
||||
bool fastInterrupts;
|
||||
bool accurateSinglePrecision;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ using namespace Gen;
|
||||
{
|
||||
LOG(DYNA_REC, "JIT Statistics =======================");
|
||||
LOG(DYNA_REC, "Number of blocks currently: %i", numBlocks);
|
||||
LOG(DYNA_REC, "Code cache size: %i b", GetCodePtr() - codeCache);
|
||||
LOG(DYNA_REC, "======================================");
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,34 +20,34 @@
|
||||
|
||||
#include "x64Emitter.h"
|
||||
|
||||
using namespace Gen;
|
||||
enum FlushMode
|
||||
{
|
||||
FLUSH_ALL
|
||||
};
|
||||
using namespace Gen;
|
||||
enum FlushMode
|
||||
{
|
||||
FLUSH_ALL
|
||||
};
|
||||
|
||||
enum GrabMode
|
||||
{
|
||||
M_READ = 1,
|
||||
M_WRITE = 2,
|
||||
M_READWRITE = 3,
|
||||
};
|
||||
enum GrabMode
|
||||
{
|
||||
M_READ = 1,
|
||||
M_WRITE = 2,
|
||||
M_READWRITE = 3,
|
||||
};
|
||||
|
||||
struct PPCCachedReg
|
||||
{
|
||||
OpArg location;
|
||||
bool away; // value not in source register
|
||||
};
|
||||
struct PPCCachedReg
|
||||
{
|
||||
OpArg location;
|
||||
bool away; // value not in source register
|
||||
};
|
||||
|
||||
struct X64CachedReg
|
||||
{
|
||||
int ppcReg;
|
||||
bool dirty;
|
||||
bool free;
|
||||
};
|
||||
struct X64CachedReg
|
||||
{
|
||||
int ppcReg;
|
||||
bool dirty;
|
||||
bool free;
|
||||
};
|
||||
|
||||
typedef int XReg;
|
||||
typedef int PReg;
|
||||
typedef int XReg;
|
||||
typedef int PReg;
|
||||
|
||||
#ifdef _M_X64
|
||||
#define NUMXREGS 16
|
||||
@@ -55,97 +55,96 @@
|
||||
#define NUMXREGS 8
|
||||
#endif
|
||||
|
||||
class RegCache
|
||||
class RegCache
|
||||
{
|
||||
private:
|
||||
bool locks[32];
|
||||
bool saved_locks[32];
|
||||
bool saved_xlocks[NUMXREGS];
|
||||
|
||||
protected:
|
||||
bool xlocks[NUMXREGS];
|
||||
PPCCachedReg regs[32];
|
||||
X64CachedReg xregs[NUMXREGS];
|
||||
|
||||
PPCCachedReg saved_regs[32];
|
||||
X64CachedReg saved_xregs[NUMXREGS];
|
||||
|
||||
void DiscardRegContentsIfCached(int preg);
|
||||
virtual const int *GetAllocationOrder(int &count) = 0;
|
||||
|
||||
XEmitter *emit;
|
||||
|
||||
public:
|
||||
virtual ~RegCache() {}
|
||||
virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0;
|
||||
|
||||
void SetEmitter(XEmitter *emitter) {emit = emitter;}
|
||||
|
||||
void FlushR(X64Reg reg);
|
||||
void FlushR(X64Reg reg, X64Reg reg2) {FlushR(reg); FlushR(reg2);}
|
||||
void FlushLockX(X64Reg reg) {
|
||||
FlushR(reg);
|
||||
LockX(reg);
|
||||
}
|
||||
void FlushLockX(X64Reg reg1, X64Reg reg2) {
|
||||
FlushR(reg1); FlushR(reg2);
|
||||
LockX(reg1); LockX(reg2);
|
||||
}
|
||||
virtual void Flush(FlushMode mode);
|
||||
virtual void Flush(PPCAnalyst::CodeOp *op) {Flush(FLUSH_ALL);}
|
||||
void SanityCheck() const;
|
||||
void KillImmediate(int preg);
|
||||
|
||||
//TODO - instead of doload, use "read", "write"
|
||||
//read only will not set dirty flag
|
||||
virtual void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true) = 0;
|
||||
virtual void StoreFromX64(int preg) = 0;
|
||||
|
||||
const OpArg &R(int preg) const {return regs[preg].location;}
|
||||
X64Reg RX(int preg) const
|
||||
{
|
||||
private:
|
||||
bool locks[32];
|
||||
bool saved_locks[32];
|
||||
bool saved_xlocks[NUMXREGS];
|
||||
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||
return regs[preg].location.GetSimpleReg();
|
||||
PanicAlert("Not so simple - %i", preg);
|
||||
return (X64Reg)-1;
|
||||
}
|
||||
virtual OpArg GetDefaultLocation(int reg) const = 0;
|
||||
|
||||
protected:
|
||||
bool xlocks[NUMXREGS];
|
||||
PPCCachedReg regs[32];
|
||||
X64CachedReg xregs[NUMXREGS];
|
||||
// Register locking.
|
||||
void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff);
|
||||
void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff);
|
||||
void UnlockAll();
|
||||
void UnlockAllX();
|
||||
|
||||
PPCCachedReg saved_regs[32];
|
||||
X64CachedReg saved_xregs[NUMXREGS];
|
||||
bool IsFreeX(int xreg) const;
|
||||
|
||||
void DiscardRegContentsIfCached(int preg);
|
||||
virtual const int *GetAllocationOrder(int &count) = 0;
|
||||
|
||||
XEmitter *emit;
|
||||
X64Reg GetFreeXReg();
|
||||
|
||||
public:
|
||||
virtual ~RegCache() {}
|
||||
virtual void Start(PPCAnalyst::BlockRegStats &stats) = 0;
|
||||
void SaveState();
|
||||
void LoadState();
|
||||
};
|
||||
|
||||
void SetEmitter(XEmitter *emitter) {emit = emitter;}
|
||||
|
||||
void FlushR(X64Reg reg);
|
||||
void FlushR(X64Reg reg, X64Reg reg2) {FlushR(reg); FlushR(reg2);}
|
||||
void FlushLockX(X64Reg reg) {
|
||||
FlushR(reg);
|
||||
LockX(reg);
|
||||
}
|
||||
void FlushLockX(X64Reg reg1, X64Reg reg2) {
|
||||
FlushR(reg1); FlushR(reg2);
|
||||
LockX(reg1); LockX(reg2);
|
||||
}
|
||||
virtual void Flush(FlushMode mode);
|
||||
virtual void Flush(PPCAnalyst::CodeOp *op) {Flush(FLUSH_ALL);}
|
||||
void SanityCheck() const;
|
||||
void KillImmediate(int preg);
|
||||
|
||||
//TODO - instead of doload, use "read", "write"
|
||||
//read only will not set dirty flag
|
||||
virtual void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true) = 0;
|
||||
virtual void StoreFromX64(int preg) = 0;
|
||||
|
||||
const OpArg &R(int preg) const {return regs[preg].location;}
|
||||
X64Reg RX(int preg) const
|
||||
{
|
||||
if (regs[preg].away && regs[preg].location.IsSimpleReg())
|
||||
return regs[preg].location.GetSimpleReg();
|
||||
PanicAlert("Not so simple - %i", preg);
|
||||
return (X64Reg)-1;
|
||||
}
|
||||
virtual OpArg GetDefaultLocation(int reg) const = 0;
|
||||
|
||||
// Register locking.
|
||||
void Lock(int p1, int p2=0xff, int p3=0xff, int p4=0xff);
|
||||
void LockX(int x1, int x2=0xff, int x3=0xff, int x4=0xff);
|
||||
void UnlockAll();
|
||||
void UnlockAllX();
|
||||
|
||||
bool IsFreeX(int xreg) const;
|
||||
|
||||
X64Reg GetFreeXReg();
|
||||
|
||||
void SaveState();
|
||||
void LoadState();
|
||||
};
|
||||
|
||||
class GPRRegCache : public RegCache
|
||||
{
|
||||
public:
|
||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromX64(int preg);
|
||||
OpArg GetDefaultLocation(int reg) const;
|
||||
const int *GetAllocationOrder(int &count);
|
||||
void SetImmediate32(int preg, u32 immValue);
|
||||
};
|
||||
class GPRRegCache : public RegCache
|
||||
{
|
||||
public:
|
||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromX64(int preg);
|
||||
OpArg GetDefaultLocation(int reg) const;
|
||||
const int *GetAllocationOrder(int &count);
|
||||
void SetImmediate32(int preg, u32 immValue);
|
||||
};
|
||||
|
||||
|
||||
class FPURegCache : public RegCache
|
||||
{
|
||||
public:
|
||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromX64(int preg);
|
||||
const int *GetAllocationOrder(int &count);
|
||||
OpArg GetDefaultLocation(int reg) const;
|
||||
};
|
||||
class FPURegCache : public RegCache
|
||||
{
|
||||
public:
|
||||
void Start(PPCAnalyst::BlockRegStats &stats);
|
||||
void LoadToX64(int preg, bool doLoad = true, bool makeDirty = true);
|
||||
void StoreFromX64(int preg);
|
||||
const int *GetAllocationOrder(int &count);
|
||||
OpArg GetDefaultLocation(int reg) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@
|
||||
if (!merge_branch) {
|
||||
// Keep the normal code separate for clarity.
|
||||
CMP(32, gpr.R(a), comparand);
|
||||
|
||||
FixupBranch pLesser = J_CC(less_than);
|
||||
FixupBranch pGreater = J_CC(greater_than);
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // _x86Reg == 0
|
||||
@@ -216,42 +217,45 @@
|
||||
} else {
|
||||
int test_bit = 8 >> (js.next_inst.BI & 3);
|
||||
bool condition = (js.next_inst.BO & 8) ? false : true;
|
||||
|
||||
u32 destination;
|
||||
if (js.next_inst.AA)
|
||||
destination = SignExt16(js.next_inst.BD << 2);
|
||||
else
|
||||
destination = js.next_compilerPC + SignExt16(js.next_inst.BD << 2);
|
||||
|
||||
CMP(32, gpr.R(a), comparand);
|
||||
gpr.UnlockAll();
|
||||
|
||||
u32 destination1;
|
||||
if (js.next_inst.AA)
|
||||
destination1 = SignExt16(js.next_inst.BD << 2);
|
||||
else
|
||||
destination1 = js.next_compilerPC + SignExt16(js.next_inst.BD << 2);
|
||||
u32 destination2 = js.next_compilerPC + 4;
|
||||
|
||||
// Test swapping (in the future, will be used to inline across branches the right way)
|
||||
// if (rand() & 1)
|
||||
// std::swap(destination1, destination2), condition = !condition;
|
||||
|
||||
gpr.Flush(FLUSH_ALL);
|
||||
fpr.Flush(FLUSH_ALL);
|
||||
FixupBranch pLesser = J_CC(less_than);
|
||||
FixupBranch pGreater = J_CC(greater_than);
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // _x86Reg == 0
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x2)); // == 0
|
||||
FixupBranch continue1 = J();
|
||||
|
||||
SetJumpTarget(pGreater);
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4)); // _x86Reg > 0
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x4)); // > 0
|
||||
FixupBranch continue2 = J();
|
||||
|
||||
SetJumpTarget(pLesser);
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8)); // _x86Reg < 0
|
||||
MOV(8, M(&PowerPC::ppcState.cr_fast[crf]), Imm8(0x8)); // < 0
|
||||
FixupBranch continue3;
|
||||
if (!!(8 & test_bit) == condition) continue3 = J();
|
||||
|
||||
//if (!!(8 & test_bit) != condition) SetJumpTarget(continue3);
|
||||
if (!!(4 & test_bit) != condition) SetJumpTarget(continue2);
|
||||
if (!!(2 & test_bit) != condition) SetJumpTarget(continue1);
|
||||
|
||||
WriteExit(destination, 0);
|
||||
WriteExit(destination1, 0);
|
||||
|
||||
if (!!(8 & test_bit) == condition) SetJumpTarget(continue3);
|
||||
if (!!(4 & test_bit) == condition) SetJumpTarget(continue2);
|
||||
if (!!(2 & test_bit) == condition) SetJumpTarget(continue1);
|
||||
|
||||
WriteExit(js.next_compilerPC + 4, 1);
|
||||
WriteExit(destination2, 1);
|
||||
|
||||
js.cancel = true;
|
||||
}
|
||||
|
||||
@@ -139,11 +139,18 @@ void Jit64::WriteFloatToConstRamAddress(const Gen::X64Reg& xmm_reg, u32 address)
|
||||
|
||||
void Jit64::ForceSinglePrecisionS(X64Reg xmm) {
|
||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||
CVTSD2SS(xmm, R(xmm));
|
||||
CVTSS2SD(xmm, R(xmm));
|
||||
if (jo.accurateSinglePrecision)
|
||||
{
|
||||
CVTSD2SS(xmm, R(xmm));
|
||||
CVTSS2SD(xmm, R(xmm));
|
||||
}
|
||||
}
|
||||
|
||||
void Jit64::ForceSinglePrecisionP(X64Reg xmm) {
|
||||
// Most games don't need these. Zelda requires it though - some platforms get stuck without them.
|
||||
CVTPD2PS(xmm, R(xmm));
|
||||
CVTPS2PD(xmm, R(xmm));
|
||||
if (jo.accurateSinglePrecision)
|
||||
{
|
||||
CVTPD2PS(xmm, R(xmm));
|
||||
CVTPS2PD(xmm, R(xmm));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
|
||||
code[i].inst = inst;
|
||||
code[i].branchTo = -1;
|
||||
code[i].branchToIndex = -1;
|
||||
code[i].skip = false;
|
||||
GekkoOPInfo *opinfo = GetOpInfo(inst);
|
||||
if (opinfo)
|
||||
numCycles += opinfo->numCyclesMinusOne + 1;
|
||||
@@ -345,6 +346,7 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
|
||||
}
|
||||
else
|
||||
{
|
||||
code[i].skip = true;
|
||||
address = destination;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ struct CodeOp //16B
|
||||
bool outputCR0;
|
||||
bool outputCR1;
|
||||
bool outputPS1;
|
||||
bool skip; // followed BL-s for example
|
||||
};
|
||||
|
||||
struct BlockStats
|
||||
|
||||
Reference in New Issue
Block a user