EE: Switch to 64 bit cycle counter

[SAVEVERSION+]
This commit is contained in:
Ziemas
2026-03-07 09:28:55 -05:00
committed by Ty
parent 6284a5de4f
commit f576962dd8
19 changed files with 125 additions and 128 deletions
+1 -1
View File
@@ -523,7 +523,7 @@ cpuRegs.PERF.n.pccr, cpuRegs.PERF.n.pcr0, cpuRegs.PERF.n.pcr1, _Imm_ & 0x3F);*/
case 9:
{
u32 incr = cpuRegs.cycle - cpuRegs.lastCOP0Cycle;
s64 incr = cpuRegs.cycle - cpuRegs.lastCOP0Cycle;
if (incr == 0)
incr++;
cpuRegs.CP0.n.Count += incr;
+13 -13
View File
@@ -31,13 +31,13 @@ Counter counters[4];
SyncCounter hsyncCounter;
SyncCounter vsyncCounter;
u32 nextStartCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate()
u64 nextStartCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate()
s32 nextDeltaCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate()
// Forward declarations needed because C/C++ both are wimpy single-pass compilers.
static void rcntStartGate(bool mode, u32 sCycle);
static void rcntEndGate(bool mode, u32 sCycle);
static void rcntStartGate(bool mode, u64 sCycle);
static void rcntEndGate(bool mode, u64 sCycle);
static void rcntWcount(int index, u32 value);
static void rcntWmode(int index, u32 value);
static void rcntWtarget(int index, u32 value);
@@ -425,7 +425,7 @@ void UpdateVSyncRate(bool force)
}
// FMV switch stuff
extern uint eecount_on_last_vdec;
extern u64 eecount_on_last_vdec;
extern bool FMVstarted;
extern bool EnableFMV;
@@ -484,7 +484,7 @@ static __fi void DoFMVSwitch()
}
}
static __fi void VSyncStart(u32 sCycle)
static __fi void VSyncStart(u64 sCycle)
{
// End-of-frame tasks.
DoFMVSwitch();
@@ -561,7 +561,7 @@ static __fi void GSVSync()
}
}
static __fi void VSyncEnd(u32 sCycle)
static __fi void VSyncEnd(u64 sCycle)
{
EECNT_LOG(" ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount);
@@ -740,7 +740,7 @@ __fi void rcntSyncCounter(int i)
const u32 change = (cpuRegs.cycle - counters[i].startCycle) / counters[i].rate;
counters[i].startCycle += change * counters[i].rate;
counters[i].startCycle &= ~(counters[i].rate - 1);
counters[i].startCycle &= ~((u64)counters[i].rate - 1);
if (rcntCanCount(i))
counters[i].count += change;
@@ -789,7 +789,7 @@ static __fi void _rcntSetGate(int index)
}
// mode - 0 means hblank source, 8 means vblank source.
static __fi void rcntStartGate(bool isVblank, u32 sCycle)
static __fi void rcntStartGate(bool isVblank, u64 sCycle)
{
for (int i = 0; i < 4; i++)
{
@@ -818,7 +818,7 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
// Just set the start cycle -- counting will be done as needed
// for events (overflows, targets, mode changes, and the gate off below)
rcntSyncCounter(i);
counters[i].startCycle = sCycle & ~(counters[i].rate - 1);
counters[i].startCycle = sCycle & ~((u64)counters[i].rate - 1);
EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", i,
isVblank ? "vblank" : "hblank", counters[i].count);
break;
@@ -830,7 +830,7 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
rcntSyncCounter(i);
counters[i].count = 0;
counters[i].target &= 0xffff;
counters[i].startCycle = sCycle & ~(counters[i].rate - 1);
counters[i].startCycle = sCycle & ~((u64)counters[i].rate - 1);
EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", i,
isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count);
break;
@@ -846,7 +846,7 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
}
// mode - 0 means hblank signal, 8 means vblank signal.
static __fi void rcntEndGate(bool isVblank, u32 sCycle)
static __fi void rcntEndGate(bool isVblank, u64 sCycle)
{
for (int i = 0; i < 4; i++)
{
@@ -859,7 +859,7 @@ static __fi void rcntEndGate(bool isVblank, u32 sCycle)
switch (counters[i].mode.GateMode)
{
case 0x0: //Count When Signal is low (V_RENDER ONLY)
counters[i].startCycle = sCycle & ~(counters[i].rate - 1);
counters[i].startCycle = sCycle & ~((u64)counters[i].rate - 1);
EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", i,
isVblank ? "vblank" : "hblank", counters[i].count);
@@ -903,7 +903,7 @@ static __fi void rcntWmode(int index, u32 value)
}
// In case the rate has changed we need to set the start cycle to the previous tick.
counters[index].startCycle = cpuRegs.cycle & ~(counters[index].rate - 1);
counters[index].startCycle = cpuRegs.cycle & ~((u64)counters[index].rate - 1);
_rcntSetGate(index);
_rcntSet(index);
}
+3 -3
View File
@@ -60,13 +60,13 @@ struct Counter
};
u32 target, hold;
u32 rate, interrupt;
u32 startCycle; // delta values should be signed.
u64 startCycle; // delta values should be signed.
};
struct SyncCounter
{
u32 Mode;
u32 startCycle; // start cycle of timer
u64 startCycle; // start cycle of timer
s32 deltaCycles;
};
@@ -118,7 +118,7 @@ extern SyncCounter hsyncCounter;
extern SyncCounter vsyncCounter;
extern s32 nextDeltaCounter; // delta until the next counter event (must be signed)
extern u32 nextStartCounter;
extern u64 nextStartCounter;
extern uint g_FrameCount;
extern void rcntUpdate_hScanline();
+1 -1
View File
@@ -15,7 +15,7 @@ static __fi void IntCHackCheck()
{
// Sanity check: To protect from accidentally "rewinding" the cyclecount
// on the few times nextBranchCycle can be behind our current cycle.
s32 diff = cpuRegs.nextEventCycle - cpuRegs.cycle;
s64 diff = cpuRegs.nextEventCycle - cpuRegs.cycle;
if (diff > 0 && (cpuRegs.cycle - cpuRegs.lastEventCycle) > 8) cpuRegs.cycle = cpuRegs.nextEventCycle;
}
+1 -1
View File
@@ -39,7 +39,7 @@ alignas(16) const int non_linear_quantizer_scale[32] =
56, 64, 72, 80, 88, 96, 104, 112
};
uint eecount_on_last_vdec = 0;
u64 eecount_on_last_vdec = 0;
bool FMVstarted = false;
bool EnableFMV = false;
+1 -1
View File
@@ -284,7 +284,7 @@ extern bool FMVstarted;
extern bool EnableFMV;
alignas(16) extern tIPU_cmd ipu_cmd;
extern uint eecount_on_last_vdec;
extern u64 eecount_on_last_vdec;
extern void ipuReset();
+2 -2
View File
@@ -273,7 +273,7 @@ void ipuCMDProcess()
void ipu0Interrupt()
{
IPU_LOG("ipu0Interrupt: %x", cpuRegs.cycle);
IPU_LOG("ipu0Interrupt: %llx", cpuRegs.cycle);
if(ipu0ch.qwc > 0)
{
@@ -289,7 +289,7 @@ void ipu0Interrupt()
__fi void ipu1Interrupt()
{
IPU_LOG("ipu1Interrupt %x:", cpuRegs.cycle);
IPU_LOG("ipu1Interrupt %llx:", cpuRegs.cycle);
if(!IPU1Status.DMAFinished || IPU1Status.InProgress) //Sanity Check
{
+1 -1
View File
@@ -251,7 +251,7 @@ static __fi void _doBranch_shared(u32 tar)
if (can_skip)
{
if (static_cast<s32>(cpuRegs.nextEventCycle - cpuRegs.cycle) > 0)
if (static_cast<s64>(cpuRegs.nextEventCycle - cpuRegs.cycle) > 0)
cpuRegs.cycle = cpuRegs.nextEventCycle;
else
cpuRegs.nextEventCycle = cpuRegs.cycle;
-3
View File
@@ -164,9 +164,6 @@ alignas(16) extern psxRegisters psxRegs;
#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register
extern s32 EEsCycle;
extern u32 EEoCycle;
#endif
extern s32 psxNextDeltaCounter;
+4 -4
View File
@@ -32,7 +32,7 @@
using namespace R5900; // for R5900 disasm tools
s32 EEsCycle; // used to sync the IOP to the EE
u32 EEoCycle;
u64 EEoCycle;
alignas(16) cpuRegistersPack _cpuRegistersPack;
alignas(16) tlbs tlb[48];
@@ -168,7 +168,7 @@ void cpuTlbMiss(u32 addr, u32 bd, u32 excode)
{
// Avoid too much spamming on the interpreter
if (Cpu != &intCpu || IsDebugBuild) {
Console.Error("cpuTlbMiss pc:%x, cycl:%x, addr: %x, status=%x, code=%x",
Console.Error("cpuTlbMiss pc:%x, cycl:%llx, addr: %x, status=%x, code=%x",
cpuRegs.pc, cpuRegs.cycle, addr, cpuRegs.CP0.n.Status.val, excode);
}
@@ -190,7 +190,7 @@ void cpuTlbMissW(u32 addr, u32 bd) {
}
// sets a branch test to occur some time from an arbitrary starting point.
__fi void cpuSetNextEvent( u32 startCycle, s32 delta )
__fi void cpuSetNextEvent( u64 startCycle, s32 delta )
{
// typecast the conditional to signed so that things don't blow up
// if startCycle is greater than our next branch cycle.
@@ -221,7 +221,7 @@ __fi int cpuGetCycles(int interrupt)
// tests the cpu cycle against the given start and delta values.
// Returns true if the delta time has passed.
__fi int cpuTestCycle( u32 startCycle, s32 delta )
__fi int cpuTestCycle( u64 startCycle, s32 delta )
{
// typecast the conditional to signed so that things don't explode
// if the startCycle is ahead of our current cpu cycle.
+9 -9
View File
@@ -15,7 +15,7 @@ extern const char* const bios[256];
}
extern s32 EEsCycle;
extern u32 EEoCycle;
extern u64 EEoCycle;
union GPR_reg { // Declare union type GPR register
u128 UQ;
@@ -121,8 +121,8 @@ struct cpuRegisters {
u32 code; // current instruction
PERFregs PERF;
u32 eCycle[32];
u32 sCycle[32]; // for internal counters
u32 cycle; // calculate cpucycles..
u64 sCycle[32]; // for internal counters
u64 cycle; // calculate cpucycles..
u32 interrupt;
int branch;
int opmode; // operating mode
@@ -131,10 +131,10 @@ struct cpuRegisters {
u32 pcWriteback;
// if cpuRegs.cycle is greater than this cycle, should check cpuEventTest for updates
u32 nextEventCycle;
u32 lastEventCycle;
u32 lastCOP0Cycle;
u32 lastPERFCycle[2];
u64 nextEventCycle;
u64 lastEventCycle;
u64 lastCOP0Cycle;
u64 lastPERFCycle[2];
};
// used for optimization
@@ -405,9 +405,9 @@ extern void cpuClearInt(uint n);
extern void GoemonPreloadTlb();
extern void GoemonUnloadTlb(u32 key);
extern void cpuSetNextEvent( u32 startCycle, s32 delta );
extern void cpuSetNextEvent( u64 startCycle, s32 delta );
extern void cpuSetNextEventDelta( s32 delta );
extern int cpuTestCycle( u32 startCycle, s32 delta );
extern int cpuTestCycle( u64 startCycle, s32 delta );
extern void cpuSetEvent();
extern int cpuGetCycles(int interrupt);
+1 -1
View File
@@ -26,7 +26,7 @@ enum class FreezeAction
// [SAVEVERSION+]
// This informs the auto updater that the users savestates will be invalidated.
static const u32 g_SaveVersion = (0x9A57 << 16) | 0x0000;
static const u32 g_SaveVersion = (0x9A58 << 16) | 0x0000;
// the freezing data between submodules and core
+3 -3
View File
@@ -128,7 +128,7 @@ struct alignas(16) VURegs
// flags/cycle are needed by VIF dma code, so they have to be here (for now)
// We may replace these by accessors in the future, if merited.
u32 cycle;
u64 cycle;
u32 flags;
// Current opcode being interpreted or recompiled (this var is used by Interps
@@ -156,7 +156,7 @@ struct alignas(16) VURegs
u32 statusflag;
u32 clipflag;
s32 nextBlockCycles;
s64 nextBlockCycles;
u8* Mem;
u8* Micro;
@@ -164,7 +164,7 @@ struct alignas(16) VURegs
u32 xgkickaddr;
u32 xgkickdiff;
u32 xgkicksizeremaining;
u32 xgkicklastcycle;
u64 xgkicklastcycle;
u32 xgkickcyclecount;
u32 xgkickenable;
u32 xgkickendpacket;
+3 -3
View File
@@ -46,7 +46,7 @@ __fi void _vu0run(bool breakOnMbit, bool addCycles, bool sync_only) {
if (!(VU0.VI[REG_VPU_STAT].UL & 1)) return;
//VU0 is ahead of the EE and M-Bit is already encountered, so no need to wait for it, just catch up the EE
if ((VU0.flags & VUFLAG_MFLAGSET) && breakOnMbit && (s32)(cpuRegs.cycle - VU0.cycle) <= 0)
if ((VU0.flags & VUFLAG_MFLAGSET) && breakOnMbit && (s64)(cpuRegs.cycle - VU0.cycle) <= 0)
{
cpuRegs.cycle = VU0.cycle;
return;
@@ -55,12 +55,12 @@ __fi void _vu0run(bool breakOnMbit, bool addCycles, bool sync_only) {
if(!EmuConfig.Cpu.Recompiler.EnableEE)
intUpdateCPUCycles();
u32 startcycle = cpuRegs.cycle;
u64 startcycle = cpuRegs.cycle;
s32 runCycles = 0x7fffffff;
if (sync_only)
{
runCycles = (s32)(cpuRegs.cycle - VU0.cycle);
runCycles = (s64)(cpuRegs.cycle - VU0.cycle);
if (runCycles < 0)
return;
+1 -1
View File
@@ -276,7 +276,7 @@ __fi void vif1VUFinish()
__fi void vif1Interrupt()
{
VIF_LOG("vif1Interrupt: %8.8x chcr %x, done %x, qwc %x", cpuRegs.cycle, vif1ch.chcr._u32, vif1.done, vif1ch.qwc);
VIF_LOG("vif1Interrupt: %8.8llx chcr %x, done %x, qwc %x", cpuRegs.cycle, vif1ch.chcr._u32, vif1.done, vif1ch.qwc);
g_vif1Cycles = 0;
+49 -49
View File
@@ -135,13 +135,13 @@ void recMFC0()
if (_Rd_ == 9)
{
// This case needs to be handled even if the write-back is ignored (_Rt_ == 0 )
xMOV(ecx, ptr32[&cpuRegs.cycle]);
xADD(ecx, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], ecx); // update cycles
xMOV(eax, ecx);
xSUB(eax, ptr[&cpuRegs.lastCOP0Cycle]);
xADD(ptr[&cpuRegs.CP0.n.Count], eax);
xMOV(ptr[&cpuRegs.lastCOP0Cycle], ecx);
xMOV(rcx, ptr64[&cpuRegs.cycle]);
xADD(rcx, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
xMOV(rax, rcx);
xSUB(rax, ptr[&cpuRegs.lastCOP0Cycle]);
xADD(ptr[&cpuRegs.CP0.n.Count], rax);
xMOV(ptr[&cpuRegs.lastCOP0Cycle], rcx);
if (!_Rt_)
return;
@@ -164,9 +164,9 @@ void recMFC0()
else if (0 == (_Imm_ & 2)) // MFPC 0, only LSB of register matters
{
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)COP0_UpdatePCCR);
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
@@ -175,9 +175,9 @@ void recMFC0()
else // MFPC 1
{
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)COP0_UpdatePCCR);
const int regt = _allocX86reg(X86TYPE_GPR, _Rt_, MODE_WRITE);
@@ -204,9 +204,9 @@ void recMTC0()
{
case 12:
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)WriteCP0Status, g_cpuConstRegs[_Rt_].UL[0]);
break;
@@ -216,10 +216,10 @@ void recMTC0()
break;
case 9:
xMOV(ecx, ptr32[&cpuRegs.cycle]);
xADD(ecx, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], ecx); // update cycles
xMOV(ptr[&cpuRegs.lastCOP0Cycle], ecx);
xMOV(rcx, ptr64[&cpuRegs.cycle]);
xADD(rcx, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
xMOV(ptr64[&cpuRegs.lastCOP0Cycle], rcx);
xMOV(ptr32[&cpuRegs.CP0.r[9]], g_cpuConstRegs[_Rt_].UL[0]);
break;
@@ -230,28 +230,28 @@ void recMTC0()
break;
// Updates PCRs and sets the PCCR.
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)COP0_UpdatePCCR);
xMOV(ptr32[&cpuRegs.PERF.n.pccr], g_cpuConstRegs[_Rt_].UL[0]);
xFastCall((void*)COP0_DiagnosticPCCR);
}
else if (0 == (_Imm_ & 2)) // MTPC 0, only LSB of register matters
{
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xMOV(ptr32[&cpuRegs.PERF.n.pcr0], g_cpuConstRegs[_Rt_].UL[0]);
xMOV(ptr[&cpuRegs.lastPERFCycle[0]], eax);
xMOV(ptr64[&cpuRegs.lastPERFCycle[0]], rax);
}
else // MTPC 1
{
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xMOV(ptr32[&cpuRegs.PERF.n.pcr1], g_cpuConstRegs[_Rt_].UL[0]);
xMOV(ptr[&cpuRegs.lastPERFCycle[1]], eax);
xMOV(ptr64[&cpuRegs.lastPERFCycle[1]], rax);
}
break;
@@ -271,9 +271,9 @@ void recMTC0()
case 12:
_eeMoveGPRtoR(arg1reg, _Rt_);
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)WriteCP0Status);
break;
@@ -284,11 +284,11 @@ void recMTC0()
break;
case 9:
xMOV(ecx, ptr32[&cpuRegs.cycle]);
xADD(ecx, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], ecx); // update cycles
xMOV(rcx, ptr64[&cpuRegs.cycle]);
xADD(rcx, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
_eeMoveGPRtoM((uptr)&cpuRegs.CP0.r[9], _Rt_);
xMOV(ptr[&cpuRegs.lastCOP0Cycle], ecx);
xMOV(ptr64[&cpuRegs.lastCOP0Cycle], rcx);
break;
case 25:
@@ -297,28 +297,28 @@ void recMTC0()
if (0 != (_Imm_ & 0x3E)) // only effective when the register is 0
break;
iFlushCall(FLUSH_INTERPRETER);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xFastCall((void*)COP0_UpdatePCCR);
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_);
xFastCall((void*)COP0_DiagnosticPCCR);
}
else if (0 == (_Imm_ & 2)) // MTPC 0, only LSB of register matters
{
xMOV(ecx, ptr32[&cpuRegs.cycle]);
xADD(ecx, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], ecx); // update cycles
xMOV(rcx, ptr64[&cpuRegs.cycle]);
xADD(rcx, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr0, _Rt_);
xMOV(ptr[&cpuRegs.lastPERFCycle[0]], ecx);
xMOV(ptr64[&cpuRegs.lastPERFCycle[0]], rcx);
}
else // MTPC 1
{
xMOV(ecx, ptr32[&cpuRegs.cycle]);
xADD(ecx, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], ecx); // update cycles
xMOV(rcx, ptr64[&cpuRegs.cycle]);
xADD(rcx, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rcx); // update cycles
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pcr1, _Rt_);
xMOV(ptr[&cpuRegs.lastPERFCycle[1]], ecx);
xMOV(ptr64[&cpuRegs.lastPERFCycle[1]], rcx);
}
break;
+21 -21
View File
@@ -326,8 +326,8 @@ void recBranchCall(void (*func)())
// In order to make sure a branch test is performed, the nextBranchCycle is set
// to the current cpu cycle.
xMOV(eax, ptr[&cpuRegs.cycle]);
xMOV(ptr[&cpuRegs.nextEventCycle], eax);
xMOV(rax, ptr64[&cpuRegs.cycle]);
xMOV(ptr64[&cpuRegs.nextEventCycle], rax);
recCall(func);
g_branch = 2;
@@ -1362,20 +1362,20 @@ static void iBranchTest(u32 newpc)
if (EmuConfig.Speedhacks.WaitLoop && s_nBlockFF && newpc == s_branchTo)
{
xMOV(eax, ptr32[&cpuRegs.nextEventCycle]);
xADD(ptr32[&cpuRegs.cycle], scaleblockcycles());
xCMP(eax, ptr32[&cpuRegs.cycle]);
xCMOVS(eax, ptr32[&cpuRegs.cycle]);
xMOV(ptr32[&cpuRegs.cycle], eax);
xMOV(rax, ptr64[&cpuRegs.nextEventCycle]);
xADD(ptr64[&cpuRegs.cycle], scaleblockcycles());
xCMP(rax, ptr64[&cpuRegs.cycle]);
xCMOVS(rax, ptr64[&cpuRegs.cycle]);
xMOV(ptr64[&cpuRegs.cycle], rax);
xJMP((void*)DispatcherEvent);
}
else
{
xMOV(eax, ptr[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles());
xMOV(ptr[&cpuRegs.cycle], eax); // update cycles
xSUB(eax, ptr[&cpuRegs.nextEventCycle]);
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xSUB(rax, ptr64[&cpuRegs.nextEventCycle]);
if (newpc == 0xffffffff)
xJS(DispatcherReg);
@@ -2141,17 +2141,17 @@ static bool recSkipTimeoutLoop(s32 reg, bool is_timeout_loop)
// if new_v0 > 0 { jump to dispatcher because loop exited early }
// else new_v0 is 0, so exit loop
xMOV(ebx, ptr32[&cpuRegs.cycle]); // ebx = cycle
xMOV(ecx, ptr32[&cpuRegs.nextEventCycle]); // ecx = nextEventCycle
xCMP(ebx, ecx);
xMOV(rbx, ptr64[&cpuRegs.cycle]); // ebx = cycle
xMOV(rcx, ptr64[&cpuRegs.nextEventCycle]); // ecx = nextEventCycle
xCMP(rbx, rcx);
//xJAE((void*)DispatcherEvent); // jump to dispatcher if event immediately
// TODO: In the case where nextEventCycle < cycle because it's overflowed, tack 8
// cycles onto the event count, so hopefully it'll wrap around. This is pretty
// gross, but until we switch to 64-bit counters, not many better options.
xForwardJB8 not_dispatcher;
xADD(ebx, 8);
xMOV(ptr32[&cpuRegs.cycle], ebx);
xADD(rbx, 8);
xMOV(ptr64[&cpuRegs.cycle], rbx);
xJMP((void*)DispatcherEvent);
not_dispatcher.SetTarget();
@@ -2159,10 +2159,10 @@ static bool recSkipTimeoutLoop(s32 reg, bool is_timeout_loop)
xLEA(rax, ptrNative[rdx * 8 + rbx]); // edx = v0 * 8 + cycle
xCMP(rcx, rax);
xCMOVB(rax, rcx); // eax = new_cycles = min(v8 * 8, nextEventCycle)
xMOV(ptr32[&cpuRegs.cycle], eax); // writeback new_cycles
xSUB(eax, ebx); // new_cycles -= cycle
xSHR(eax, 3); // compute new v0 value
xSUB(edx, eax); // v0 -= cycle_diff
xMOV(ptr64[&cpuRegs.cycle], rax); // writeback new_cycles
xSUB(rax, rbx); // new_cycles -= cycle
xSHR(rax, 3); // compute new v0 value
xSUB(rdx, rax); // v0 -= cycle_diff
xMOV(ptr32[&cpuRegs.GPR.r[reg].UL[0]], edx); // write back new value of v0
xJNZ((void*)DispatcherEvent); // jump to dispatcher if new v0 is not zero (i.e. an event)
xMOV(ptr32[&cpuRegs.pc], s_nEndBlock); // otherwise end of loop
@@ -2716,7 +2716,7 @@ StartRecomp:
else
{
xMOV(ptr32[&cpuRegs.pc], pc);
xADD(ptr32[&cpuRegs.cycle], scaleblockcycles());
xADD(ptr64[&cpuRegs.cycle], scaleblockcycles());
recBlocks.Link(HWADDR(pc), xJcc32());
}
}
+1 -1
View File
@@ -354,7 +354,7 @@ _mVUt void mVUcleanUp()
u32 cycles_passed = std::min(mVU.cycles, 3000) * EmuConfig.Speedhacks.EECycleSkip;
if (cycles_passed > 0)
{
s32 vu0_offset = VU0.cycle - cpuRegs.cycle;
s64 vu0_offset = VU0.cycle - cpuRegs.cycle;
cpuRegs.cycle += cycles_passed;
// VU0 needs to stay in sync with the CPU otherwise things get messy
+10 -10
View File
@@ -143,7 +143,7 @@ bool mVUIsReservedCOP2(int hostreg)
void recV##f() \
{ \
iFlushCall(FLUSH_FOR_POSSIBLE_MICRO_EXEC); \
xADD(ptr32[&cpuRegs.cycle], scaleblockcycles_clear()); \
xADD(ptr64[&cpuRegs.cycle], scaleblockcycles_clear()); \
recCall(V##f); \
}
@@ -331,22 +331,22 @@ static void COP2_Interlock(bool mBitSync)
{
iFlushCall(FLUSH_FOR_POSSIBLE_MICRO_EXEC);
_freeX86reg(eax);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xTEST(ptr32[&VU0.VI[REG_VPU_STAT].UL], 0x1);
xForwardJZ32 skipvuidle;
if (mBitSync)
{
xSUB(eax, ptr32[&VU0.cycle]);
xSUB(rax, ptr64[&VU0.cycle]);
// Why do we check this here? Ratchet games, maybe others end up with flickering polygons
// when we use lazy COP2 sync, otherwise. The micro resumption getting deferred an extra
// EE block is apparently enough to cause issues.
if (EmuConfig.Gamefixes.VUSyncHack || EmuConfig.Gamefixes.FullVU0SyncHack)
xSUB(eax, ptr32[&VU0.nextBlockCycles]);
xCMP(eax, 4);
xSUB(rax, ptr64[&VU0.nextBlockCycles]);
xCMP(rax, 4);
xForwardJL32 skip;
xLoadFarAddr(arg1reg, CpuVU0);
xMOV(arg2reg, s_nBlockInterlocked);
@@ -366,9 +366,9 @@ static void mVUSyncVU0()
{
iFlushCall(FLUSH_FOR_POSSIBLE_MICRO_EXEC);
_freeX86reg(eax);
xMOV(eax, ptr32[&cpuRegs.cycle]);
xADD(eax, scaleblockcycles_clear());
xMOV(ptr32[&cpuRegs.cycle], eax); // update cycles
xMOV(rax, ptr64[&cpuRegs.cycle]);
xADD(rax, scaleblockcycles_clear());
xMOV(ptr64[&cpuRegs.cycle], rax); // update cycles
xTEST(ptr32[&VU0.VI[REG_VPU_STAT].UL], 0x1);
xForwardJZ32 skipvuidle;