Changed way ticks are counted to make sure the speed hacks are activated when both the EE and IOP are idle. EE/IOP time synchronization is probably not quite right yet though.

git-svn-id: http://svn.purei.org/purei/trunk@1006 b36208d7-6611-0410-8bec-b1987f11c4a2
This commit is contained in:
jpd002 2012-09-25 03:17:46 +00:00
parent 4233c33cfe
commit 30dfc3fe28
5 changed files with 147 additions and 110 deletions

View File

@ -92,6 +92,8 @@ CPS2VM::CPS2VM()
, m_singleStepVu1(false)
, m_vblankTicks(0)
, m_inVblank(false)
, m_eeExecutionTicks(0)
, m_iopExecutionTicks(0)
, m_spuUpdateTicks(SPU_UPDATE_TICKS)
, m_pCDROM0(NULL)
, m_dmac(m_ram, m_spr, m_pVUMem0, m_EE)
@ -520,6 +522,9 @@ void CPS2VM::ResetVM()
m_vblankTicks = ONSCREEN_TICKS;
m_inVblank = false;
m_eeExecutionTicks = 0;
m_iopExecutionTicks = 0;
RegisterModulesInPadHandler();
FillFakeIopRam();
@ -1038,6 +1043,79 @@ void CPS2VM::ReloadExecutable(const char* executablePath, const CPS2OS::Argument
m_os->BootFromCDROM(arguments);
}
int CPS2VM::ExecuteEe(int quota)
{
int executed = 0;
if(m_EE.m_State.callMsEnabled)
{
if(!m_vif.IsVu0Running())
{
//callMs mode over
memcpy(&m_EE.m_State.nCOP2, &m_VU0.m_State.nCOP2, sizeof(m_EE.m_State.nCOP2));
memcpy(&m_EE.m_State.nCOP2A, &m_VU0.m_State.nCOP2A, sizeof(m_EE.m_State.nCOP2A));
m_EE.m_State.callMsEnabled = 0;
}
}
else if(!m_EE.m_State.nHasException)
{
executed = (quota - m_executor.Execute(quota));
}
if(m_EE.m_State.nHasException)
{
switch(m_EE.m_State.nHasException)
{
case MIPS_EXCEPTION_SYSCALL:
m_os->SysCallHandler();
break;
case MIPS_EXCEPTION_CALLMS:
assert(m_EE.m_State.callMsEnabled);
if(m_EE.m_State.callMsEnabled)
{
//We are in callMs mode
assert(!m_vif.IsVu0Running());
//Copy the COP2 state to VPU0
memcpy(&m_VU0.m_State.nCOP2, &m_EE.m_State.nCOP2, sizeof(m_VU0.m_State.nCOP2));
memcpy(&m_VU0.m_State.nCOP2A, &m_EE.m_State.nCOP2A, sizeof(m_VU0.m_State.nCOP2A));
m_vif.StartVu0MicroProgram(m_EE.m_State.callMsAddr);
m_EE.m_State.nHasException = 0;
}
break;
case MIPS_EXCEPTION_CHECKPENDINGINT:
{
m_EE.m_State.nHasException = MIPS_EXCEPTION_NONE;
if(m_intc.IsInterruptPending())
{
m_os->ExceptionHandler();
}
}
break;
default:
assert(0);
break;
}
assert(!m_EE.m_State.nHasException);
}
return executed;
}
bool CPS2VM::IsEeIdle() const
{
CBasicBlock* nextBlock = m_executor.FindBlockAt(m_EE.m_State.nPC);
if(nextBlock && nextBlock->GetSelfLoopCount() > 5000)
{
return true;
}
else if(m_os->IsIdle())
{
return true;
}
else if(m_EE.m_State.nPC >= 0x1FC03100 && m_EE.m_State.nPC <= 0x1FC03110)
{
return true;
}
return false;
}
void CPS2VM::EmuThread()
{
while(1)
@ -1117,73 +1195,23 @@ void CPS2VM::EmuThread()
}
}
int executed = 0;
if(m_EE.m_State.callMsEnabled)
{
if(!m_vif.IsVu0Running())
{
//callMs mode over
memcpy(&m_EE.m_State.nCOP2, &m_VU0.m_State.nCOP2, sizeof(m_EE.m_State.nCOP2));
memcpy(&m_EE.m_State.nCOP2A, &m_VU0.m_State.nCOP2A, sizeof(m_EE.m_State.nCOP2A));
m_EE.m_State.callMsEnabled = 0;
}
}
else if(!m_EE.m_State.nHasException)
{
int executeQuota = m_singleStepEe ? 1 : 5000;
executed += (executeQuota - m_executor.Execute(executeQuota));
}
if(m_EE.m_State.nHasException)
{
switch(m_EE.m_State.nHasException)
{
case MIPS_EXCEPTION_SYSCALL:
m_os->SysCallHandler();
break;
case MIPS_EXCEPTION_CALLMS:
assert(m_EE.m_State.callMsEnabled);
if(m_EE.m_State.callMsEnabled)
{
//We are in callMs mode
assert(!m_vif.IsVu0Running());
//Copy the COP2 state to VPU0
memcpy(&m_VU0.m_State.nCOP2, &m_EE.m_State.nCOP2, sizeof(m_VU0.m_State.nCOP2));
memcpy(&m_VU0.m_State.nCOP2A, &m_EE.m_State.nCOP2A, sizeof(m_VU0.m_State.nCOP2A));
m_vif.StartVu0MicroProgram(m_EE.m_State.callMsAddr);
m_EE.m_State.nHasException = 0;
}
break;
case MIPS_EXCEPTION_CHECKPENDINGINT:
{
m_EE.m_State.nHasException = MIPS_EXCEPTION_NONE;
if(m_intc.IsInterruptPending())
{
m_os->ExceptionHandler();
}
}
break;
default:
assert(0);
break;
}
assert(!m_EE.m_State.nHasException);
}
//EE CPU is 8 times faster than the IOP CPU
static const int tickStep = 4800;
m_eeExecutionTicks += tickStep;
m_iopExecutionTicks += tickStep / 8;
m_eeExecutionTicks -= ExecuteEe(m_singleStepEe ? 1 : m_eeExecutionTicks);
unsigned int iopExecuted = m_iop.ExecuteCpu(m_singleStepIop ? 1 : m_iopExecutionTicks);
m_iopExecutionTicks -= iopExecuted;
int executed = tickStep;
if(IsEeIdle() && m_iop.IsCpuIdle())
{
CBasicBlock* nextBlock = m_executor.FindBlockAt(m_EE.m_State.nPC);
const int skipAmount = 50000;
if(nextBlock && nextBlock->GetSelfLoopCount() > 5000)
{
executed += skipAmount;
}
else if(m_os->IsIdle())
{
executed += skipAmount;
}
else if(m_EE.m_State.nPC >= 0x1FC03100 && m_EE.m_State.nPC <= 0x1FC03110)
{
executed += skipAmount;
}
executed *= 16;
m_eeExecutionTicks = 0;
m_iopExecutionTicks = 0;
}
m_EE.m_State.nCOP0[CCOP_SCU::COUNT] += executed;
@ -1191,8 +1219,7 @@ void CPS2VM::EmuThread()
m_spuUpdateTicks -= executed;
m_timer.Count(executed);
//IOP Execution
m_iop.ExecuteCpu(m_singleStepIop);
m_iop.CountTicks(iopExecuted);
#ifdef DEBUGGER_INCLUDED
static bool wasVu1Running = false;

View File

@ -138,6 +138,8 @@ public:
int m_vblankTicks;
bool m_inVblank;
int m_spuUpdateTicks;
int m_eeExecutionTicks;
int m_iopExecutionTicks;
CISO9660* m_pCDROM0;
@ -174,6 +176,8 @@ private:
void RegisterModulesInPadHandler();
void FillFakeIopRam();
int ExecuteEe(int);
bool IsEeIdle() const;
void EmuThread();
boost::thread* m_thread;

View File

@ -218,9 +218,34 @@ uint32 CSubSystem::WriteIoRegister(uint32 address, uint32 value)
return 0;
}
unsigned int CSubSystem::ExecuteCpu(bool singleStep)
bool CSubSystem::IsCpuIdle()
{
int ticks = 0;
if(m_bios->IsIdle())
{
return true;
}
else
{
uint32 physicalPc = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nPC);
CBasicBlock* nextBlock = m_executor.FindBlockAt(physicalPc);
if(nextBlock && nextBlock->GetSelfLoopCount() > 5000)
{
//Go a little bit faster if we're "stuck"
return true;
}
}
return false;
}
void CSubSystem::CountTicks(int ticks)
{
m_counters.Update(ticks);
m_bios->CountTicks(ticks);
}
int CSubSystem::ExecuteCpu(int quota)
{
int executed = 0;
if(!m_cpu.m_State.nHasException)
{
if(m_intc.HasPendingInterrupt())
@ -230,45 +255,11 @@ unsigned int CSubSystem::ExecuteCpu(bool singleStep)
}
if(!m_cpu.m_State.nHasException)
{
bool isIdle = false;
int quota = singleStep ? 1 : 500;
{
if(m_bios->IsIdle())
{
isIdle = true;
ticks += (quota * 2);
}
else
{
uint32 physicalPc = m_cpu.m_pAddrTranslator(&m_cpu, m_cpu.m_State.nPC);
CBasicBlock* nextBlock = m_executor.FindBlockAt(physicalPc);
if(nextBlock && nextBlock->GetSelfLoopCount() > 5000)
{
//Go a little bit faster if we're "stuck"
isIdle = true;
ticks += (quota * 2);
}
}
}
if(isIdle && !singleStep)
{
quota /= 50;
}
ticks += (quota - m_executor.Execute(quota));
assert(ticks >= 0);
if(ticks > 0)
{
m_counters.Update(ticks);
m_bios->CountTicks(ticks);
}
executed = (quota - m_executor.Execute(quota));
}
if(m_cpu.m_State.nHasException)
{
m_bios->HandleException();
}
return ticks;
return executed;
}

View File

@ -28,7 +28,9 @@ namespace Iop
virtual ~CSubSystem();
void Reset();
unsigned int ExecuteCpu(bool);
int ExecuteCpu(int);
bool IsCpuIdle();
void CountTicks(int);
void SetBios(const BiosPtr&);

View File

@ -66,7 +66,8 @@ void CPsfSubSystem::Update(bool singleStep, CSoundHandler* soundHandler)
{
#ifdef DEBUGGER_INCLUDED
uint64 frameTime = (CHighResTimer::MICROSECOND / FRAMES_PER_SEC);
int ticks = m_iop.ExecuteCpu(singleStep);
int ticks = m_iop.ExecuteCpu(singleStep ? 1 : 500);
m_iop.CountTicks(ticks);
static int frameCounter = m_frameTicks;
static uint64 currentTime = CHighResTimer::GetTime();
@ -95,9 +96,21 @@ void CPsfSubSystem::Update(bool singleStep, CSoundHandler* soundHandler)
}
else
{
int ticks = m_iop.ExecuteCpu(false);
m_spuUpdateCounter -= ticks;
m_frameCounter -= ticks;
//Execute CPU and step devices
{
int ticks = 0;
int quota = 500;
if(m_iop.IsCpuIdle())
{
ticks += (quota * 2);
quota /= 50;
}
ticks += m_iop.ExecuteCpu(quota);
m_iop.CountTicks(ticks);
m_spuUpdateCounter -= ticks;
m_frameCounter -= ticks;
}
if(m_spuUpdateCounter < 0)
{
m_spuUpdateCounter += m_spuUpdateTicks;