From b824c2d31a58658395ec0e35555a74bec1b6e0e5 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sat, 4 Nov 2023 03:19:44 +0000 Subject: [PATCH] Counters: Improve counter updates and fix a couple of errors --- pcsx2/Counters.cpp | 370 ++++++++++++++++++++++-------------------- pcsx2/IopCounters.cpp | 100 ++++++------ pcsx2/IopDma.cpp | 2 +- pcsx2/SPU2/spu2.cpp | 2 +- pcsx2/SPU2/spu2.h | 2 +- 5 files changed, 249 insertions(+), 227 deletions(-) diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index f2db4ad1a5e27..44fbda722f2c8 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -73,7 +73,8 @@ static bool IsProgressiveVideoMode() return !(*(u32*)PS2GS_BASE(GS_SYNCV) & 0x1) || !(*(u32*)PS2GS_BASE(GS_SMODE1) & 0x6000); } -void rcntReset(int index) { +void rcntReset(int index) +{ counters[index].count = 0; counters[index].sCycleT = cpuRegs.cycle; } @@ -81,20 +82,22 @@ void rcntReset(int index) { // Updates the state of the nextCounter value (if needed) to serve // any pending events for the given counter. // Call this method after any modifications to the state of a counter. -static __fi void _rcntSet( int cntidx ) +static __fi void _rcntSet(int cntidx) { s32 c; - pxAssume( cntidx <= 4 ); // rcntSet isn't valid for h/vsync counters. + pxAssume(cntidx <= 4); // rcntSet isn't valid for h/vsync counters. const Counter& counter = counters[cntidx]; // Stopped or special hsync gate? - if (!counter.mode.IsCounting || (counter.mode.ClockSource == 0x3) ) return; + if (!counter.mode.IsCounting || (counter.mode.ClockSource == 0x3)) + return; - if (!counter.mode.TargetInterrupt && !counter.mode.OverflowInterrupt) return; + if (!counter.mode.TargetInterrupt && !counter.mode.OverflowInterrupt) + 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 ) + if (counter.count > 0x10000 || counter.count > counter.target) { nextCounter = 4; return; @@ -106,26 +109,27 @@ static __fi void _rcntSet( int cntidx ) // 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(); + c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); if (c < nextCounter) { nextCounter = c; - cpuSetNextEvent( nextsCounter, nextCounter ); // Need to update on counter resets/target changes + cpuSetNextEvent(nextsCounter, nextCounter); // Need to update on counter resets/target changes } // Ignore target diff if target is currently disabled. // (the overflow is all we care about since it goes first, and then the // target will be turned on afterward, and handled in the next event test). - if( counter.target & EECNT_FUTURE_TARGET ) + if (counter.target & EECNT_FUTURE_TARGET) { return; } else { + c = ((counter.target - counter.count) * counter.rate) - (cpuRegs.cycle - counter.sCycleT); - c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); + c += cpuRegs.cycle - nextsCounter; // adjust for time passed since last rcntUpdate(); if (c < nextCounter) { nextCounter = c; @@ -149,7 +153,7 @@ static __fi void cpuRcntSet() nextCounter = nextHsync; for (i = 0; i < 4; i++) - _rcntSet( i ); + _rcntSet(i); // sanity check! if (nextCounter < 0) @@ -166,11 +170,12 @@ void rcntInit() std::memset(counters, 0, sizeof(counters)); - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) + { counters[i].rate = 2; counters[i].target = 0xffff; } - counters[0].interrupt = 9; + counters[0].interrupt = 9; counters[1].interrupt = 10; counters[2].interrupt = 11; counters[3].interrupt = 12; @@ -180,7 +185,8 @@ void rcntInit() vsyncCounter.Mode = MODE_VRENDER; vsyncCounter.sCycle = cpuRegs.cycle; - for (i=0; i<4; i++) rcntReset(i); + for (i = 0; i < 4; i++) + rcntReset(i); cpuRcntSet(); } @@ -246,11 +252,15 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca info->hBlank = (u32)(hBlank / 10000); info->hScanlinesPerFrame = scansPerFrame; - if ((Render % 10000) >= 5000) info->Render++; - if ((Blank % 10000) >= 5000) info->Blank++; + if ((Render % 10000) >= 5000) + info->Render++; + if ((Blank % 10000) >= 5000) + info->Blank++; - if ((hRender % 10000) >= 5000) info->hRender++; - if ((hBlank % 10000) >= 5000) info->hBlank++; + 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 @@ -260,7 +270,8 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca info->hSyncError = vSyncCycles - hSyncCycles; //Console.Warning("%d",info->hSyncError); } - else info->hSyncError = 0; + 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. @@ -316,25 +327,25 @@ double GetVerticalFrequency() switch (gsVideoMode) { - case GS_VideoMode::Uninitialized: // SetGsCrt hasn't executed yet, give some temporary values. - return 60.00; - case GS_VideoMode::PAL: - case GS_VideoMode::DVD_PAL: - return (IsProgressiveVideoMode() == false) ? EmuConfig.GS.FrameratePAL : EmuConfig.GS.FrameratePAL - 0.24f; - case GS_VideoMode::NTSC: - case GS_VideoMode::DVD_NTSC: - return (IsProgressiveVideoMode() == false) ? EmuConfig.GS.FramerateNTSC : EmuConfig.GS.FramerateNTSC - 0.11f; - case GS_VideoMode::SDTV_480P: - return 59.94; - case GS_VideoMode::HDTV_1080P: - case GS_VideoMode::HDTV_1080I: - case GS_VideoMode::HDTV_720P: - case GS_VideoMode::SDTV_576P: - case GS_VideoMode::VESA: - return 60.00; - default: - // Pass NTSC vertical frequency value when unknown video mode is detected. - return FRAMERATE_NTSC * 2; + case GS_VideoMode::Uninitialized: // SetGsCrt hasn't executed yet, give some temporary values. + return 60.00; + case GS_VideoMode::PAL: + case GS_VideoMode::DVD_PAL: + return (IsProgressiveVideoMode() == false) ? EmuConfig.GS.FrameratePAL : EmuConfig.GS.FrameratePAL - 0.24f; + case GS_VideoMode::NTSC: + case GS_VideoMode::DVD_NTSC: + return (IsProgressiveVideoMode() == false) ? EmuConfig.GS.FramerateNTSC : EmuConfig.GS.FramerateNTSC - 0.11f; + case GS_VideoMode::SDTV_480P: + return 59.94; + case GS_VideoMode::HDTV_1080P: + case GS_VideoMode::HDTV_1080I: + case GS_VideoMode::HDTV_720P: + case GS_VideoMode::SDTV_576P: + case GS_VideoMode::VESA: + return 60.00; + default: + // Pass NTSC vertical frequency value when unknown video mode is detected. + return FRAMERATE_NTSC * 2; } } @@ -497,14 +508,15 @@ static __fi void VSyncStart(u32 sCycle) VMManager::Internal::Throttle(); gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times! - - if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) - SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC START (frame: %d) ================", g_FrameCount ); + + 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(); - if (gates) rcntStartGate(true, sCycle); // Counters Start Gate code + if (gates) + rcntStartGate(true, sCycle); // Counters Start Gate code // INTC - VB Blank Start Hack -- // Hack fix! This corrects a freezeup in Granda 2 where it decides to spin @@ -554,14 +566,15 @@ static __fi void GSVSync() static __fi void VSyncEnd(u32 sCycle) { - if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) - SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount ); + if (EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll) + SysTrace.EE.Counters.Write(" ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount); g_FrameCount++; - hwIntcIrq(INTC_VBLANK_E); // HW Irq + hwIntcIrq(INTC_VBLANK_E); // HW Irq psxVBlankEnd(); // psxCounters vBlank End - if (gates) rcntEndGate(true, sCycle); // Counters End Gate Code + if (gates) + 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 @@ -575,48 +588,54 @@ static __fi void VSyncEnd(u32 sCycle) //#define VSYNC_DEBUG // Uncomment this to enable some vSync Timer debugging features. #ifdef VSYNC_DEBUG -static u32 hsc=0; +static u32 hsc = 0; static int vblankinc = 0; #endif __fi void rcntUpdate_hScanline() { - if( !cpuTestCycle( hsyncCounter.sCycle, hsyncCounter.CycleT ) ) return; + if (!cpuTestCycle(hsyncCounter.sCycle, hsyncCounter.CycleT)) + return; //iopEventAction = 1; - if (hsyncCounter.Mode == MODE_HBLANK) { //HBLANK Start + if (hsyncCounter.Mode == MODE_HBLANK) + { //HBLANK Start rcntStartGate(false, hsyncCounter.sCycle); psxCheckStartGate16(0); // 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.sCycle += vSyncInfo.hBlank; // start (absolute cycle value) + hsyncCounter.CycleT = vSyncInfo.hRender; // endpoint (delta from start value) hsyncCounter.Mode = MODE_HRENDER; } - else { //HBLANK END / HRENDER Begin + else + { //HBLANK END / HRENDER Begin if (!CSRreg.HSINT) { CSRreg.HSINT = true; if (!GSIMR.HSMSK) gsIrq(); } - if (gates) rcntEndGate(false, hsyncCounter.sCycle); - if (psxhblankgate) psxCheckEndGate16(0); + if (gates) + rcntEndGate(false, hsyncCounter.sCycle); + if (psxhblankgate) + psxCheckEndGate16(0); // 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.sCycle += vSyncInfo.hRender; // start (absolute cycle value) + hsyncCounter.CycleT = vSyncInfo.hBlank; // endpoint (delta from start value) hsyncCounter.Mode = MODE_HBLANK; -# ifdef VSYNC_DEBUG +#ifdef VSYNC_DEBUG hsc++; -# endif +#endif } } __fi void rcntUpdate_vSync() { - if (!cpuTestCycle(vsyncCounter.sCycle, vsyncCounter.CycleT)) return; + if (!cpuTestCycle(vsyncCounter.sCycle, vsyncCounter.CycleT)) + return; if (vsyncCounter.Mode == MODE_VSYNC) { @@ -634,7 +653,7 @@ __fi void rcntUpdate_vSync() // Don't set the start cycle, makes it easier to calculate the correct Vsync End time vsyncCounter.CycleT = vSyncInfo.Blank; } - else // VSYNC end / VRENDER begin + else // VSYNC end / VRENDER begin { VSyncStart(vsyncCounter.sCycle); @@ -645,25 +664,26 @@ __fi void rcntUpdate_vSync() // Accumulate hsync rounding errors: hsyncCounter.sCycle += vSyncInfo.hSyncError; -# ifdef VSYNC_DEBUG +#ifdef VSYNC_DEBUG vblankinc++; - if( vblankinc > 1 ) + if (vblankinc > 1) { - if( hsc != vSyncInfo.hScanlinesPerFrame ) - Console.WriteLn( " ** vSync > Abnormal Scanline Count: %d", hsc ); + if (hsc != vSyncInfo.hScanlinesPerFrame) + Console.WriteLn(" ** vSync > Abnormal Scanline Count: %d", hsc); hsc = 0; vblankinc = 0; } -# endif +#endif } } -static __fi void _cpuTestTarget( int i ) +static __fi void _cpuTestTarget(int i) { if (counters[i].count < counters[i].target) return; - if(counters[i].mode.TargetInterrupt) { + if (counters[i].mode.TargetInterrupt) + { EECNT_LOG("EE Counter[%d] TARGET reached - mode=%x, count=%x, target=%x", i, counters[i].mode, counters[i].count, counters[i].target); if (!counters[i].mode.TargetReached) { @@ -678,11 +698,13 @@ static __fi void _cpuTestTarget( int i ) counters[i].target |= EECNT_FUTURE_TARGET; // OR with future target to prevent a retrigger } -static __fi void _cpuTestOverflow( int i ) +static __fi void _cpuTestOverflow(int i) { - if (counters[i].count <= 0xffff) return; + if (counters[i].count <= 0xffff) + return; - if (counters[i].mode.OverflowInterrupt) { + if (counters[i].mode.OverflowInterrupt) + { EECNT_LOG("EE Counter[%d] OVERFLOW - mode=%x, count=%x", i, counters[i].mode, counters[i].count); if (!counters[i].mode.OverflowReached) { @@ -708,57 +730,56 @@ __fi void rcntUpdate() // Update counters so that we can perform overflow and target tests. - for (int i=0; i<=3; i++) + for (int i = 0; i <= 3; i++) { // We want to count gated counters (except the hblank which exclude below, and are // counted by the hblank timer instead) //if ( gates & (1< 0 ) - { - counters[index].count += change / counters[index].rate; - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } + if (counters[index].mode.IsCounting) + { + if (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; + else + counters[index].sCycleT = cpuRegs.cycle; // 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). counters[index].modeval &= ~(value & 0xc00); counters[index].modeval = (counters[index].modeval & 0xc00) | (value & 0x3ff); - EECNT_LOG("EE Counter[%d] writeMode = %x passed value=%x", index, counters[index].modeval, value ); + EECNT_LOG("EE Counter[%d] writeMode = %x passed value=%x", index, counters[index].modeval, value); switch (counters[index].mode.ClockSource) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK case 0: counters[index].rate = 2; break; @@ -902,34 +920,35 @@ static __fi void rcntWmode(int index, u32 value) case 3: counters[index].rate = vSyncInfo.hBlank+vSyncInfo.hRender; break; } - _rcntSetGate( index ); - _rcntSet( index ); + _rcntSetGate(index); + _rcntSet(index); } 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 ); + 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 (counters[index].mode.IsCounting) + { + if (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; counters[index].count = value & 0xffff; // reset the target, and make sure we don't get a premature target. counters[index].target &= 0xffff; - if( counters[index].count > counters[index].target ) - counters[index].target |= EECNT_FUTURE_TARGET; - // re-calculate the start cycle of the counter based on elapsed time since the last counter update: - if(counters[index].mode.IsCounting) { - if(counters[index].mode.ClockSource != 0x3) { - s32 change = cpuRegs.cycle - counters[index].sCycleT; - if( change > 0 ) { - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } - } - } - else counters[index].sCycleT = cpuRegs.cycle; + if (counters[index].count > counters[index].target) + counters[index].target |= EECNT_FUTURE_TARGET; - _rcntSet( index ); + _rcntSet(index); } static __fi void rcntWtarget(int index, u32 value) @@ -942,23 +961,20 @@ 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(counters[index].mode.IsCounting) { - if(counters[index].mode.ClockSource != 0x3) { - - u32 change = cpuRegs.cycle - counters[index].sCycleT; - if( change > 0 ) - { - counters[index].count += change / counters[index].rate; - change -= (change / counters[index].rate) * counters[index].rate; - counters[index].sCycleT = cpuRegs.cycle - change; - } + if (counters[index].mode.IsCounting) + { + if (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; } } - if( counters[index].target <= rcntCycle(index) ) + if (counters[index].target <= counters[index].count) counters[index].target |= EECNT_FUTURE_TARGET; - _rcntSet( index ); + _rcntSet(index); } static __fi void rcntWhold(int index, u32 value) @@ -982,8 +998,8 @@ __fi u32 rcntRcount(int index) return ret; } -template< uint page > -__fi u16 rcntRead32( u32 mem ) +template +__fi u16 rcntRead32(u32 mem) { // Important DevNote: // Yes this uses a u16 return value on purpose! The upper bits 16 of the counter registers @@ -1013,10 +1029,10 @@ __fi u16 rcntRead32( u32 mem ) return psHu16(mem); } -template< uint page > -__fi bool rcntWrite32( u32 mem, mem32_t& value ) +template +__fi bool rcntWrite32(u32 mem, mem32_t& value) { - pxAssume( mem >= RCNT0_COUNT && mem < 0x10002000 ); + pxAssume(mem >= RCNT0_COUNT && mem < 0x10002000); // [TODO] : counters should actually just use the EE's hw register space for storing // count, mode, target, and hold. This will allow for a simplified handler for register @@ -1046,25 +1062,25 @@ __fi bool rcntWrite32( u32 mem, mem32_t& value ) return true; } -template u16 rcntRead32<0x00>( u32 mem ); -template u16 rcntRead32<0x01>( u32 mem ); +template u16 rcntRead32<0x00>(u32 mem); +template u16 rcntRead32<0x01>(u32 mem); -template bool rcntWrite32<0x00>( u32 mem, mem32_t& value ); -template bool rcntWrite32<0x01>( u32 mem, mem32_t& value ); +template bool rcntWrite32<0x00>(u32 mem, mem32_t& value); +template bool rcntWrite32<0x01>(u32 mem, mem32_t& value); bool SaveStateBase::rcntFreeze() { - Freeze( counters ); - Freeze( hsyncCounter ); - Freeze( vsyncCounter ); - Freeze( nextCounter ); - Freeze( nextsCounter ); - Freeze( vSyncInfo ); - Freeze( gsVideoMode ); - Freeze( gsIsInterlaced ); - Freeze( gates ); - - if( IsLoading() ) + Freeze(counters); + Freeze(hsyncCounter); + Freeze(vsyncCounter); + Freeze(nextCounter); + Freeze(nextsCounter); + Freeze(vSyncInfo); + Freeze(gsVideoMode); + Freeze(gsIsInterlaced); + Freeze(gates); + + if (IsLoading()) cpuRcntSet(); return IsOkay(); diff --git a/pcsx2/IopCounters.cpp b/pcsx2/IopCounters.cpp index d29b8ea880e98..e8d2acaf2a025 100644 --- a/pcsx2/IopCounters.cpp +++ b/pcsx2/IopCounters.cpp @@ -161,7 +161,7 @@ void psxRcntInit() psxCounters[4].interrupt = 0x08000; psxCounters[5].interrupt = 0x10000; - psxCounters[6].rate = 768 * 12; // 12 SPU ticks. 768 would be ideal but some games slow down internally for some reason + psxCounters[6].rate = 768; psxCounters[6].CycleT = psxCounters[6].rate; psxCounters[6].mode = 0x8; @@ -312,7 +312,7 @@ static void _psxCheckStartGate(int i) return; case 0x1: // GATE_ON_ClearStart - count normally with resets after every end gate - // do nothing - All counting will be done on a need-to-count basis. + // do nothing - All counting will be done on a need-to-count basis. return; case 0x2: // GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end @@ -322,7 +322,7 @@ static void _psxCheckStartGate(int i) break; case 0x3: //GATE_ON_Start - start and count normally on gate end (no restarts or stops or clears) - // do nothing! + // do nothing! return; } _rcntSet(i); @@ -443,8 +443,6 @@ void psxRcntUpdate() for (i = 0; i <= 5; i++) { - s32 change = psxRegs.cycle - psxCounters[i].sCycleT; - // don't count disabled or hblank counters... // We can't check the ALTSOURCE flag because the PSXCLOCK source *should* // be counted here. @@ -460,17 +458,21 @@ void psxRcntUpdate() if (psxCounters[i].rate == PSXHBLANK) continue; - if (change <= 0) - continue; - - psxCounters[i].count += change / psxCounters[i].rate; if (psxCounters[i].rate != 1) { - change -= (change / psxCounters[i].rate) * psxCounters[i].rate; - psxCounters[i].sCycleT = psxRegs.cycle - change; + const u32 change = (psxRegs.cycle - psxCounters[i].sCycleT) / psxCounters[i].rate; + + if (change <= 0) + continue; + + 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; + } } // Do target/overflow testing @@ -499,16 +501,12 @@ void psxRcntUpdate() const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT; s32 c = psxCounters[6].CycleT; - if (difference >= psxCounters[6].CycleT) - { - psxCounters[6].sCycleT = psxRegs.cycle; - psxCounters[6].CycleT = psxCounters[6].rate; - SPU2async(difference); - c = psxCounters[6].CycleT; - } - else - c -= difference; - psxNextCounter = c; + const u32 spu2_delta = (psxRegs.cycle - lClocks) % 768; + psxCounters[6].sCycleT = psxRegs.cycle; + psxCounters[6].CycleT = psxCounters[6].rate - spu2_delta; + SPU2async(); + psxNextCounter = psxCounters[6].CycleT; + DEV9async(1); const s32 diffusb = psxRegs.cycle - psxCounters[7].sCycleT; s32 cusb = psxCounters[7].CycleT; @@ -516,7 +514,7 @@ void psxRcntUpdate() if (diffusb >= psxCounters[7].CycleT) { USBasync(diffusb); - psxCounters[7].sCycleT = psxRegs.cycle; + psxCounters[7].sCycleT += psxCounters[7].rate * (diffusb / psxCounters[7].rate); psxCounters[7].CycleT = psxCounters[7].rate; } else @@ -533,30 +531,25 @@ void psxRcntUpdate() // void psxRcntWcount16(int index, u16 value) { - u32 change; - pxAssert(index < 3); //DevCon.Warning("16bit IOP Counter[%d] writeCount16 = %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) - - change = psxRegs.cycle - psxCounters[index].sCycleT; - psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); + const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; + psxCounters[index].sCycleT += change * psxCounters[index].rate; } psxCounters[index].count = value & 0xffff; + psxCounters[index].target &= 0xffff; + if (psxCounters[index].count > psxCounters[index].target) { // Count already higher than Target //DevCon.Warning("32bit Count already higher than target"); psxCounters[index].target |= IOPCNT_FUTURE_TARGET; } - else - psxCounters[index].target &= 0xffff; _rcntSet(index); } @@ -565,8 +558,6 @@ void psxRcntWcount16(int index, u16 value) // void psxRcntWcount32(int index, u32 value) { - u32 change; - pxAssert(index >= 3 && index < 6); PSXCNT_LOG("32bit IOP Counter[%d] writeCount32 = %x", index, value); @@ -575,20 +566,20 @@ void psxRcntWcount32(int index, u32 value) // Re-adjust the sCycleT to match where the counter is currently // (remainder of the rate divided into the time passed will do the trick) - change = psxRegs.cycle - psxCounters[index].sCycleT; - psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); + const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; + psxCounters[index].sCycleT += change * psxCounters[index].rate; } psxCounters[index].count = value; + psxCounters[index].target &= 0xffffffff; + if (psxCounters[index].count > psxCounters[index].target) { // Count already higher than Target //DevCon.Warning("32bit Count already higher than target"); psxCounters[index].target |= IOPCNT_FUTURE_TARGET; } - else - psxCounters[index].target &= 0xffffffff; _rcntSet(index); } @@ -781,11 +772,23 @@ void psxRcntWtarget16(int index, u32 value) // Pulse mode reset psxCounters[index].mode |= IOPCNT_INT_REQ; // Interrupt flag reset to high } + + if (!(psxCounters[index].mode & IOPCNT_STOPPED) && + (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; + } + // 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. - if (psxCounters[index].target <= psxRcntCycles(index)) + if (psxCounters[index].target <= psxCounters[index].count) psxCounters[index].target |= IOPCNT_FUTURE_TARGET; _rcntSet(index); @@ -803,11 +806,22 @@ void psxRcntWtarget32(int index, u32 value) // Pulse mode reset psxCounters[index].mode |= IOPCNT_INT_REQ; // Interrupt flag reset to high } + + if (!(psxCounters[index].mode & IOPCNT_STOPPED) && + (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; + } // 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. - if (psxCounters[index].target <= psxRcntCycles(index)) + if (psxCounters[index].target <= psxCounters[index].count) psxCounters[index].target |= IOPCNT_FUTURE_TARGET; _rcntSet(index); @@ -854,14 +868,6 @@ u32 psxRcntRcount32(int index) return retval; } -u64 psxRcntCycles(int index) -{ - if (psxCounters[index].mode & IOPCNT_STOPPED || psxCounters[index].rate == PSXHBLANK) - return psxCounters[index].count; - - return (u64)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate)); -} - void psxRcntSetGates() { if (psxCounters[0].mode & IOPCNT_ENABLE_GATE) diff --git a/pcsx2/IopDma.cpp b/pcsx2/IopDma.cpp index db90135a6d7a2..b12a53470aaa0 100644 --- a/pcsx2/IopDma.cpp +++ b/pcsx2/IopDma.cpp @@ -44,7 +44,7 @@ static void psxDmaGeneric(u32 madr, u32 bcr, u32 chcr, u32 spuCore) // Update the spu2 to the current cycle before initiating the DMA - SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); + SPU2async(); //Console.Status("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); psxCounters[6].sCycleT = psxRegs.cycle; diff --git a/pcsx2/SPU2/spu2.cpp b/pcsx2/SPU2/spu2.cpp index 033c4f1073164..c1e7c7950be12 100644 --- a/pcsx2/SPU2/spu2.cpp +++ b/pcsx2/SPU2/spu2.cpp @@ -225,7 +225,7 @@ bool SPU2::IsRunningPSXMode() return s_psxmode; } -void SPU2async(u32 cycles) +void SPU2async() { TimeUpdate(psxRegs.cycle); } diff --git a/pcsx2/SPU2/spu2.h b/pcsx2/SPU2/spu2.h index f0e5390100079..58a0dc31916b6 100644 --- a/pcsx2/SPU2/spu2.h +++ b/pcsx2/SPU2/spu2.h @@ -62,7 +62,7 @@ bool IsAudioCaptureActive(); void SPU2write(u32 mem, u16 value); u16 SPU2read(u32 mem); -void SPU2async(u32 cycles); +void SPU2async(); s32 SPU2freeze(FreezeAction mode, freezeData* data); void SPU2readDMA4Mem(u16* pMem, u32 size);