Move downcount into MIPSState for efficiency, enable block linking.

On ARM JIT we can now reach it through the cpu context reg.
This commit is contained in:
Henrik Rydgard
2013-01-12 00:44:18 +01:00
parent 38f437010c
commit 674911ddba
11 changed files with 49 additions and 84 deletions

View File

@@ -67,7 +67,9 @@ Event *eventPool = 0;
Event *eventTsPool = 0;
int allocatedTsEvents = 0;
int downcount, slicelength;
// Downcount has been moved to currentMIPS, to save a couple of clocks in every ARM JIT block
// as we can already reach that structure through a register.
int slicelength;
s64 globalTimer;
s64 idledCycles;
@@ -153,7 +155,7 @@ void UnregisterAllEvents()
void Init()
{
downcount = INITIAL_SLICE_LENGTH;
currentMIPS->downcount = INITIAL_SLICE_LENGTH;
slicelength = INITIAL_SLICE_LENGTH;
globalTimer = 0;
idledCycles = 0;
@@ -183,7 +185,7 @@ void Shutdown()
u64 GetTicks()
{
return (u64)globalTimer + slicelength - downcount;
return (u64)globalTimer + slicelength - currentMIPS->downcount;
}
u64 GetIdleTicks()
@@ -462,23 +464,23 @@ void MoveEvents()
void Advance()
{
int cyclesExecuted = slicelength - downcount;
int cyclesExecuted = slicelength - currentMIPS->downcount;
globalTimer += cyclesExecuted;
downcount = slicelength;
currentMIPS->downcount = slicelength;
ProcessFifoWaitEvents();
if (!first)
{
// WARN_LOG(CPU, "WARNING - no events in queue. Setting downcount to 10000");
downcount += 10000;
// WARN_LOG(CPU, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000");
currentMIPS->downcount += 10000;
}
else
{
slicelength = (int)(first->time - globalTimer);
if (slicelength > MAX_SLICE_LENGTH)
slicelength = MAX_SLICE_LENGTH;
downcount = slicelength;
currentMIPS->downcount = slicelength;
}
if (advanceCallback)
advanceCallback(cyclesExecuted);
@@ -496,13 +498,13 @@ void LogPendingEvents()
void Idle(int maxIdle)
{
int cyclesDown = downcount;
int cyclesDown = currentMIPS->downcount;
if (maxIdle != 0 && cyclesDown > maxIdle)
cyclesDown = maxIdle;
if (first && cyclesDown > 0)
{
int cyclesExecuted = slicelength - downcount;
int cyclesExecuted = slicelength - currentMIPS->downcount;
int cyclesNextEvent = (int) (first->time - globalTimer);
if (cyclesNextEvent < cyclesExecuted + cyclesDown)
@@ -517,9 +519,9 @@ void Idle(int maxIdle)
DEBUG_LOG(CPU, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(CPU_HZ * 0.001f));
idledCycles += cyclesDown;
downcount -= cyclesDown;
if (downcount == 0)
downcount = -1;
currentMIPS->downcount -= cyclesDown;
if (currentMIPS->downcount == 0)
currentMIPS->downcount = -1;
}
std::string GetScheduledEventsSummary()
@@ -561,7 +563,6 @@ void DoState(PointerWrap &p)
p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
p.Do(CPU_HZ);
p.Do(downcount);
p.Do(slicelength);
p.Do(globalTimer);
p.Do(idledCycles);

View File

@@ -119,7 +119,6 @@ namespace CoreTiming
void SetClockFrequencyMHz(int cpuMhz);
int GetClockFrequencyMHz();
extern int downcount;
extern int slicelength;
}; // end of namespace

View File

@@ -138,25 +138,7 @@ namespace MIPSComp
break;
}
}
//rd = rs X rt
/*
void Jit::CompTriArith(u32 op, void (XEmitter::*arith)(int, const OpArg &, const OpArg &))
{
int rt = _RT;
int rs = _RS;
int rd = _RD;
gpr.Lock(rt, rs, rd);
MOV(32, R(EAX), gpr.R(rs));
MOV(32, R(EBX), gpr.R(rt));
gpr.BindToRegister(rd, true, true);
(this->*arith)(32, R(EAX), R(EBX));
MOV(32, gpr.R(rd), R(EAX));
gpr.UnlockAll();
}
*/
void Jit::Comp_RType3(u32 op)
{
int rt = _RT;

View File

@@ -205,18 +205,18 @@ void Jit::MovToPC(ARMReg r) {
void Jit::DoDownCount()
{
ARMABI_MOVI2R(R0, (u32)&CoreTiming::downcount);
LDR(R1, R0);
if(js.downcountAmount < 255) // We can enlarge this if we used rotations
LDR(R1, R10, offsetof(MIPSState, downcount));
Operand2 op2;
if (TryMakeOperand2(js.downcountAmount, op2)) // We can enlarge this if we used rotations
{
SUBS(R1, R1, js.downcountAmount);
STR(R0, R1);
SUBS(R1, R1, op2);
STR(R10, R1, offsetof(MIPSState, downcount));
} else {
// Should be fine to use R2 here, flushed the regcache anyway.
// If js.downcountAmount can be expressed as an Imm8, we don't need this anyway.
ARMABI_MOVI2R(R2, js.downcountAmount);
SUBS(R1, R1, R2);
STR(R0, R1);
STR(R10, R1, offsetof(MIPSState, downcount));
}
}

View File

@@ -31,7 +31,7 @@ struct ArmJitOptions
{
ArmJitOptions()
{
enableBlocklink = false;
enableBlocklink = true;
}
bool enableBlocklink;
@@ -131,6 +131,7 @@ private:
MIPSState *mips_;
public:
// Code pointers
const u8 *enterCode;

View File

@@ -95,8 +95,7 @@ ArmJitBlockCache::~ArmJitBlockCache()
Shutdown();
}
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
// This clears the JIT block cache. It's called from JitCache.cpp when the JIT cache
// is full and when saving and loading states.
void ArmJitBlockCache::Clear()
{
@@ -117,17 +116,6 @@ void ArmJitBlockCache::ClearSafe()
#endif
}
/*void JitBlockCache::DestroyBlocksWithFlag(BlockFlag death_flag)
{
for (int i = 0; i < num_blocks; i++)
{
if (blocks[i].flags & death_flag)
{
DestroyBlock(i, false);
}
}
}*/
void ArmJitBlockCache::Reset()
{
Shutdown();
@@ -279,13 +267,8 @@ std::string ArmJitBlockCache::GetCompiledDisassembly(int block_num)
}
//Block linker
//Make sure to have as many blocks as possible compiled before calling this
//It's O(N), so it's fast :)
//Can be faster by doing a queue for blocks to link up, and only process those
//Should probably be done
//It's O(1), so it's fast :)
void ArmJitBlockCache::LinkBlockExits(int i)
{
ArmJitBlock &b = blocks[i];
@@ -302,7 +285,7 @@ void ArmJitBlockCache::LinkBlockExits(int i)
if (destinationBlock != -1)
{
ARMXEmitter emit(b.exitPtrs[e]);
// emit.JMP(blocks[destinationBlock].checkedEntry, true);
emit.B(blocks[destinationBlock].checkedEntry);
b.linkStatus[e] = true;
}
}
@@ -366,25 +349,20 @@ void ArmJitBlockCache::DestroyBlock(int block_num, bool invalidate)
UnlinkBlock(block_num);
blockCodePointers[block_num] = 0;
// Send anyone who tries to run this block back to the dispatcher.
// Not entirely ideal, but .. pretty good.
// Spurious entrances from previously linked blocks can only come through checkedEntry
// I hope there's enough space...
// checkedEntry is the only "linked" entrance so it's enough to overwrite that.
ARMXEmitter emit((u8 *)b.checkedEntry);
//emit.MOV(32, M(&mips->pc), Imm32(b.originalAddress));
//emit.JMP(MIPSComp::jit->Asm().dispatcher, true);
// this is not needed really
/*
emit.SetCodePtr((u8 *)blockCodePointers[blocknum]);
emit.MOV(32, M(&PC), Imm32(b.originalAddress));
emit.JMP(asm_routines.dispatcher, true);
*/
emit.ARMABI_MOVI2R(R0, b.originalAddress);
emit.STR(R10, R0, offsetof(MIPSState, pc));
emit.B(MIPSComp::jit->dispatcher);
}
void ArmJitBlockCache::InvalidateICache(u32 address, const u32 length)
{
// Convert the logical address to a physical address for the block map
u32 pAddr = address & 0x1FFFFFFF;
u32 pAddr = address & 0x3FFFFFFF;
// destroy JIT blocks
// !! this works correctly under assumption that any two overlapping blocks end at the same address

View File

@@ -110,6 +110,7 @@ void MIPSState::DoState(PointerWrap &p)
p.DoArray(vfpuWriteMask, sizeof(vfpuWriteMask) / sizeof(vfpuWriteMask[0]));
p.Do(pc);
p.Do(nextPC);
p.Do(downcount);
p.Do(hi);
p.Do(lo);
p.Do(fpcond);
@@ -131,7 +132,7 @@ void MIPSState::SetWriteMask(const bool wm[4])
void MIPSState::SingleStep()
{
int cycles = MIPS_SingleStep();
CoreTiming::downcount -= cycles;
currentMIPS->downcount -= cycles;
CoreTiming::Advance();
}

View File

@@ -122,6 +122,8 @@ public:
u32 pc;
u32 nextPC;
u32 downcount; // This really doesn't belong here, it belongs in CoreTiming. But you gotta do what you gotta do, this needs to be reachable in the ARM JIT.
u32 hi;
u32 lo;
@@ -129,11 +131,12 @@ public:
u32 fcr31; //fpu control register
u32 fpcond; // cache the cond flag of fcr31 (& 1 << 23)
GMRng rng; // VFPU hardware random number generator. Probably not the right type.
bool inDelaySlot;
int llBit; // ll/sc
GMRng rng; // VFPU hardware random number generator. Probably not the right type.
// Debug stuff
u32 debugCount; // can be used to count basic blocks before crashes, etc.

View File

@@ -948,7 +948,7 @@ int MIPSInterpret_RunUntil(u64 globalTicks)
while (coreState == CORE_RUNNING)
{
// NEVER stop in a delay slot!
while (CoreTiming::downcount >= 0 && coreState == CORE_RUNNING)
while (curMips->downcount >= 0 && coreState == CORE_RUNNING)
{
// int cycles = 0;
{
@@ -990,7 +990,7 @@ int MIPSInterpret_RunUntil(u64 globalTicks)
curMips->pc = curMips->nextPC;
curMips->inDelaySlot = false;
}
CoreTiming::downcount -= 1;
curMips->downcount -= 1;
goto again;
}
}
@@ -1025,7 +1025,7 @@ int MIPSInterpret_RunFastUntil(u64 globalTicks)
MIPSState *curMips = currentMIPS;
while (coreState == CORE_RUNNING)
{
while (CoreTiming::downcount >= 0 && coreState == CORE_RUNNING) // TODO: Try to get rid of the latter check
while (curMips->downcount >= 0 && coreState == CORE_RUNNING) // TODO: Try to get rid of the latter check
{
again:
bool wasInDelaySlot = curMips->inDelaySlot;
@@ -1122,7 +1122,7 @@ int MIPSInterpret_RunFastUntil(u64 globalTicks)
curMips->pc = curMips->nextPC;
curMips->inDelaySlot = false;
}
CoreTiming::downcount -= 1;
curMips->downcount -= 1;
goto again;
}
}

View File

@@ -137,7 +137,7 @@ void Jit::Comp_Generic(u32 op)
void Jit::WriteExit(u32 destination, int exit_num)
{
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
SUB(32, M(&currentMIPS->downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
//If nobody has taken care of this yet (this can be removed when all branches are done)
JitBlock *b = js.curBlock;
@@ -161,13 +161,13 @@ void Jit::WriteExitDestInEAX()
{
// TODO: Some wasted potential, dispatcher will alwa
MOV(32, M(&mips_->pc), R(EAX));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
SUB(32, M(&currentMIPS->downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_.dispatcher, true);
}
void Jit::WriteSyscallExit()
{
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
SUB(32, M(&currentMIPS->downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_.dispatcherCheckCoreState, true);
}

View File

@@ -35,7 +35,7 @@ struct JitOptions
{
JitOptions()
{
enableBlocklink = false;
enableBlocklink = true;
}
bool enableBlocklink;