mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
EE: Switch to 64 bit cycle counter
[SAVEVERSION+]
This commit is contained in:
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user