diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 17c6d12131e4d..41d13581df178 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -7,6 +7,7 @@ #include "CDVD/IsoReader.h" #include "CDVD/IsoFileFormats.h" #include "GS.h" +#include "SIO/Sio.h" #include "Elfheader.h" #include "ps2/BiosTools.h" #include "Recording/InputRecording.h" @@ -1553,13 +1554,20 @@ void cdvdUpdateTrayState() void cdvdVsync() { + // We're counting in frames, but one second isn't exactly 50 or 60 frames in most cases, so we'll keep the fractions. cdvd.RTCcount++; - if (cdvd.RTCcount < GetVerticalFrequency()) + const double verticalFrequency = GetVerticalFrequency(); + if (cdvd.RTCcount < verticalFrequency) return; - cdvd.RTCcount = 0; + + cdvd.RTCcount -= verticalFrequency; cdvdUpdateTrayState(); + // FolderMemoryCard needs information on how much time has passed since the last write + // Call it every second. + sioNextFrame(); + cdvd.RTC.second++; if (cdvd.RTC.second < 60) return; diff --git a/pcsx2/CDVD/CDVD.h b/pcsx2/CDVD/CDVD.h index 5b653bf2aa0e6..6877d35c47c20 100644 --- a/pcsx2/CDVD/CDVD.h +++ b/pcsx2/CDVD/CDVD.h @@ -123,7 +123,7 @@ struct cdvdStruct // Calculates the number of Vsyncs and once it reaches a total number of Vsyncs worth a second with respect to // the videomode's vertical frequency, it updates the real time clock. - int RTCcount; + double RTCcount; cdvdRTC RTC; u32 CurrentSector; diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index 7abfa00f6954e..32a258f10368d 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -31,8 +31,8 @@ Counter counters[4]; SyncCounter hsyncCounter; SyncCounter vsyncCounter; -u32 nextsCounter; // records the cpuRegs.cycle value of the last call to rcntUpdate() -s32 nextCounter; // delta from nextsCounter, in cycles, until the next rcntUpdate() +u32 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. @@ -59,7 +59,7 @@ static bool IsProgressiveVideoMode() void rcntReset(int index) { counters[index].count = 0; - counters[index].sCycleT = cpuRegs.cycle; + counters[index].startCycle = cpuRegs.cycle; } // Updates the state of the nextCounter value (if needed) to serve @@ -76,13 +76,13 @@ static __fi void _rcntSet(int cntidx) if (!rcntCanCount(cntidx) || (counter.mode.ClockSource == 0x3)) return; - if (!counter.mode.TargetInterrupt && !counter.mode.OverflowInterrupt) + if (!counter.mode.TargetInterrupt && !counter.mode.OverflowInterrupt && !counter.mode.ZeroReturn) return; // check for special cases where the overflow or target has just passed // (we probably missed it because we're doing/checking other things) if (counter.count > 0x10000 || counter.count > counter.target) { - nextCounter = 4; + nextDeltaCounter = 4; return; } @@ -91,13 +91,14 @@ static __fi void _rcntSet(int cntidx) // that into account. Adding the difference from that cycle count to the current one // will do the trick! - c = ((0x10000 - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); - c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); - if (c < nextCounter) + c = ((0x10000 - counter.count) * counter.rate) - (cpuRegs.cycle - counter.startCycle); + c += cpuRegs.cycle - nextStartCounter; // adjust for time passed since last rcntUpdate(); + + if (c < nextDeltaCounter) { - nextCounter = c; + nextDeltaCounter = c; - cpuSetNextEvent(nextsCounter, nextCounter); // Need to update on counter resets/target changes + cpuSetNextEvent(nextStartCounter, nextDeltaCounter); // Need to update on counter resets/target changes } // Ignore target diff if target is currently disabled. @@ -111,12 +112,13 @@ static __fi void _rcntSet(int cntidx) else { - c = ((counter.target - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); - c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); - if (c < nextCounter) + c = ((counter.target - counter.count) * counter.rate) - (cpuRegs.cycle - counter.startCycle); + c += cpuRegs.cycle - nextStartCounter; // adjust for time passed since last rcntUpdate(); + + if (c < nextDeltaCounter) { - nextCounter = c; - cpuSetNextEvent(nextsCounter, nextCounter); // Need to update on counter resets/target changes + nextDeltaCounter = c; + cpuSetNextEvent(nextStartCounter, nextDeltaCounter); // Need to update on counter resets/target changes } } } @@ -127,22 +129,22 @@ static __fi void cpuRcntSet() int i; // Default to next VBlank - nextsCounter = cpuRegs.cycle; - nextCounter = vsyncCounter.CycleT - (cpuRegs.cycle - vsyncCounter.sCycle); + nextStartCounter = cpuRegs.cycle; + nextDeltaCounter = vsyncCounter.deltaCycles - (cpuRegs.cycle - vsyncCounter.startCycle); // Also check next HSync - s32 nextHsync = hsyncCounter.CycleT - (cpuRegs.cycle - hsyncCounter.sCycle); - if (nextHsync < nextCounter) - nextCounter = nextHsync; + s32 nextHsync = hsyncCounter.deltaCycles - (cpuRegs.cycle - hsyncCounter.startCycle); + if (nextHsync < nextDeltaCounter) + nextDeltaCounter = nextHsync; for (i = 0; i < 4; i++) _rcntSet(i); // sanity check! - if (nextCounter < 0) - nextCounter = 0; + if (nextDeltaCounter < 0) + nextDeltaCounter = 0; - cpuSetNextEvent(nextsCounter, nextCounter); // Need to update on counter resets/target changes + cpuSetNextEvent(nextStartCounter, nextDeltaCounter); // Need to update on counter resets/target changes } @@ -187,11 +189,11 @@ void rcntInit() gsIsInterlaced = VMManager::Internal::IsFastBootInProgress(); hsyncCounter.Mode = MODE_HRENDER; - hsyncCounter.sCycle = cpuRegs.cycle; - vsyncCounter.CycleT = vSyncInfo.hRender; + hsyncCounter.startCycle = cpuRegs.cycle; + hsyncCounter.deltaCycles = vSyncInfo.hRender; vsyncCounter.Mode = MODE_VRENDER; - vsyncCounter.CycleT = vSyncInfo.Render; - vsyncCounter.sCycle = cpuRegs.cycle; + vsyncCounter.deltaCycles = vSyncInfo.Render; + vsyncCounter.startCycle = cpuRegs.cycle; for (i = 0; i < 4; i++) rcntReset(i); @@ -240,31 +242,18 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca info->GSBlank = (u32)(GSBlank / 10000); info->Render = (u32)(Render / 10000); info->Blank = (u32)(Blank / 10000); + const u64 accumilated_vrender = (Render % 10000) + (Blank % 10000); + info->Render += (u32)(accumilated_vrender / 10000); info->hRender = (u32)(hRender / 10000); info->hBlank = (u32)(hBlank / 10000); info->hScanlinesPerFrame = scansPerFrame; - if ((Render % 10000) >= 5000) - info->Render++; - if ((Blank % 10000) >= 5000) - info->Blank++; + const u64 accumilatedHRenderError = (hRender % 10000) + (hBlank % 10000); + const u64 accumilatedHFractional = accumilatedHRenderError % 10000; + info->hRender += (u32)(accumilatedHRenderError / 10000); + info->hSyncError = (accumilatedHFractional * (scansPerFrame / (IsInterlacedVideoMode() ? 2 : 1))) / 10000; - if ((hRender % 10000) >= 5000) - info->hRender++; - if ((hBlank % 10000) >= 5000) - info->hBlank++; - - // Calculate accumulative hSync rounding error per half-frame: - if (IsInterlacedVideoMode()) // gets off the chart in that mode - { - u32 hSyncCycles = ((info->hRender + info->hBlank) * scansPerFrame) / 2; - u32 vSyncCycles = (info->Render + info->Blank); - info->hSyncError = vSyncCycles - hSyncCycles; - //Console.Warning("%d",info->hSyncError); - } - else - info->hSyncError = 0; // Note: In NTSC modes there is some small rounding error in the vsync too, // however it would take thousands of frames for it to amount to anything and // is thus not worth the effort at this time. @@ -419,10 +408,16 @@ void UpdateVSyncRate(bool force) if (custom && video_mode_initialized) Console.WriteLn(Color_StrongGreen, " ... with user configured refresh rate: %.02f Hz", vertical_frequency); - hsyncCounter.CycleT = (hsyncCounter.Mode == MODE_HBLANK) ? vSyncInfo.hBlank : vSyncInfo.hRender; - vsyncCounter.CycleT = (vsyncCounter.Mode == MODE_GSBLANK) ? + s32 hdiff = hsyncCounter.deltaCycles; + s32 vdiff = vsyncCounter.deltaCycles; + hsyncCounter.deltaCycles = (hsyncCounter.Mode == MODE_HBLANK) ? vSyncInfo.hBlank : vSyncInfo.hRender; + vsyncCounter.deltaCycles = (vsyncCounter.Mode == MODE_GSBLANK) ? vSyncInfo.GSBlank : - ((vsyncCounter.Mode == MODE_VSYNC) ? vSyncInfo.Blank : vSyncInfo.Render); + ((vsyncCounter.Mode == MODE_VBLANK) ? vSyncInfo.Blank : vSyncInfo.Render); + + hsyncCounter.startCycle += hdiff - hsyncCounter.deltaCycles; + vsyncCounter.startCycle += vdiff - vsyncCounter.deltaCycles; + cpuRcntSet(); VMManager::Internal::FrameRateChanged(); @@ -504,15 +499,17 @@ static __fi void VSyncStart(u32 sCycle) if (EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) SysTrace.EE.Counters.Write(" ================ EE COUNTER VSYNC START (frame: %d) ================", g_FrameCount); - hwIntcIrq(INTC_VBLANK_S); - psxVBlankStart(); - // Memcard auto ejection - Uses a tick system timed off of real time, decrementing one tick per frame. AutoEject::CountDownTicks(); // Memcard IO detection - Uses a tick system to determine when memcards are no longer being written. MemcardBusy::Decrement(); - rcntStartGate(true, sCycle); // Counters Start Gate code + if (!GSSMODE1reg.SINT) + { + hwIntcIrq(INTC_VBLANK_S); + rcntStartGate(true, sCycle); // Counters Start Gate code + psxVBlankStart(); + } // INTC - VB Blank Start Hack -- // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin @@ -546,6 +543,8 @@ static __fi void VSyncStart(u32 sCycle) static __fi void GSVSync() { // CSR is swapped and GS vBlank IRQ is triggered roughly 3.5 hblanks after VSync Start + if (GSSMODE1reg.SINT) + return; if (IsProgressiveVideoMode()) CSRreg.SetField(); @@ -566,15 +565,12 @@ static __fi void VSyncEnd(u32 sCycle) SysTrace.EE.Counters.Write(" ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount); g_FrameCount++; - - hwIntcIrq(INTC_VBLANK_E); // HW Irq - psxVBlankEnd(); // psxCounters vBlank End - rcntEndGate(true, sCycle); // Counters End Gate Code - - // FolderMemoryCard needs information on how much time has passed since the last write - // Call it every 60 frames - if (!(g_FrameCount % 60)) - sioNextFrame(); + if (!GSSMODE1reg.SINT) + { + hwIntcIrq(INTC_VBLANK_E); // HW Irq + psxVBlankEnd(); // psxCounters vBlank End + rcntEndGate(true, sCycle); // Counters End Gate Code + } // This doesn't seem to be needed here. Games only seem to break with regard to the // vsyncstart irq. @@ -587,76 +583,39 @@ static u32 hsc = 0; static int vblankinc = 0; #endif -__fi void rcntUpdate_hScanline() -{ - if (!cpuTestCycle(hsyncCounter.sCycle, hsyncCounter.CycleT)) - return; - - //iopEventAction = 1; - if (hsyncCounter.Mode == MODE_HBLANK) - { //HBLANK End / HRENDER Begin - rcntEndGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT); - psxHBlankEnd(); - - // Setup the hRender's start and end cycle information: - hsyncCounter.sCycle += vSyncInfo.hBlank; // start (absolute cycle value) - hsyncCounter.CycleT = vSyncInfo.hRender; // endpoint (delta from start value) - hsyncCounter.Mode = MODE_HRENDER; - } - else - { //HBLANK START / HRENDER End - if (!CSRreg.HSINT) - { - CSRreg.HSINT = true; - if (!GSIMR.HSMSK) - gsIrq(); - } - - rcntStartGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT); - psxHBlankStart(); - - // set up the hblank's start and end cycle information: - hsyncCounter.sCycle += vSyncInfo.hRender; // start (absolute cycle value) - hsyncCounter.CycleT = vSyncInfo.hBlank; // endpoint (delta from start value) - hsyncCounter.Mode = MODE_HBLANK; - -#ifdef VSYNC_DEBUG - hsc++; -#endif - } -} - __fi void rcntUpdate_vSync() { - if (!cpuTestCycle(vsyncCounter.sCycle, vsyncCounter.CycleT)) + if (!cpuTestCycle(vsyncCounter.startCycle, vsyncCounter.deltaCycles)) return; - if (vsyncCounter.Mode == MODE_VSYNC) + if (vsyncCounter.Mode == MODE_VBLANK) { - VSyncEnd(vsyncCounter.sCycle + vsyncCounter.CycleT); + vsyncCounter.startCycle += vSyncInfo.Blank; + vsyncCounter.deltaCycles = vSyncInfo.Render; + + VSyncEnd(vsyncCounter.startCycle); - vsyncCounter.sCycle += vSyncInfo.Blank; - vsyncCounter.CycleT = vSyncInfo.Render; vsyncCounter.Mode = MODE_VRENDER; // VSYNC END - Render begin } else if (vsyncCounter.Mode == MODE_GSBLANK) // GS CSR Swap and interrupt { GSVSync(); - vsyncCounter.Mode = MODE_VSYNC; + vsyncCounter.Mode = MODE_VBLANK; // Don't set the start cycle, makes it easier to calculate the correct Vsync End time - vsyncCounter.CycleT = vSyncInfo.Blank; + vsyncCounter.deltaCycles = vSyncInfo.Blank; } else // VSYNC Start { - VSyncStart(vsyncCounter.sCycle + vsyncCounter.CycleT); + vsyncCounter.startCycle += vSyncInfo.Render; + vsyncCounter.deltaCycles = vSyncInfo.GSBlank; + + VSyncStart(vsyncCounter.startCycle); - vsyncCounter.sCycle += vSyncInfo.Render; - vsyncCounter.CycleT = vSyncInfo.GSBlank; vsyncCounter.Mode = MODE_GSBLANK; // Accumulate hsync rounding errors: - hsyncCounter.sCycle += vSyncInfo.hSyncError; + hsyncCounter.deltaCycles += vSyncInfo.hSyncError; #ifdef VSYNC_DEBUG vblankinc++; @@ -671,6 +630,53 @@ __fi void rcntUpdate_vSync() } } +__fi void rcntUpdate_hScanline() +{ + if (!cpuTestCycle(hsyncCounter.startCycle, hsyncCounter.deltaCycles)) + return; + + //iopEventAction = 1; + if (hsyncCounter.Mode == MODE_HBLANK) + { //HBLANK End / HRENDER Begin + + // Setup the hRender's start and end cycle information: + hsyncCounter.startCycle += vSyncInfo.hBlank; // start (absolute cycle value) + hsyncCounter.deltaCycles = vSyncInfo.hRender; // endpoint (delta from start value) + if (!GSSMODE1reg.SINT) + { + rcntEndGate(false, hsyncCounter.startCycle); + psxHBlankEnd(); + } + + hsyncCounter.Mode = MODE_HRENDER; + } + else + { //HBLANK START / HRENDER End + + // set up the hblank's start and end cycle information: + hsyncCounter.startCycle += vSyncInfo.hRender; // start (absolute cycle value) + hsyncCounter.deltaCycles = vSyncInfo.hBlank; // endpoint (delta from start value) + if (!GSSMODE1reg.SINT) + { + if (!CSRreg.HSINT) + { + CSRreg.HSINT = true; + if (!GSIMR.HSMSK) + gsIrq(); + } + + rcntStartGate(false, hsyncCounter.startCycle); + psxHBlankStart(); + } + + hsyncCounter.Mode = MODE_HBLANK; + +#ifdef VSYNC_DEBUG + hsc++; +#endif + } +} + static __fi void _cpuTestTarget(int i) { if (counters[i].count < counters[i].target) @@ -726,7 +732,23 @@ __fi bool rcntCanCount(int i) (counters[i].mode.GateSource == 1 && (vsyncCounter.Mode == MODE_VRENDER || counters[i].mode.GateMode != 0))); } - // forceinline note: this method is called from two locations, but one +__fi void rcntSyncCounter(int i) +{ + if (counters[i].mode.ClockSource != 0x3) // don't count hblank sources + { + 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); + + if (rcntCanCount(i)) + counters[i].count += change; + } + else + counters[i].startCycle = cpuRegs.cycle; +} + +// forceinline note: this method is called from two locations, but one // of them is the interpreter, which doesn't count. ;) So might as // well forceinline it! __fi void rcntUpdate() @@ -739,22 +761,13 @@ __fi void rcntUpdate() for (int i = 0; i <= 3; i++) { - if (!rcntCanCount(i)) - continue; + rcntSyncCounter(i); - if (counters[i].mode.ClockSource != 0x3) // don't count hblank sources - { - const u32 change = (cpuRegs.cycle - counters[i].sCycleT) / counters[i].rate; - counters[i].count += change; - counters[i].sCycleT += change * counters[i].rate; + if (counters[i].mode.ClockSource == 0x3 || !rcntCanCount(i)) // don't count hblank sources + continue; - // Check Counter Targets and Overflows: - // Check Overflow first, in case the target is 0 - _cpuTestOverflow(i); - _cpuTestTarget(i); - } - else - counters[i].sCycleT = cpuRegs.cycle; + _cpuTestOverflow(i); + _cpuTestTarget(i); } cpuRcntSet(); @@ -784,10 +797,8 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle) // Update counters using the hblank as the clock. This keeps the hblank source // nicely in sync with the counters and serves as an optimization also, since these // counter won't receive special rcntUpdate scheduling. - // Note: Target and overflow tests must be done here since they won't be done // currectly by rcntUpdate (since it's not being scheduled for these counters) - counters[i].count += HBLANK_COUNTER_SPEED; _cpuTestOverflow(i); _cpuTestTarget(i); @@ -803,11 +814,10 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle) { case 0x0: //Count When Signal is low (V_RENDER ONLY) - // Just set the start cycle (sCycleT) -- counting will be done as needed + // Just set the start cycle -- counting will be done as needed // for events (overflows, targets, mode changes, and the gate off below) - - counters[i].count = rcntRcount(i); - counters[i].sCycleT = sCycle; + rcntSyncCounter(i); + counters[i].startCycle = sCycle & ~(counters[i].rate - 1); EECNT_LOG("EE Counter[%d] %s StartGate Type0, count = %x", i, isVblank ? "vblank" : "hblank", counters[i].count); break; @@ -816,14 +826,12 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle) break; case 0x1: // Reset on Vsync start case 0x3: // Reset on Vsync start and end - { + rcntSyncCounter(i); counters[i].count = 0; counters[i].target &= 0xffff; - const u32 change = (sCycle - counters[i].sCycleT) / counters[i].rate; - counters[i].sCycleT = sCycle - ((sCycle - counters[i].sCycleT) - (change * counters[i].rate)); + counters[i].startCycle = sCycle & ~(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; } } @@ -850,7 +858,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].sCycleT = sCycle; + counters[i].startCycle = sCycle & ~(counters[i].rate - 1); EECNT_LOG("EE Counter[%d] %s EndGate Type0, count = %x", i, isVblank ? "vblank" : "hblank", counters[i].count); @@ -862,14 +870,12 @@ static __fi void rcntEndGate(bool isVblank, u32 sCycle) case 0x2: // Reset on Vsync end case 0x3: // Reset on Vsync start and end - { + rcntSyncCounter(i); EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", i, isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count); counters[i].count = 0; counters[i].target &= 0xffff; - const u32 change = (sCycle - counters[i].sCycleT) / counters[i].rate; - counters[i].sCycleT = sCycle - ((sCycle - counters[i].sCycleT) - (change * counters[i].rate)); - } + counters[i].startCycle = sCycle & ~(counters[i].rate - 1); break; } } @@ -879,14 +885,7 @@ static __fi void rcntEndGate(bool isVblank, u32 sCycle) static __fi void rcntWmode(int index, u32 value) { - if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3) - { - const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; - counters[index].count += change; - counters[index].sCycleT += change * counters[index].rate; - } - else - counters[index].sCycleT = cpuRegs.cycle; + rcntSyncCounter(index); // Clear OverflowReached and TargetReached flags (0xc00 mask), but *only* if they are set to 1 in the // given value. (yes, the bits are cleared when written with '1's). @@ -902,6 +901,8 @@ static __fi void rcntWmode(int index, u32 value) case 3: counters[index].rate = vSyncInfo.hBlank+vSyncInfo.hRender; break; } + // 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); _rcntSetGate(index); _rcntSet(index); } @@ -911,13 +912,7 @@ static __fi void rcntWcount(int index, u32 value) EECNT_LOG("EE Counter[%d] writeCount = %x, oldcount=%x, target=%x", index, value, counters[index].count, counters[index].target); // re-calculate the start cycle of the counter based on elapsed time since the last counter update: - if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3) - { - const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; - counters[index].sCycleT += change * counters[index].rate; - } - else - counters[index].sCycleT = cpuRegs.cycle; + rcntSyncCounter(index); counters[index].count = value & 0xffff; @@ -940,14 +935,7 @@ static __fi void rcntWtarget(int index, u32 value) // If the target is behind the current count, set it up so that the counter must // overflow first before the target fires: - if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3) - { - const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; - counters[index].count += change; - counters[index].sCycleT += change * counters[index].rate; - } - else - counters[index].sCycleT = cpuRegs.cycle; + rcntSyncCounter(index); if (counters[index].target <= counters[index].count) counters[index].target |= EECNT_FUTURE_TARGET; @@ -965,11 +953,9 @@ __fi u32 rcntRcount(int index) { u32 ret; - // only count if the counter is turned on (0x80) and is not an hsync gate (!0x03) - if (rcntCanCount(index) && (counters[index].mode.ClockSource != 0x3)) - ret = counters[index].count + ((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); - else - ret = counters[index].count; + rcntSyncCounter(index); + + ret = counters[index].count; // Spams the Console. EECNT_LOG("EE Counter[%d] readCount32 = %x", index, ret); @@ -984,24 +970,25 @@ __fi u16 rcntRead32(u32 mem) // are all fixed to 0, so we always truncate everything in these two pages using a u16 // return value! --air - switch( mem ) { - case(RCNT0_COUNT): return (u16)rcntRcount(0); - case(RCNT0_MODE): return (u16)counters[0].modeval; - case(RCNT0_TARGET): return (u16)counters[0].target; - case(RCNT0_HOLD): return (u16)counters[0].hold; - - case(RCNT1_COUNT): return (u16)rcntRcount(1); - case(RCNT1_MODE): return (u16)counters[1].modeval; - case(RCNT1_TARGET): return (u16)counters[1].target; - case(RCNT1_HOLD): return (u16)counters[1].hold; - - case(RCNT2_COUNT): return (u16)rcntRcount(2); - case(RCNT2_MODE): return (u16)counters[2].modeval; - case(RCNT2_TARGET): return (u16)counters[2].target; - - case(RCNT3_COUNT): return (u16)rcntRcount(3); - case(RCNT3_MODE): return (u16)counters[3].modeval; - case(RCNT3_TARGET): return (u16)counters[3].target; + switch( mem ) + { + case(RCNT0_COUNT): return (u16)rcntRcount(0); + case(RCNT0_MODE): return (u16)counters[0].modeval; + case(RCNT0_TARGET): return (u16)counters[0].target; + case(RCNT0_HOLD): return (u16)counters[0].hold; + + case(RCNT1_COUNT): return (u16)rcntRcount(1); + case(RCNT1_MODE): return (u16)counters[1].modeval; + case(RCNT1_TARGET): return (u16)counters[1].target; + case(RCNT1_HOLD): return (u16)counters[1].hold; + + case(RCNT2_COUNT): return (u16)rcntRcount(2); + case(RCNT2_MODE): return (u16)counters[2].modeval; + case(RCNT2_TARGET): return (u16)counters[2].target; + + case(RCNT3_COUNT): return (u16)rcntRcount(3); + case(RCNT3_MODE): return (u16)counters[3].modeval; + case(RCNT3_TARGET): return (u16)counters[3].target; } return psHu16(mem); @@ -1016,24 +1003,25 @@ __fi bool rcntWrite32(u32 mem, mem32_t& value) // count, mode, target, and hold. This will allow for a simplified handler for register // reads. - switch( mem ) { - case(RCNT0_COUNT): return rcntWcount(0, value), false; - case(RCNT0_MODE): return rcntWmode(0, value), false; - case(RCNT0_TARGET): return rcntWtarget(0, value), false; - case(RCNT0_HOLD): return rcntWhold(0, value), false; - - case(RCNT1_COUNT): return rcntWcount(1, value), false; - case(RCNT1_MODE): return rcntWmode(1, value), false; - case(RCNT1_TARGET): return rcntWtarget(1, value), false; - case(RCNT1_HOLD): return rcntWhold(1, value), false; - - case(RCNT2_COUNT): return rcntWcount(2, value), false; - case(RCNT2_MODE): return rcntWmode(2, value), false; - case(RCNT2_TARGET): return rcntWtarget(2, value), false; - - case(RCNT3_COUNT): return rcntWcount(3, value), false; - case(RCNT3_MODE): return rcntWmode(3, value), false; - case(RCNT3_TARGET): return rcntWtarget(3, value), false; + switch( mem ) + { + case(RCNT0_COUNT): return rcntWcount(0, value), false; + case(RCNT0_MODE): return rcntWmode(0, value), false; + case(RCNT0_TARGET): return rcntWtarget(0, value), false; + case(RCNT0_HOLD): return rcntWhold(0, value), false; + + case(RCNT1_COUNT): return rcntWcount(1, value), false; + case(RCNT1_MODE): return rcntWmode(1, value), false; + case(RCNT1_TARGET): return rcntWtarget(1, value), false; + case(RCNT1_HOLD): return rcntWhold(1, value), false; + + case(RCNT2_COUNT): return rcntWcount(2, value), false; + case(RCNT2_MODE): return rcntWmode(2, value), false; + case(RCNT2_TARGET): return rcntWtarget(2, value), false; + + case(RCNT3_COUNT): return rcntWcount(3, value), false; + case(RCNT3_MODE): return rcntWmode(3, value), false; + case(RCNT3_TARGET): return rcntWtarget(3, value), false; } // unhandled .. do memory writeback. @@ -1051,8 +1039,8 @@ bool SaveStateBase::rcntFreeze() Freeze(counters); Freeze(hsyncCounter); Freeze(vsyncCounter); - Freeze(nextCounter); - Freeze(nextsCounter); + Freeze(nextDeltaCounter); + Freeze(nextStartCounter); Freeze(vSyncInfo); Freeze(gsVideoMode); Freeze(gsIsInterlaced); diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index 7e8e325e631e3..b1e5cfb359b73 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -60,14 +60,14 @@ struct Counter }; u32 target, hold; u32 rate, interrupt; - u32 sCycleT; // delta values should be signed. + u32 startCycle; // delta values should be signed. }; struct SyncCounter { u32 Mode; - u32 sCycle; // start cycle of timer - s32 CycleT; + u32 startCycle; // start cycle of timer + s32 deltaCycles; }; //------------------------------------------------------------------ @@ -107,9 +107,6 @@ struct SyncCounter #define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines #define MODE_VBLANK 0x1 //Set during the Blanking Scanlines #define MODE_GSBLANK 0x2 //Set during the Syncing Scanlines (Delayed GS CSR Swap) -#define MODE_VSYNC 0x3 //Set during the Syncing Scanlines -#define MODE_VBLANK1 0x0 //Set during the Blanking Scanlines (half-frame 1) -#define MODE_VBLANK2 0x1 //Set during the Blanking Scanlines (half-frame 2) #define MODE_HRENDER 0x0 //Set for ~5/6 of 1 Scanline #define MODE_HBLANK 0x1 //Set for the remaining ~1/6 of 1 Scanline @@ -120,13 +117,14 @@ extern Counter counters[4]; extern SyncCounter hsyncCounter; extern SyncCounter vsyncCounter; -extern s32 nextCounter; // delta until the next counter event (must be signed) -extern u32 nextsCounter; +extern s32 nextDeltaCounter; // delta until the next counter event (must be signed) +extern u32 nextStartCounter; extern uint g_FrameCount; extern void rcntUpdate_hScanline(); extern void rcntUpdate_vSync(); extern bool rcntCanCount(int i); +extern void rcntSyncCounter(int i); extern void rcntUpdate(); extern void rcntInit(); diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index 3a28b1fe4a8fb..1f7a6d5481a9a 100644 --- a/pcsx2/GS.cpp +++ b/pcsx2/GS.cpp @@ -52,6 +52,7 @@ static __fi void gsCSRwrite( const tGS_CSR& csr ) if(csr.SIGNAL) { + const bool resume = CSRreg.SIGNAL; // SIGNAL : What's not known here is whether or not the SIGID register should be updated // here or when the IMR is cleared (below). GUNIT_LOG("csr.SIGNAL"); @@ -65,7 +66,9 @@ static __fi void gsCSRwrite( const tGS_CSR& csr ) } else CSRreg.SIGNAL = false; gifUnit.gsSIGNAL.queued = false; - gifUnit.Execute(false, true); // Resume paused transfers + + if (resume) + gifUnit.Execute(false, true); // Resume paused transfers } if (csr.FINISH) { @@ -179,14 +182,17 @@ void gsWrite64_generic( u32 mem, u64 value ) void gsWrite64_page_00( u32 mem, u64 value ) { s_GSRegistersWritten |= (mem == GS_DISPFB1 || mem == GS_DISPFB2 || mem == GS_PMODE); - + bool reqUpdate = false; if (mem == GS_SMODE1 || mem == GS_SMODE2) { if (value != *(u64*)PS2GS_BASE(mem)) - UpdateVSyncRate(false); + reqUpdate = true; } gsWrite64_generic( mem, value ); + + if (reqUpdate) + UpdateVSyncRate(false); } void gsWrite64_page_01( u32 mem, u64 value ) diff --git a/pcsx2/GS.h b/pcsx2/GS.h index a7a8c62ea67f1..bab7645d04819 100644 --- a/pcsx2/GS.h +++ b/pcsx2/GS.h @@ -6,6 +6,7 @@ #include "Common.h" #include "Gif.h" #include "GS/GS.h" +#include "GS/GSRegs.h" #include "common/SingleRegisterTypes.h" @@ -193,42 +194,6 @@ union tGS_IMR bool masked() const { return (SIGMSK || FINISHMSK || HSMSK || VSMSK || EDWMSK); } }; -// -------------------------------------------------------------------------------------- -// GSRegSMODE1 -// -------------------------------------------------------------------------------------- -// Previously, the union was used to get the CMOD bit of the SMODE1 register -// Commenting it out as it's unused right now. (Might potentially be useful in the future) -//union GSRegSMODE1 -//{ -// struct -// { -// u32 RC : 3; -// u32 LC : 7; -// u32 T1248 : 2; -// u32 SLCK : 1; -// u32 CMOD : 2; -// u32 EX : 1; -// u32 PRST : 1; -// u32 SINT : 1; -// u32 XPCK : 1; -// u32 PCK2 : 2; -// u32 SPML : 4; -// u32 GCONT : 1; -// u32 PHS : 1; -// u32 PVS : 1; -// u32 PEHS : 1; -// u32 PEVS : 1; -// u32 CLKSEL : 2; -// u32 NVCK : 1; -// u32 SLCK2 : 1; -// u32 VCKSEL : 2; -// u32 VHP : 1; -// u32 _PAD1 : 27; -// }; -// -// u64 SMODE1; -//}; - // -------------------------------------------------------------------------------------- // GSRegSIGBLID // -------------------------------------------------------------------------------------- @@ -242,7 +207,7 @@ struct GSRegSIGBLID #define PS2GS_BASE(mem) (PS2MEM_GS + (mem & 0x13ff)) #define CSRreg ((tGS_CSR&)*(PS2MEM_GS + 0x1000)) - +#define GSSMODE1reg ((GSRegSMODE1&)*(PS2MEM_GS + 0x0010)) #define GSCSRr ((u32&)*(PS2MEM_GS + 0x1000)) #define GSIMR ((tGS_IMR&)*(PS2MEM_GS + 0x1010)) #define GSSIGLBLID ((GSRegSIGBLID&)*(PS2MEM_GS + 0x1080)) @@ -264,6 +229,7 @@ enum class GS_VideoMode : int }; extern GS_VideoMode gsVideoMode; +extern u32 lastCSRFlag; extern bool gsIsInterlaced; ///////////////////////////////////////////////////////////////////////////// diff --git a/pcsx2/IopCounters.cpp b/pcsx2/IopCounters.cpp index c6c2dd51061ae..a66d146114dbd 100644 --- a/pcsx2/IopCounters.cpp +++ b/pcsx2/IopCounters.cpp @@ -32,8 +32,8 @@ #define PSXSOUNDCLK ((int)(48000)) psxCounter psxCounters[NUM_COUNTERS]; -s32 psxNextCounter; -u32 psxNextsCounter; +s32 psxNextDeltaCounter; +u32 psxNextStartCounter; bool hBlanking = false; bool vBlanking = false; @@ -44,44 +44,27 @@ bool vBlanking = false; // used to disable targets until after an overflow #define IOPCNT_FUTURE_TARGET (0x1000000000ULL) #define IOPCNT_MODE_WRITE_MSK 0x63FF -#define IOPCNT_MODE_FLAG_MSK 0x1800 - -#define IOPCNT_ENABLE_GATE (1 << 0) // enables gate-based counters -#define IOPCNT_MODE_GATE (3 << 1) // 0x6 Gate mode (dependant on counter) -#define IOPCNT_MODE_RESET_CNT (1 << 3) // 0x8 resets the counter on target (if interrupt only?) -#define IOPCNT_INT_TARGET (1 << 4) // 0x10 triggers an interrupt on targets -#define IOPCNT_INT_OVERFLOW (1 << 5) // 0x20 triggers an interrupt on overflows -#define IOPCNT_INT_REPEAT (1 << 6) // 0x40 0=One shot (ignore TOGGLE bit 7) 1=Repeat Fire (Check TOGGLE bit 7) -#define IOPCNT_INT_TOGGLE (1 << 7) // 0x80 0=Pulse (reset on read), 1=toggle each interrupt condition (in 1 shot not reset after fired) -#define IOPCNT_ALT_SOURCE (1 << 8) // 0x100 uses hblank on counters 1 and 3, and PSXCLOCK on counter 0 -#define IOPCNT_INT_REQ (1 << 10) // 0x400 1=Can fire interrupt, 0=Interrupt Fired (reset on read if not 1 shot) -#define IOPCNT_INT_CMPFLAG (1 << 11) // 0x800 1=Target interrupt raised -#define IOPCNT_INT_OFLWFLAG (1 << 12) // 0x1000 1=Overflow interrupt raised +#define IOPCNT_MODE_FLAG_MSK 0x1C00 + +#define IOPCNT_GATE_CNT_LOW 0 // Counts only when signal is low (V/H RENDER). +#define IOPCNT_GATE_CLR_END 1 // Counts continuously, clears at end of BLANK. +#define IOPCNT_GATE_CNT_HIGH_ZERO_OFF 2 // Starts at beginning of next BLANK, counts only during BLANK, returns zero any other time. +#define IOPCNT_GATE_START_AT_END 3 // Starts at end of next BLANK, continuous count, no clear. // Use an arbitrary value to flag HBLANK counters. // These counters will be counted by the hblank gates coming from the EE, // which ensures they stay 100% in sync with the EE's hblank counters. #define PSXHBLANK 0x2001 -#if 0 -// Unused -static void psxRcntReset(int index) -{ - psxCounters[index].count = 0; - psxCounters[index].mode &= ~0x18301C00; - psxCounters[index].sCycleT = psxRegs.cycle; -} -#endif - static bool psxRcntCanCount(int cntidx) { - if (psxCounters[cntidx].mode & IOPCNT_STOPPED) + if (psxCounters[cntidx].mode.stopped) return false; - if (!(psxCounters[cntidx].mode & IOPCNT_ENABLE_GATE)) + if (!(psxCounters[cntidx].mode.gateEnable)) return true; - const u32 gateMode = (psxCounters[cntidx].mode & IOPCNT_MODE_GATE) >> 1; + const u32 gateMode = psxCounters[cntidx].mode.gateMode; if (cntidx == 2 || cntidx == 4 || cntidx == 5) { @@ -92,13 +75,40 @@ static bool psxRcntCanCount(int cntidx) const bool blanking = cntidx == 0 ? hBlanking : vBlanking; // Stop counting if Gate mode 0 (only count when rendering) and blanking or Gate mode 2 (only count when blanking) when not blanking - if ((gateMode == 0 && blanking == true) || (gateMode == 2 && blanking == false)) + if ((gateMode == IOPCNT_GATE_CNT_LOW && blanking == true) || (gateMode == IOPCNT_GATE_CNT_HIGH_ZERO_OFF && blanking == false)) return false; // All other cases allow counting. return true; } +static void psxRcntSync(int cntidx) +{ + if ((psxCounters[cntidx].currentIrqMode.repeatInterrupt) && !(psxCounters[cntidx].currentIrqMode.toggleInterrupt)) + { //Repeat IRQ mode Pulsed, resets a few cycles after the interrupt, this should do. + psxCounters[cntidx].mode.intrEnable = true; + } + + if (psxRcntCanCount(cntidx) && psxCounters[cntidx].rate != PSXHBLANK) + { + const u32 change = (psxRegs.cycle - psxCounters[cntidx].startCycle) / psxCounters[cntidx].rate; + if (change > 0) + { + psxCounters[cntidx].count += change; + psxCounters[cntidx].startCycle += change * psxCounters[cntidx].rate; + + psxCounters[cntidx].startCycle &= ~(psxCounters[cntidx].rate - 1); + } + } + else + { + if (psxCounters[cntidx].mode.gateEnable && psxCounters[cntidx].mode.gateMode == IOPCNT_GATE_CNT_HIGH_ZERO_OFF) + psxCounters[cntidx].count = 0; + + psxCounters[cntidx].startCycle = psxRegs.cycle; + } +} + static void _rcntSet(int cntidx) { u64 overflowCap = (cntidx >= 3) ? 0x100000000ULL : 0x10000; @@ -114,36 +124,33 @@ static void _rcntSet(int cntidx) if (counter.rate == PSXHBLANK || !psxRcntCanCount(cntidx)) return; - if (!(counter.mode & (IOPCNT_INT_TARGET | IOPCNT_INT_OVERFLOW))) - return; // check for special cases where the overflow or target has just passed // (we probably missed it because we're doing/checking other things) if (counter.count > overflowCap || counter.count > counter.target) { - psxNextCounter = 4; + psxNextDeltaCounter = 4; return; } - c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); - c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); + c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.startCycle); + c += psxRegs.cycle - psxNextStartCounter; // adjust for time passed since last rcntUpdate(); - if (c < (u64)psxNextCounter) + if (c < (u64)psxNextDeltaCounter) { - psxNextCounter = (u32)c; - psxSetNextBranch(psxNextsCounter, psxNextCounter); //Need to update on counter resets/target changes + psxNextDeltaCounter = (u32)c; + psxSetNextBranch(psxNextStartCounter, psxNextDeltaCounter); //Need to update on counter resets/target changes } - //if((counter.mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue; if (counter.target & IOPCNT_FUTURE_TARGET) return; - c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT); - c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate(); + c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.startCycle); + c += psxRegs.cycle - psxNextStartCounter; // adjust for time passed since last rcntUpdate(); - if (c < (u64)psxNextCounter) + if (c < (u64)psxNextDeltaCounter) { - psxNextCounter = (u32)c; - psxSetNextBranch(psxNextsCounter, psxNextCounter); //Need to update on counter resets/target changes + psxNextDeltaCounter = (u32)c; + psxSetNextBranch(psxNextStartCounter, psxNextDeltaCounter); //Need to update on counter resets/target changes } } @@ -157,14 +164,18 @@ void psxRcntInit() for (i = 0; i < 3; i++) { psxCounters[i].rate = 1; - psxCounters[i].mode |= IOPCNT_INT_REQ; + psxCounters[i].mode.intrEnable = true; psxCounters[i].target = IOPCNT_FUTURE_TARGET; + psxCounters[i].currentIrqMode.repeatInterrupt = false; + psxCounters[i].currentIrqMode.toggleInterrupt = false; } for (i = 3; i < 6; i++) { psxCounters[i].rate = 1; - psxCounters[i].mode |= IOPCNT_INT_REQ; + psxCounters[i].mode.intrEnable = true; psxCounters[i].target = IOPCNT_FUTURE_TARGET; + psxCounters[i].currentIrqMode.repeatInterrupt = false; + psxCounters[i].currentIrqMode.toggleInterrupt = false; } psxCounters[0].interrupt = 0x10; @@ -176,72 +187,71 @@ void psxRcntInit() psxCounters[5].interrupt = 0x10000; psxCounters[6].rate = 768; - psxCounters[6].CycleT = psxCounters[6].rate; - psxCounters[6].mode = 0x8; + psxCounters[6].deltaCycles = psxCounters[6].rate; + psxCounters[6].mode.modeval = 0x8; psxCounters[7].rate = PSXCLK / 1000; - psxCounters[7].CycleT = psxCounters[7].rate; - psxCounters[7].mode = 0x8; + psxCounters[7].deltaCycles = psxCounters[7].rate; + psxCounters[7].mode.modeval = 0x8; for (i = 0; i < 8; i++) - psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].startCycle = psxRegs.cycle; // Tell the IOP to branch ASAP, so that timers can get // configured properly. - psxNextCounter = 1; - psxNextsCounter = psxRegs.cycle; + psxNextDeltaCounter = 1; + psxNextStartCounter = psxRegs.cycle; } -static bool _rcntFireInterrupt(int i, bool isOverflow) +static void _rcntFireInterrupt(int i, bool isOverflow) { - bool ret = false; -# - if (psxCounters[i].mode & IOPCNT_INT_REQ) - { - // IRQ fired - PSXCNT_LOG("Counter %d %s IRQ Fired count %x", i, isOverflow ? "Overflow" : "Target", psxCounters[i].count); - psxHu32(0x1070) |= psxCounters[i].interrupt; - iopTestIntc(); - ret = true; - } - else + bool updateIntr = psxCounters[i].currentIrqMode.repeatInterrupt; + + if (psxCounters[i].mode.intrEnable) { - //DevCon.Warning("Counter %d IRQ not fired count %x", i, psxCounters[i].count); - if (!(psxCounters[i].mode & IOPCNT_INT_REPEAT)) // One shot + bool already_set = isOverflow ? psxCounters[i].mode.overflowFlag : psxCounters[i].mode.targetFlag; + if (updateIntr || !already_set) { - PSXCNT_LOG("Counter %x ignoring %s interrupt (One Shot)", i, isOverflow ? "Overflow" : "Target"); - return false; + // IRQ fired + //DevCon.Warning("Counter %d %s IRQ Fired count %x target %x psx Cycle %d", i, isOverflow ? "Overflow" : "Target", psxCounters[i].count, psxCounters[i].target, psxRegs.cycle); + psxHu32(0x1070) |= psxCounters[i].interrupt; + iopTestIntc(); } - } - if (psxCounters[i].mode & IOPCNT_INT_TOGGLE) - { - // Toggle mode - psxCounters[i].mode ^= IOPCNT_INT_REQ; // Interrupt flag inverted + updateIntr |= psxCounters[i].currentIrqMode.toggleInterrupt; } - else + + if (updateIntr) { - psxCounters[i].mode &= ~IOPCNT_INT_REQ; // Interrupt flag set low + if (psxCounters[i].currentIrqMode.toggleInterrupt) + { + // Toggle mode + psxCounters[i].mode.intrEnable ^= true; // Interrupt flag inverted + } + else + { + psxCounters[i].mode.intrEnable = false; // Interrupt flag set low + } } - - return ret; } + static void _rcntTestTarget(int i) { if (psxCounters[i].count < psxCounters[i].target) return; PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)", - i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); + i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode.modeval); - if (psxCounters[i].mode & IOPCNT_INT_TARGET) + if (psxCounters[i].mode.targetIntr) { // Target interrupt - if (_rcntFireInterrupt(i, false)) - psxCounters[i].mode |= IOPCNT_INT_CMPFLAG; + _rcntFireInterrupt(i, false); } - if (psxCounters[i].mode & IOPCNT_MODE_RESET_CNT) + psxCounters[i].mode.targetFlag = true; + + if (psxCounters[i].mode.zeroReturn) { // Reset on target psxCounters[i].count -= psxCounters[i].target; @@ -258,20 +268,20 @@ static __fi void _rcntTestOverflow(int i) return; PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)", - i, psxCounters[i].count, maxTarget, psxCounters[i].mode); + i, psxCounters[i].count, maxTarget, psxCounters[i].mode.modeval); - if ((psxCounters[i].mode & IOPCNT_INT_OVERFLOW)) + if (psxCounters[i].mode.overflIntr) { // Overflow interrupt - if (_rcntFireInterrupt(i, true)) - psxCounters[i].mode |= IOPCNT_INT_OFLWFLAG; // Overflow flag + _rcntFireInterrupt(i, true); } + psxCounters[i].mode.overflowFlag = true; + // Update count. // Count wraps around back to zero, while the target is restored (if not in one shot mode). // (high bit of the target gets set by rcntWtarget when the target is behind // the counter value, and thus should not be flagged until after an overflow) - psxCounters[i].count -= maxTarget + 1; psxCounters[i].target &= maxTarget; } @@ -314,10 +324,10 @@ static __fi void _rcntTestOverflow(int i) static void _psxCheckStartGate(int i) { - if (!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) + if (!(psxCounters[i].mode.gateEnable)) return; // Ignore Gate - switch ((psxCounters[i].mode & 0x6) >> 1) + switch (psxCounters[i].mode.gateMode) { case 0x0: // GATE_ON_count - count while gate signal is low (RENDER) @@ -327,7 +337,7 @@ static void _psxCheckStartGate(int i) psxRcntRcount32(i); // Not strictly necessary. - psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].startCycle = psxRegs.cycle & ~(psxCounters[i].rate - 1); break; case 0x1: // GATE_ON_ClearStart - Counts constantly, clears on Blank END @@ -335,10 +345,10 @@ static void _psxCheckStartGate(int i) break; case 0x2: // GATE_ON_Clear_OFF_Start - Counts only when Blanking, clears on both ends, starts counting on next Blank Start. - psxCounters[i].mode &= ~IOPCNT_STOPPED; + psxRcntSync(i); + psxCounters[i].mode.stopped = false; psxCounters[i].count = 0; psxCounters[i].target &= ~IOPCNT_FUTURE_TARGET; - psxCounters[i].sCycleT = psxRegs.cycle; break; case 0x3: //GATE_ON_Start - Starts counting when the next Blank Ends, no clear. @@ -349,33 +359,34 @@ static void _psxCheckStartGate(int i) static void _psxCheckEndGate(int i) { - if (!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) + if (!(psxCounters[i].mode.gateEnable)) return; // Ignore Gate // NOTE: Starting and stopping of modes 0 and 2 are checked in psxRcntCanCount(), only need to update the start cycle and counts. - switch ((psxCounters[i].mode & 0x6) >> 1) + switch (psxCounters[i].mode.gateMode) { case 0x0: // GATE_ON_count - count while gate signal is low (RENDER) - psxCounters[i].sCycleT = psxRegs.cycle; + psxCounters[i].startCycle = psxRegs.cycle & ~(psxCounters[i].rate - 1); break; case 0x1: // GATE_ON_ClearStart - Counts constantly, clears on Blank END + psxRcntSync(i); psxCounters[i].count = 0; psxCounters[i].target &= ~IOPCNT_FUTURE_TARGET; break; case 0x2: // GATE_ON_Clear_OFF_Start - Counts only when Blanking, clears on both ends, starts counting on next Blank Start. // No point in updating the count, since we're gonna clear it. + psxRcntSync(i); psxCounters[i].count = 0; psxCounters[i].target &= ~IOPCNT_FUTURE_TARGET; - psxCounters[i].sCycleT = psxRegs.cycle; break; // do not set the counter case 0x3: // GATE_ON_Start - Starts counting when the next Blank Ends, no clear. - if (psxCounters[i].mode & IOPCNT_STOPPED) + if (psxCounters[i].mode.stopped) { - psxCounters[i].sCycleT = psxRegs.cycle; - psxCounters[i].mode &= ~IOPCNT_STOPPED; + psxCounters[i].startCycle = psxRegs.cycle & ~(psxCounters[i].rate - 1); + psxCounters[i].mode.stopped = false; } break; } @@ -446,8 +457,8 @@ void psxRcntUpdate() { int i; - psxNextCounter = 0x7fffffff; - psxNextsCounter = psxRegs.cycle; + psxNextDeltaCounter = 0x7fffffff; + psxNextStartCounter = psxRegs.cycle; for (i = 0; i < 6; i++) { @@ -455,58 +466,39 @@ void psxRcntUpdate() // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* // be counted here. - if (!psxRcntCanCount(i)) - continue; - - if ((psxCounters[i].mode & IOPCNT_INT_REPEAT) && !(psxCounters[i].mode & IOPCNT_INT_TOGGLE)) - { //Repeat IRQ mode Pulsed, resets a few cycles after the interrupt, this should do. - psxCounters[i].mode |= IOPCNT_INT_REQ; - } + psxRcntSync(i); if (psxCounters[i].rate == PSXHBLANK) continue; - if (psxCounters[i].rate != 1) - { - const u32 change = (psxRegs.cycle - psxCounters[i].sCycleT) / psxCounters[i].rate; - - if (change > 0) - { - psxCounters[i].count += change; - psxCounters[i].sCycleT += change * psxCounters[i].rate; - } - } - else - { - psxCounters[i].count += psxRegs.cycle - psxCounters[i].sCycleT; - psxCounters[i].sCycleT = psxRegs.cycle; - } + if (!psxRcntCanCount(i)) + continue; _rcntTestOverflow(i); _rcntTestTarget(i); } const u32 spu2_delta = (psxRegs.cycle - lClocks) % 768; - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = psxCounters[6].rate - spu2_delta; + psxCounters[6].startCycle = psxRegs.cycle - spu2_delta; + psxCounters[6].deltaCycles = psxCounters[6].rate; SPU2async(); - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter = psxCounters[6].deltaCycles; - DEV9async(1); - const s32 diffusb = psxRegs.cycle - psxCounters[7].sCycleT; - s32 cusb = psxCounters[7].CycleT; + DEV9async(1); + const s32 diffusb = psxRegs.cycle - psxCounters[7].startCycle; + s32 cusb = psxCounters[7].deltaCycles; - if (diffusb >= psxCounters[7].CycleT) + if (diffusb >= psxCounters[7].deltaCycles) { USBasync(diffusb); - psxCounters[7].sCycleT += psxCounters[7].rate * (diffusb / psxCounters[7].rate); - psxCounters[7].CycleT = psxCounters[7].rate; + psxCounters[7].startCycle += psxCounters[7].rate * (diffusb / psxCounters[7].rate); + psxCounters[7].deltaCycles = psxCounters[7].rate; } else cusb -= diffusb; - if (cusb < psxNextCounter) - psxNextCounter = cusb; + if (cusb < psxNextDeltaCounter) + psxNextDeltaCounter = cusb; for (i = 0; i < 6; i++) _rcntSet(i); @@ -517,15 +509,10 @@ void psxRcntUpdate() void psxRcntWcount16(int index, u16 value) { pxAssert(index < 3); - //DevCon.Warning("16bit IOP Counter[%d] writeCount16 = %x", index, value); + PSXCNT_LOG("16bit IOP Counter[%d] writeCount16 = %x", index, value); + + psxRcntSync(index); - if (psxCounters[index].rate != PSXHBLANK) - { - const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; - psxCounters[index].sCycleT += change * psxCounters[index].rate; - } - else - psxCounters[index].sCycleT = psxRegs.cycle; psxCounters[index].count = value & 0xffff; psxCounters[index].target &= 0xffff; @@ -547,16 +534,8 @@ void psxRcntWcount32(int index, u32 value) pxAssert(index >= 3 && index < 6); PSXCNT_LOG("32bit IOP Counter[%d] writeCount32 = %x", index, value); - if (psxCounters[index].rate != PSXHBLANK) - { - // Re-adjust the sCycleT to match where the counter is currently - // (remainder of the rate divided into the time passed will do the trick) + psxRcntSync(index); - const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; - psxCounters[index].sCycleT += change * psxCounters[index].rate; - } - else - psxCounters[index].sCycleT = psxRegs.cycle; psxCounters[index].count = value; psxCounters[index].target &= 0xffffffff; @@ -580,10 +559,16 @@ __fi void psxRcntWmode16(int index, u32 value) pxAssume(index >= 0 && index < 3); psxCounter& counter = psxCounters[index]; + psxCounterMode oldMode = counter.mode; + + counter.mode.modeval = (value & IOPCNT_MODE_WRITE_MSK) | (counter.mode.modeval & IOPCNT_MODE_FLAG_MSK); // Write new value, preserve flags - counter.mode = (value & IOPCNT_MODE_WRITE_MSK) | (counter.mode & IOPCNT_MODE_FLAG_MSK); // Write new value, preserve flags - counter.mode |= IOPCNT_INT_REQ; // IRQ Enable + if (!((oldMode.targetFlag || oldMode.overflowFlag) && (oldMode.targetIntr || oldMode.overflIntr))) + psxRcntSetNewIntrMode(index); + if (counter.mode.repeatIntr != counter.currentIrqMode.repeatInterrupt || counter.mode.toggleIntr != counter.currentIrqMode.toggleInterrupt) + DevCon.Warning("Write to psxCounter[%d] mode old repeat %d new %d old toggle %d new %d", index, counter.currentIrqMode.repeatInterrupt, counter.mode.repeatIntr, counter.currentIrqMode.toggleInterrupt, counter.mode.toggleIntr); + if (value & (1 << 4)) { irqmode += 1; @@ -610,35 +595,27 @@ __fi void psxRcntWmode16(int index, u32 value) } if (index == 2) { - switch (value & 0x200) - { - case 0x000: - psxCounters[2].rate = 1; - break; - case 0x200: - psxCounters[2].rate = 8; - break; - jNO_DEFAULT; - } + if (counter.mode.t2Prescale) + psxCounters[2].rate = 8; + else + psxCounters[2].rate = 1; } else { // Counters 0 and 1 can select PIXEL or HSYNC as an alternate source: counter.rate = 1; - if (value & IOPCNT_ALT_SOURCE) + if (counter.mode.extSignal) counter.rate = (index == 0) ? PSXPIXEL : PSXHBLANK; if (counter.rate == PSXPIXEL) Console.Warning("PSX Pixel clock set to time 0, sync may be incorrect"); - if (counter.mode & IOPCNT_ENABLE_GATE) + if (counter.mode.gateEnable) { - // If set to gate mode 3, the counting starts at the end of the next blank depending on which counter. - if ((counter.mode & IOPCNT_MODE_GATE) == 0x4 && !psxRcntCanCount(index)) - counter.mode |= IOPCNT_STOPPED; - else if ((counter.mode & IOPCNT_MODE_GATE) == 0x6) - counter.mode |= IOPCNT_STOPPED; + // If set to gate mode 2 or 3, the counting starts at the start and end of the next blank respectively depending on which counter. + if (counter.mode.gateMode >= IOPCNT_GATE_CNT_HIGH_ZERO_OFF) + counter.mode.stopped = true; PSXCNT_LOG("IOP Counter[%d] Gate Check set, value = 0x%04X", index, value); } @@ -646,8 +623,7 @@ __fi void psxRcntWmode16(int index, u32 value) // Current counter *always* resets on mode write. counter.count = 0; - counter.sCycleT = psxRegs.cycle; - + counter.startCycle = psxRegs.cycle & ~(counter.rate - 1); counter.target &= 0xffff; _rcntSet(index); @@ -661,10 +637,16 @@ __fi void psxRcntWmode32(int index, u32 value) int irqmode = 0; pxAssume(index >= 3 && index < 6); psxCounter& counter = psxCounters[index]; + psxCounterMode oldMode = counter.mode; + + counter.mode.modeval = (value & IOPCNT_MODE_WRITE_MSK) | (counter.mode.modeval & IOPCNT_MODE_FLAG_MSK); // Write new value, preserve flags - counter.mode = (value & IOPCNT_MODE_WRITE_MSK) | (counter.mode & IOPCNT_MODE_FLAG_MSK); // Write new value, preserve flags - counter.mode |= IOPCNT_INT_REQ; // IRQ Enable + if (!((oldMode.targetFlag || oldMode.overflowFlag) && (oldMode.targetIntr || oldMode.overflIntr))) + psxRcntSetNewIntrMode(index); + if (counter.mode.repeatIntr != counter.currentIrqMode.repeatInterrupt || counter.mode.toggleIntr != counter.currentIrqMode.toggleInterrupt) + DevCon.Warning("Write to psxCounter[%d] mode old repeat %d new %d old toggle %d new %d", index, counter.currentIrqMode.repeatInterrupt, counter.mode.repeatIntr, counter.currentIrqMode.toggleInterrupt, counter.mode.toggleIntr); + if (value & (1 << 4)) { irqmode += 1; @@ -693,39 +675,40 @@ __fi void psxRcntWmode32(int index, u32 value) { // Counter 3 has the HBlank as an alternate source. counter.rate = 1; - if (value & IOPCNT_ALT_SOURCE) + + if (counter.mode.extSignal) counter.rate = PSXHBLANK; - if (counter.mode & IOPCNT_ENABLE_GATE) + if (counter.mode.gateEnable) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value); // If set to gate mode 2 or 3, the counting starts at the start and end of the next blank respectively depending on which counter. - if ((counter.mode & IOPCNT_MODE_GATE) > 0x2) - counter.mode |= IOPCNT_STOPPED; + if (counter.mode.gateMode >= IOPCNT_GATE_CNT_HIGH_ZERO_OFF) + counter.mode.stopped = true; } } else { - switch (value & 0x6000) + switch (counter.mode.t4_5Prescale) { - case 0x0000: - counter.rate = 1; - break; - case 0x2000: + case 0x1: counter.rate = 8; break; - case 0x4000: + case 0x2: counter.rate = 16; break; - case 0x6000: + case 0x3: counter.rate = 256; break; + default: + counter.rate = 1; + break; } } // Current counter *always* resets on mode write. counter.count = 0; - counter.sCycleT = psxRegs.cycle; + counter.startCycle = psxRegs.cycle & ~(counter.rate - 1); counter.target &= 0xffffffff; _rcntSet(index); } @@ -738,24 +721,7 @@ void psxRcntWtarget16(int index, u32 value) PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx", index, value); psxCounters[index].target = value & 0xffff; - if (!(psxCounters[index].mode & IOPCNT_INT_TOGGLE)) - { - // Pulse mode reset - psxCounters[index].mode |= IOPCNT_INT_REQ; // Interrupt flag reset to high - } - - if (psxRcntCanCount(index) && - (psxCounters[index].rate != PSXHBLANK)) - { - // Re-adjust the sCycleT to match where the counter is currently - // (remainder of the rate divided into the time passed will do the trick) - - const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; - psxCounters[index].count += change; - psxCounters[index].sCycleT += change * psxCounters[index].rate; - } - else - psxCounters[index].sCycleT = psxRegs.cycle; + psxRcntSync(index); // protect the target from an early arrival. // if the target is behind the current count, then set the target overflow @@ -770,28 +736,11 @@ void psxRcntWtarget16(int index, u32 value) void psxRcntWtarget32(int index, u32 value) { pxAssert(index >= 3 && index < 6); - PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx mode %x", index, value, psxCounters[index].mode); + PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx mode %x", index, value, psxCounters[index].mode.modeval); psxCounters[index].target = value; - if (!(psxCounters[index].mode & IOPCNT_INT_TOGGLE)) - { - // Pulse mode reset - psxCounters[index].mode |= IOPCNT_INT_REQ; // Interrupt flag reset to high - } - - if (psxRcntCanCount(index) && - (psxCounters[index].rate != PSXHBLANK)) - { - // Re-adjust the sCycleT to match where the counter is currently - // (remainder of the rate divided into the time passed will do the trick) - - const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; - psxCounters[index].count += change; - psxCounters[index].sCycleT += change * psxCounters[index].rate; - } - else - psxCounters[index].sCycleT = psxRegs.cycle; + psxRcntSync(index); // protect the target from an early arrival. // if the target is behind the current count, then set the target overflow // flag, so that the target won't be active until after the next overflow. @@ -804,56 +753,50 @@ void psxRcntWtarget32(int index, u32 value) u16 psxRcntRcount16(int index) { - u32 retval = (u32)psxCounters[index].count; + psxRcntSync(index); + const u32 retval = (u32)psxCounters[index].count; pxAssert(index < 3); PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx", index, (u16)retval); - // Don't count HBLANK timers - // Don't count stopped gates either. - const bool canCount = psxRcntCanCount(index); - if ((psxCounters[index].rate != PSXHBLANK) && canCount) - { - u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); - retval += delta; - PSXCNT_LOG(" (delta = %lx)", delta); - } - else if (!canCount && (psxCounters[index].mode & IOPCNT_ENABLE_GATE) && (psxCounters[index].mode & IOPCNT_MODE_GATE) == 4) - retval = 0; - return (u16)retval; } u32 psxRcntRcount32(int index) { - u32 retval = (u32)psxCounters[index].count; + psxRcntSync(index); + + const u32 retval = (u32)psxCounters[index].count; pxAssert(index >= 3 && index < 6); PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx", index, retval); - const bool canCount = psxRcntCanCount(index); - if ((psxCounters[index].rate != PSXHBLANK) && canCount) - { - u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); - retval += delta; - PSXCNT_LOG(" (delta = %lx)", delta); - } - else if (!canCount && (psxCounters[index].mode & IOPCNT_ENABLE_GATE) && (psxCounters[index].mode & IOPCNT_MODE_GATE) == 4) - retval = 0; - return retval; } +void psxRcntSetNewIntrMode(int index) +{ + psxCounters[index].mode.targetFlag = false; + psxCounters[index].mode.overflowFlag = false; + psxCounters[index].mode.intrEnable = true; + + if (psxCounters[index].mode.repeatIntr != psxCounters[index].currentIrqMode.repeatInterrupt || psxCounters[index].mode.toggleIntr != psxCounters[index].currentIrqMode.toggleInterrupt) + DevCon.Warning("Updating psxCounter[%d] mode old repeat %d new %d old toggle %d new %d", index, psxCounters[index].mode.repeatIntr, psxCounters[index].currentIrqMode.repeatInterrupt, psxCounters[index].mode.toggleIntr, psxCounters[index].currentIrqMode.toggleInterrupt); + + psxCounters[index].currentIrqMode.repeatInterrupt = psxCounters[index].mode.repeatIntr; + psxCounters[index].currentIrqMode.toggleInterrupt = psxCounters[index].mode.toggleIntr; +} + bool SaveStateBase::psxRcntFreeze() { if (!FreezeTag("iopCounters")) return false; Freeze(psxCounters); - Freeze(psxNextCounter); - Freeze(psxNextsCounter); + Freeze(psxNextDeltaCounter); + Freeze(psxNextStartCounter); Freeze(hBlanking); Freeze(vBlanking); diff --git a/pcsx2/IopCounters.h b/pcsx2/IopCounters.h index c56f21e9eb80a..9645c258a294e 100644 --- a/pcsx2/IopCounters.h +++ b/pcsx2/IopCounters.h @@ -5,12 +5,44 @@ #include "common/Pcsx2Defs.h" +struct CounterIRQBehaviour +{ + bool repeatInterrupt; + bool toggleInterrupt; +}; + +union psxCounterMode +{ + struct + { + u32 gateEnable : 1; + u32 gateMode : 2; + u32 zeroReturn : 1; + u32 targetIntr : 1; + u32 overflIntr : 1; + u32 repeatIntr : 1; + u32 toggleIntr : 1; + u32 extSignal : 1; + u32 t2Prescale : 1; + u32 intrEnable : 1; + u32 targetFlag : 1; + u32 overflowFlag : 1; + u32 t4_5Prescale : 2; + u32 stopped : 1; + }; + + u32 modeval; +}; + struct psxCounter { u64 count, target; - u32 mode; + u32 rate, interrupt; - u32 sCycleT; - s32 CycleT; + u32 startCycle; + s32 deltaCycles; + + psxCounterMode mode; + CounterIRQBehaviour currentIrqMode; }; #define NUM_COUNTERS 8 @@ -25,6 +57,7 @@ extern void psxRcntWmode16(int index, u32 value); extern void psxRcntWmode32(int index, u32 value); extern void psxRcntWtarget16(int index, u32 value); extern void psxRcntWtarget32(int index, u32 value); +extern void psxRcntSetNewIntrMode(int index); extern u16 psxRcntRcount16(int index); extern u32 psxRcntRcount32(int index); extern u64 psxRcntCycles(int index); diff --git a/pcsx2/IopDma.cpp b/pcsx2/IopDma.cpp index 8a57a1da36b71..9918d77029ff3 100644 --- a/pcsx2/IopDma.cpp +++ b/pcsx2/IopDma.cpp @@ -32,20 +32,20 @@ static void psxDmaGeneric(u32 madr, u32 bcr, u32 chcr, u32 spuCore) // Update the spu2 to the current cycle before initiating the DMA SPU2async(); - //Console.Status("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); + //Console.Status("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].startCycle); - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = size * 4; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = size * 4; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; - if ((psxRegs.iopNextEventCycle - psxNextsCounter) > (u32)psxNextCounter) + if ((psxRegs.iopNextEventCycle - psxNextStartCounter) > (u32)psxNextDeltaCounter) { - //DevCon.Warning("SPU2async Setting new counter branch, old %x new %x ((%x - %x = %x) > %x delta)", g_iopNextEventCycle, psxNextsCounter + psxNextCounter, g_iopNextEventCycle, psxNextsCounter, (g_iopNextEventCycle - psxNextsCounter), psxNextCounter); - psxRegs.iopNextEventCycle = psxNextsCounter + psxNextCounter; + //DevCon.Warning("SPU2async Setting new counter branch, old %x new %x ((%x - %x = %x) > %x delta)", g_iopNextEventCycle, psxNextStartCounter + psxNextCounter, g_iopNextEventCycle, psxNextStartCounter, (g_iopNextEventCycle - psxNextStartCounter), psxNextCounter); + psxRegs.iopNextEventCycle = psxNextStartCounter + psxNextDeltaCounter; } switch (chcr) diff --git a/pcsx2/R3000A.cpp b/pcsx2/R3000A.cpp index 7bb30a74a4271..29625009aa66f 100644 --- a/pcsx2/R3000A.cpp +++ b/pcsx2/R3000A.cpp @@ -207,7 +207,7 @@ __ri void iopEventTest() { psxRegs.iopNextEventCycle = psxRegs.cycle + iopWaitCycles; - if (psxTestCycle(psxNextsCounter, psxNextCounter)) + if (psxTestCycle(psxNextStartCounter, psxNextDeltaCounter)) { psxRcntUpdate(); iopEventAction = true; @@ -216,8 +216,8 @@ __ri void iopEventTest() { // start the next branch at the next counter event by default // the interrupt code below will assign nearer branches if needed. - if (psxNextCounter < static_cast(psxRegs.iopNextEventCycle - psxNextsCounter)) - psxRegs.iopNextEventCycle = psxNextsCounter + psxNextCounter; + if (psxNextDeltaCounter < static_cast(psxRegs.iopNextEventCycle - psxNextStartCounter)) + psxRegs.iopNextEventCycle = psxNextStartCounter + psxNextDeltaCounter; } if (psxRegs.interrupt) diff --git a/pcsx2/R3000A.h b/pcsx2/R3000A.h index 80a61b4e819c4..ee97bb8d46f8a 100644 --- a/pcsx2/R3000A.h +++ b/pcsx2/R3000A.h @@ -168,8 +168,8 @@ extern u32 EEoCycle; #endif -extern s32 psxNextCounter; -extern u32 psxNextsCounter; +extern s32 psxNextDeltaCounter; +extern u32 psxNextStartCounter; extern bool iopEventAction; extern bool iopEventTestIsActive; diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 026a744599163..8b170e5a4ee82 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -398,7 +398,7 @@ __fi void _cpuEventTest_Shared() iopEventTest(); - if (cpuTestCycle(nextsCounter, nextCounter)) + if (cpuTestCycle(nextStartCounter, nextDeltaCounter)) { rcntUpdate(); _cpuTestPERF(); @@ -450,7 +450,7 @@ __fi void _cpuEventTest_Shared() } // Apply vsync and other counter nextCycles - cpuSetNextEvent(nextsCounter, nextCounter); + cpuSetNextEvent(nextStartCounter, nextDeltaCounter); eeEventTestIsActive = false; } diff --git a/pcsx2/SPU2/Dma.cpp b/pcsx2/SPU2/Dma.cpp index 2583ebc91a91c..cf70f3df18156 100644 --- a/pcsx2/SPU2/Dma.cpp +++ b/pcsx2/SPU2/Dma.cpp @@ -345,15 +345,15 @@ void V_Core::FinishDMAwrite() DMAICounter = (DMAICounter - ReadSize) * 4; - if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > (u32)DMAICounter) + if (((psxCounters[6].startCycle + psxCounters[6].deltaCycles) - psxRegs.cycle) > (u32)DMAICounter) { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = DMAICounter; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = DMAICounter; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; } ActiveTSA = TDA; @@ -439,15 +439,15 @@ void V_Core::FinishDMAread() else DMAICounter = 4; - if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > (u32)DMAICounter) + if (((psxCounters[6].startCycle + psxCounters[6].deltaCycles) - psxRegs.cycle) > (u32)DMAICounter) { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = DMAICounter; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = DMAICounter; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; } ActiveTSA = TDA; @@ -470,15 +470,15 @@ void V_Core::DoDMAread(u16* pMem, u32 size) //Regs.ATTR |= 0x30; TADR = MADR + (size << 1); - if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > (u32)DMAICounter) + if (((psxCounters[6].startCycle + psxCounters[6].deltaCycles) - psxRegs.cycle) > (u32)DMAICounter) { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = DMAICounter; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = DMAICounter; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; } if (SPU2::MsgDMA()) diff --git a/pcsx2/SPU2/spu2sys.cpp b/pcsx2/SPU2/spu2sys.cpp index 7efcd57fe3a2c..991052e4df0bb 100644 --- a/pcsx2/SPU2/spu2sys.cpp +++ b/pcsx2/SPU2/spu2sys.cpp @@ -349,15 +349,15 @@ __forceinline void TimeUpdate(u32 cClocks) } else { - if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > (u32)Cores[0].DMAICounter) + if (((psxCounters[6].startCycle + psxCounters[6].deltaCycles) - psxRegs.cycle) > (u32)Cores[0].DMAICounter) { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = Cores[0].DMAICounter; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = Cores[0].DMAICounter; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; } } } @@ -402,15 +402,15 @@ __forceinline void TimeUpdate(u32 cClocks) } else { - if (((psxCounters[6].sCycleT + psxCounters[6].CycleT) - psxRegs.cycle) > (u32)Cores[1].DMAICounter) + if (((psxCounters[6].startCycle + psxCounters[6].deltaCycles) - psxRegs.cycle) > (u32)Cores[1].DMAICounter) { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = Cores[1].DMAICounter; + psxCounters[6].startCycle = psxRegs.cycle; + psxCounters[6].deltaCycles = Cores[1].DMAICounter; - psxNextCounter -= (psxRegs.cycle - psxNextsCounter); - psxNextsCounter = psxRegs.cycle; - if (psxCounters[6].CycleT < psxNextCounter) - psxNextCounter = psxCounters[6].CycleT; + psxNextDeltaCounter -= (psxRegs.cycle - psxNextStartCounter); + psxNextStartCounter = psxRegs.cycle; + if (psxCounters[6].deltaCycles < psxNextDeltaCounter) + psxNextDeltaCounter = psxCounters[6].deltaCycles; } } } diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index f7722f2d96c00..f5301dbd0fa81 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -192,10 +192,10 @@ bool SaveStateBase::FreezeInternals(Error* error) Freeze(EEsCycle); Freeze(EEoCycle); - Freeze(nextCounter); - Freeze(nextsCounter); - Freeze(psxNextsCounter); - Freeze(psxNextCounter); + Freeze(nextDeltaCounter); + Freeze(nextStartCounter); + Freeze(psxNextStartCounter); + Freeze(psxNextDeltaCounter); // Fourth Block - EE-related systems // --------------------------------- diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 777d93e6065a2..6072609235008 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -25,7 +25,7 @@ enum class FreezeAction // [SAVEVERSION+] // This informs the auto updater that the users savestates will be invalidated. -static const u32 g_SaveVersion = (0x9A4D << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A4E << 16) | 0x0000; // the freezing data between submodules and core diff --git a/pcsx2/ps2/Iop/IopHwRead.cpp b/pcsx2/ps2/Iop/IopHwRead.cpp index 7dc2b94c3b803..a95259d7fb22c 100644 --- a/pcsx2/ps2/Iop/IopHwRead.cpp +++ b/pcsx2/ps2/Iop/IopHwRead.cpp @@ -161,13 +161,9 @@ static __fi T _HwRead_16or32_Page1( u32 addr ) break; case 0x4: - ret = psxCounters[cntidx].mode; + ret = psxCounters[cntidx].mode.modeval; - // hmm! The old code only did this bitwise math for 16 bit reads. - // Logic indicates it should do the math consistently. Question is, - // should it do the logic for both 16 and 32, or not do logic at all? - - psxCounters[cntidx].mode &= ~0x1800; + psxRcntSetNewIntrMode(cntidx); break; case 0x8: @@ -197,13 +193,10 @@ static __fi T _HwRead_16or32_Page1( u32 addr ) break; case 0x4: - ret = psxCounters[cntidx].mode; + ret = psxCounters[cntidx].mode.modeval; PSXCNT_LOG("IOP Counter[%d] modeRead%d = %lx", cntidx, sizeof(T) * 8, ret); - // hmm! The old code only did the following bitwise math for 16 bit reads. - // Logic indicates it should do the math consistently. Question is, - // should it do the logic for both 16 and 32, or not do logic at all? - psxCounters[cntidx].mode &= ~0x1800; + psxRcntSetNewIntrMode(cntidx); break; case 0x8: