mirror of
https://github.com/izzy2lost/ppsspp.git
synced 2026-03-10 12:43:04 -07:00
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:
@@ -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);
|
||||
|
||||
@@ -119,7 +119,6 @@ namespace CoreTiming
|
||||
|
||||
void SetClockFrequencyMHz(int cpuMhz);
|
||||
int GetClockFrequencyMHz();
|
||||
extern int downcount;
|
||||
extern int slicelength;
|
||||
|
||||
}; // end of namespace
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(¤tMIPS->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(¤tMIPS->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(¤tMIPS->downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
|
||||
JMP(asm_.dispatcherCheckCoreState, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ struct JitOptions
|
||||
{
|
||||
JitOptions()
|
||||
{
|
||||
enableBlocklink = false;
|
||||
enableBlocklink = true;
|
||||
}
|
||||
|
||||
bool enableBlocklink;
|
||||
|
||||
Reference in New Issue
Block a user