diff --git a/pcsx2/Counters.c b/pcsx2/Counters.c index d3cfd2beff..798ee7cb92 100644 --- a/pcsx2/Counters.c +++ b/pcsx2/Counters.c @@ -22,22 +22,18 @@ #include "Common.h" #include "PsxCommon.h" #include "GS.h" +#include "VU.h" u64 profile_starttick = 0; u64 profile_totalticks = 0; int gates = 0; extern u8 psxhblankgate; -int hblankend = 0; Counter counters[6]; u32 nextCounter, nextsCounter; static void (*s_prevExecuteVU1Block)() = NULL; LARGE_INTEGER lfreq; -// its so it doesnt keep triggering an interrupt once its reached its target -// if it doesnt reset the counter it needs stopping -u32 eecntmask = 0; - void rcntUpdTarget(int index) { counters[index].sCycleT = cpuRegs.cycle; } @@ -49,7 +45,6 @@ void rcntUpd(int index) { void rcntReset(int index) { counters[index].count = 0; - //counters[index].mode&= ~0x00400C00; rcntUpd(index); } @@ -57,7 +52,7 @@ void rcntSet() { u32 c; int i; - nextCounter = 0xffffffff; + nextCounter = (counters[4].CycleT < counters[5].CycleT) ? counters[4].CycleT : counters[5].CycleT; nextsCounter = cpuRegs.cycle; for (i = 0; i < 4; i++) { @@ -70,15 +65,6 @@ void rcntSet() { c = ((counters[i].target - counters[i].count) * counters[i].rate) - (cpuRegs.cycle - counters[i].sCycleT); if (c < nextCounter) nextCounter = c; } - - //Calculate HBlank - c = counters[4].CycleT - (cpuRegs.cycle - counters[4].sCycleT); - if (c < nextCounter) nextCounter = c; - //if(nextCounter > 0x1000) SysPrintf("Nextcounter %x HBlank %x VBlank %x\n", nextCounter, c, counters[5].CycleT - (cpuRegs.cycle - counters[5].sCycleT)); - - //Calculate VBlank - c = counters[5].CycleT - (cpuRegs.cycle - counters[5].sCycleT); - if (c < nextCounter) nextCounter = c; } void rcntInit() { @@ -95,19 +81,8 @@ void rcntInit() { counters[2].interrupt = 11; counters[3].interrupt = 12; - counters[4].mode = 0x3c0; // The VSync counter mode - counters[5].mode = 0x3c0; - UpdateVSyncRate(); - /*hblankend = 0; - counters[5].mode &= ~0x10000; - counters[4].sCycleT = cpuRegs.cycle; - counters[4].CycleT = HBLANKCNT(1); - counters[4].count = 1; - counters[5].CycleT = VBLANKCNT(1); - counters[5].count = 1; - counters[5].sCycleT = cpuRegs.cycle;*/ - + #ifdef _WIN32 QueryPerformanceFrequency(&lfreq); #endif @@ -153,47 +128,27 @@ u64 GetCPUTicks() } void UpdateVSyncRate() { - if (Config.PsxType & 1) { - SysPrintf("PAL\n"); - counters[4].Cycle = 227000; - //if(Config.PsxType & 2)counters[5].rate = PS2VBLANK_PAL_INT; - //else counters[5].rate = PS2VBLANK_PAL; - counters[5].Cycle = 720; - } - else { - SysPrintf("NTSC\n"); - counters[4].Cycle = 227000; - //if(Config.PsxType & 2)counters[5].rate = PS2VBLANK_NTSC_INT; - //else counters[5].rate = PS2VBLANK_NTSC; - counters[5].Cycle = 720; - } - hblankend = 0; - counters[5].mode &= ~0x10000; - counters[4].sCycleT = cpuRegs.cycle; - counters[4].CycleT = HBLANKCNT(1); - counters[4].count = 1; - counters[5].CycleT = VBLANKCNT(1); - counters[5].count = 1; - counters[5].sCycleT = cpuRegs.cycle; - - //rcntUpdTarget(4); - //counters[4].CycleT = counters[4].rate; - //rcntUpdTarget(5); - //counters[5].CycleT = counters[5].rate; - //counters[5].Cycle = PS2VBLANKEND; - + counters[4].mode = MODE_HRENDER; // Counter 4 takes care of scanlines, so set the mode to HRENDER (drawing part of scanline) + counters[4].sCycle = cpuRegs.cycle; // Update Counter 4's Start Cycle to match CPU's cycle + counters[4].CycleT = HRENDER_TIME_; // Amount of cycles before the counter will be updated + + counters[5].mode = MODE_VRENDER; // Counter 5 takes care of vSync/vBlanks + counters[5].sCycle = cpuRegs.cycle; // Update Counter 5's Start Cycle to match CPU's cycle + counters[5].CycleT = VSYNC_HALF_; // Amount of cycles before the counter will be updated + + if (Config.CustomFps > 0) { iTicks = GetTickFrequency() / Config.CustomFps; SysPrintf("Framelimiter rate updated (UpdateVSyncRate): %d fps\n", Config.CustomFps); } else if (Config.PsxType & 1) { iTicks = (GetTickFrequency() / 5000) * 100; - SysPrintf("Framelimiter rate updated (UpdateVSyncRate): 50 fps\n"); + SysPrintf("Framelimiter rate updated (UpdateVSyncRate): 50 fps Pal\n"); } else { iTicks = (GetTickFrequency() / 5994) * 100; - SysPrintf("Framelimiter rate updated (UpdateVSyncRate): 59.94 fps\n"); + SysPrintf("Framelimiter rate updated (UpdateVSyncRate): 59.94 fps NTSC\n"); } rcntSet(); } @@ -209,12 +164,12 @@ void FrameLimiter() if (iEnd>=iExpectedEnd) { u64 diff = iEnd-iExpectedEnd; - if((diff>>3)>iTicks) iExpectedEnd=iEnd; + if ((diff>>3)>iTicks) iExpectedEnd=iEnd; } else do { - Sleep(1); + _TIMESLICE(); iEnd = GetCPUTicks(); - } while(iEnd0) ? Config.CustomConsecutiveFrames : 2 - // This is the number of consecutive frames we will skip - #define yesSkipFrames (Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 2 - static u8 bOkayToSkip = 0; - static u8 bKeepSkipping = 0; - static u64 uLastTime = 0; - - // This is some Extra Time to add to our Expected Time to compensate for lack of precision. - #define extraTimeBuffer 0 - // If uDeltaTime is less than this value, then we can frameskip. (45 & 54 FPS is 90% of fullspeed for Pal & NTSC respectively, the default is to only skip when slower than 90%) - u64 uExpectedTime = (Config.CustomFrameSkip>0) ? (GetTickFrequency()/Config.CustomFrameSkip + extraTimeBuffer) : ((Config.PsxType&1) ? (GetTickFrequency()/45 + extraTimeBuffer) : (GetTickFrequency()/54 + extraTimeBuffer)); - // This is used for the framelimiter; The user can set a custom FPS limit, if none is specified, used default FPS limit (50fps or 60fps). - //u64 uLimiterExpectedTime = (Config.CustomFps>0) ? (GetTickFrequency()/Config.CustomFps + extraTimeBuffer) : ((Config.PsxType&1) ? (GetTickFrequency()/50 + extraTimeBuffer) : (GetTickFrequency()/60 + extraTimeBuffer)); - u64 uCurTime = GetCPUTicks(); - u64 uDeltaTime = uCurTime - uLastTime; - - // Don't skip the Very First Frame PCSX2 renders. (This line might not be needed, but was included incase it breaks something.) - if (uDeltaTime == uCurTime) uDeltaTime = 0; - - if (bOkayToSkip == 0) // If we're done rendering our consecutive frames, its okay to skip. - { - if (uDeltaTime > uExpectedTime) // Only skip if running slow. - { - //first freeze GS regs THEN send dummy packet - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 1, 0, 0); - else GSsetFrameSkip(1); - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - Cpu->ExecuteVU1Block = DummyExecuteVU1Block; - bOkayToSkip = noSkipFrames; - bKeepSkipping = yesSkipFrames; - } - } - else if (bOkayToSkip == noSkipFrames) // If we skipped last frame, unfreeze the GS regs - { - if (bKeepSkipping <= 1) { - //first set VU1 to enabled THEN unfreeze GS regs - if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) - Cpu->ExecuteVU1Block = s_prevExecuteVU1Block; - if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); - else GSsetFrameSkip(0); - bOkayToSkip--; - } - else {bKeepSkipping--;} - } - else {bOkayToSkip--;} - - //Frame Limit so we don't go over the FPS limit - FrameLimiter(); - - uLastTime = GetCPUTicks(); - - break; - } - } - } else { // VSync Start (240 hsyncs) +void vSyncDebugStuff() { #ifdef EE_PROFILING if( (iFrame%20) == 0 ) { SysPrintf("Profiled Cycles at %d frames %d\n", iFrame, profile_totalticks); @@ -399,218 +262,287 @@ void VSync() } } #endif +} - //SysPrintf("ctrs: %d %d %d %d\n", g_nCounters[0], g_nCounters[1], g_nCounters[2], g_nCounters[3]); - //SysPrintf("vif: %d\n", (((LARGE_INTEGER*)g_nCounters)->QuadPart * 1000000) / lfreq.QuadPart); - //memset(g_nCounters, 0, 16); +__forceinline void frameLimit() +{ + switch(CHECK_FRAMELIMIT) { + case PCSX2_FRAMELIMIT_LIMIT: + FrameLimiter(); + break; - counters[5].mode|= 0x10000; - if ((CSRw & 0x8)) GSCSRr|= 0x8; - if (!(GSIMR&0x800)) gsIrq(); + case PCSX2_FRAMELIMIT_SKIP: + case PCSX2_FRAMELIMIT_VUSKIP: //Skips a sequence of consecutive frames after a sequence of rendered frames + { + // This is the least number of consecutive frames we will render w/o skipping + #define noSkipFrames (Config.CustomConsecutiveFrames>0) ? Config.CustomConsecutiveFrames : 2 + // This is the number of consecutive frames we will skip + #define yesSkipFrames (Config.CustomConsecutiveSkip>0) ? Config.CustomConsecutiveSkip : 2 + static u8 bOkayToSkip = 0; + static u8 bKeepSkipping = 0; + static u64 uLastTime = 0; - hwIntcIrq(2); - psxVBlankStart(); - - if(Config.Patch) applypatch(1); - if(gates)rcntStartGate(0x8); + // This is some Extra Time to add to our Expected Time to compensate for lack of precision. + #define extraTimeBuffer 0 + // If uDeltaTime is less than this value, then we can frameskip. (45 & 54 FPS is 90% of fullspeed for Pal & NTSC respectively, the default is to only skip when slower than 90%) + u64 uExpectedTime = (Config.CustomFrameSkip>0) ? (GetTickFrequency()/Config.CustomFrameSkip + extraTimeBuffer) : ((Config.PsxType&1) ? (GetTickFrequency()/45 + extraTimeBuffer) : (GetTickFrequency()/54 + extraTimeBuffer)); + // This is used for the framelimiter; The user can set a custom FPS limit, if none is specified, used default FPS limit (50fps or 60fps). + //u64 uLimiterExpectedTime = (Config.CustomFps>0) ? (GetTickFrequency()/Config.CustomFps + extraTimeBuffer) : ((Config.PsxType&1) ? (GetTickFrequency()/50 + extraTimeBuffer) : (GetTickFrequency()/60 + extraTimeBuffer)); + u64 uCurTime = GetCPUTicks(); + u64 uDeltaTime = uCurTime - uLastTime; - //__Log("%u %u 0\n", cpuRegs.cycle-s_lastvsync[1], timeGetTime()-s_lastvsync[0]); - //s_lastvsync[0] = timeGetTime(); - //s_lastvsync[1] = cpuRegs.cycle; + // Don't skip the Very First Frame PCSX2 renders. (This line might not be needed, but was included incase it breaks something.) + if (uDeltaTime == uCurTime) uDeltaTime = 0; + + if (bOkayToSkip == 0) // If we're done rendering our consecutive frames, its okay to skip. + { + if (uDeltaTime > uExpectedTime) // Only skip if running slow. + { + //first freeze GS regs THEN send dummy packet + if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 1, 0, 0); + else GSsetFrameSkip(1); + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + Cpu->ExecuteVU1Block = DummyExecuteVU1Block; + bOkayToSkip = noSkipFrames; + bKeepSkipping = yesSkipFrames; + } + } + else if (bOkayToSkip == noSkipFrames) // If we skipped last frame, unfreeze the GS regs + { + if (bKeepSkipping <= 1) { + //first set VU1 to enabled THEN unfreeze GS regs + if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) + Cpu->ExecuteVU1Block = s_prevExecuteVU1Block; + if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); + else GSsetFrameSkip(0); + bOkayToSkip--; + } + else {bKeepSkipping--;} + } + else {bOkayToSkip--;} + + //Frame Limit so we don't go over the FPS limit + FrameLimiter(); + + uLastTime = GetCPUTicks(); + + break; + } + } +} + +__forceinline void VSyncStart(u32 sCycle) // VSync Start +{ + vSyncDebugStuff(); // EE Profiling and Debug code + if ((CSRw & 0x8)) GSCSRr|= 0x8; + if (!(GSIMR&0x800)) gsIrq(); //GS Irq + + hwIntcIrq(2); // HW Irq + psxVBlankStart(); // psxCounters vBlank Start + + if (gates) rcntStartGate(0x8, sCycle); // Counters Start Gate code + if (Config.Patch) applypatch(1); // Apply patches (ToDo: clean up patch code) +} + +__forceinline void VSyncEnd(u32 sCycle) // VSync End +{ + iFrame++; + *(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field + + // wait until GS stops + if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), 0, 0); + else { + GSvsync((*(u32*)(PS2MEM_GS+0x1000)&0x2000)); + // update here on single thread mode *OBSOLETE* + if( PAD1update != NULL ) PAD1update(0); + if( PAD2update != NULL ) PAD2update(1); + } + + hwIntcIrq(3); // HW Irq + psxVBlankEnd(); // psxCounters vBlank End + if (gates) rcntEndGate(0x8, sCycle); // Counters End Gate Code + SysUpdate(); // check for and handle keyevents + frameLimit(); // limit FPS (also handles frameskip and VUskip) +} + +#define hScanlineNextCycle(diff, cyclesAmount) { \ + u32 compareValue = (SCANLINE_ + cyclesAmount); \ + if (diff >= compareValue) { \ + u32 increment = (diff / compareValue); \ + /*SysPrintf("Counters Optimization\n");*/ \ + /* if counter's count increases on hblank gate's off signal OR if counter increases every hblank, THEN add to the counter */ \ + if ( (!(counters[0].mode & 0x30) && (gates & (1<<0))) || (((counters[0].mode & 0x83) == 0x83) && !(gates & (1<<0))) ) counters[0].count += (increment * HBLANK_COUNTER_SPEED); \ + if ( (!(counters[1].mode & 0x30) && (gates & (1<<1))) || (((counters[1].mode & 0x83) == 0x83) && !(gates & (1<<1))) ) counters[1].count += (increment * HBLANK_COUNTER_SPEED); \ + if ( (!(counters[2].mode & 0x30) && (gates & (1<<2))) || (((counters[2].mode & 0x83) == 0x83) && !(gates & (1<<2))) ) counters[2].count += (increment * HBLANK_COUNTER_SPEED); \ + if ( (!(counters[3].mode & 0x30) && (gates & (1<<3))) || (((counters[3].mode & 0x83) == 0x83) && !(gates & (1<<3))) ) counters[3].count += (increment * HBLANK_COUNTER_SPEED); \ + counters[4].sCycle += (increment * compareValue); \ + } \ + else counters[4].sCycle += cyclesAmount; \ + counters[4].CycleT = (s32)(cyclesAmount - (cpuRegs.cycle - counters[4].sCycle)); \ + if ((s32)counters[4].CycleT < 0) { \ + counters[4].sCycle += (((s32)counters[4].CycleT) * -1); \ + counters[4].CycleT = 0; \ + } \ +} + +__forceinline void hScanline() +{ + u32 difference = (cpuRegs.cycle - counters[4].sCycle); + + if (counters[4].mode & MODE_HBLANK) { //HBLANK Start + if (difference >= HBLANK_TIME_ ) { + hScanlineNextCycle(difference, HBLANK_TIME_); + rcntStartGate(0, counters[4].sCycle); + psxCheckStartGate(0); + counters[4].mode = MODE_HRENDER; + } + } + else { //HBLANK END / HRENDER Begin + if (difference >= (HRENDER_TIME_)) { + hScanlineNextCycle(difference, HRENDER_TIME_); + if (CSRw & 0x4) GSCSRr |= 4; // signal + if (!(GSIMR&0x400)) gsIrq(); + if (gates) rcntEndGate(0, counters[4].sCycle); + if (psxhblankgate) psxCheckEndGate(0); + counters[4].mode = MODE_HBLANK; + } + } +} + +void vSync() +{ + u32 diff = (cpuRegs.cycle - counters[5].sCycle); + + hScanline(); + + if (diff >= (VSYNC_HALF_)) { + counters[5].sCycle += (VSYNC_HALF_ * (u32)(diff / VSYNC_HALF_)); + counters[5].CycleT = VSYNC_HALF_ - (cpuRegs.cycle - counters[5].sCycle); + + if (counters[5].mode == MODE_VSYNC) { + VSyncEnd(counters[5].sCycle); + counters[5].mode = MODE_VRENDER; + } + else { + VSyncStart(counters[5].sCycle); + counters[5].mode = MODE_VSYNC; + } } } void rcntUpdate() { int i; - u32 change = 0; + + vSync(); //hBlank and vSync Timers + for (i=0; i<=3; i++) { - if(gates & (1< 0) SysPrintf("Change saved on %x = %x\n", i, change); - } - - if ((u32)(cpuRegs.cycle - counters[4].sCycleT) >= (u32)counters[4].CycleT && hblankend == 1) { - - if (CSRw & 0x4) GSCSRr |= 4; // signal - if (!(GSIMR&0x400)) gsIrq(); - if (gates) rcntEndGate(0); - if (psxhblankgate) psxCheckEndGate(0); - hblankend = 0; - - counters[4].CycleT = HBLANKCNT(counters[4].count); - } - else if ((u32)(cpuRegs.cycle - counters[4].sCycleT) >= (u32)counters[4].CycleT) { - - if(counters[4].count >= counters[4].Cycle) { - //SysPrintf("%x of %x hblanks reorder in %x cycles cpuRegs.cycle = %x\n", counters[4].count, counters[4].Cycle, cpuRegs.cycle - counters[4].sCycleT, cpuRegs.cycle); - counters[4].sCycleT += HBLANKCNT(counters[4].Cycle); - counters[4].count -= counters[4].Cycle; - } - //counters[4].sCycleT += HBLANKCNT(1); - counters[4].count++; - - counters[4].CycleT = HBLANKCNT(counters[4].count) - (HBLANKCNT(0.5)); - - rcntStartGate(0); - psxCheckStartGate(0); - hblankend = 1; - //if(cpuRegs.cycle > 0xffff0000 || cpuRegs.cycle < 0x1000 - //SysPrintf("%x hsync done in %x cycles cpuRegs.cycle = %x next will happen on %x\n", counters[4].count, counters[4].CycleT, cpuRegs.cycle, (u32)(counters[4].sCycleT + counters[4].CycleT)); - } - - if((counters[5].mode & 0x10000)) { - if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT){ - //counters[5].sCycleT = cpuRegs.cycle; - counters[5].CycleT = VBLANKCNT(counters[5].count); - VSync(); - } - } - else if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT) { - if(counters[5].count >= counters[5].Cycle) { - //SysPrintf("reset %x of %x frames done in %x cycles cpuRegs.cycle = %x\n", counters[5].count, counters[5].Cycle, cpuRegs.cycle - counters[5].sCycleT, cpuRegs.cycle); - counters[5].sCycleT += VBLANKCNT(counters[5].Cycle); - counters[5].count -= counters[5].Cycle; - } - counters[5].count++; - //counters[5].sCycleT += VBLANKCNT(1); //this line brings back magna carta loading animation, but breaks vsyncs >< (rama) - counters[5].CycleT = VBLANKCNT(counters[5].count) - (VBLANKCNT(1)/2); - //SysPrintf("%x frames done in %x cycles cpuRegs.cycle = %x cycletdiff %x\n", counters[5].Cycle, counters[5].sCycleT, cpuRegs.cycle, (counters[5].CycleT - VBLANKCNT(1)) - (cpuRegs.cycle - counters[5].sCycleT)); - VSync(); + else counters[i].sCycleT = cpuRegs.cycle; } for (i=0; i<=3; i++) { if (!(counters[i].mode & 0x80)) continue; // Stopped - if ((s64)(counters[i].target - counters[i].count) <= 0 /*&& (counters[i].target & 0xffff) > 0*/) { // Target interrupt + if (counters[i].count >= counters[i].target) { // Target interrupt - //if((counters[i].target > 0xffff)) { - //SysPrintf("EE Correcting target %x after reset on target\n", i); - counters[i].target &= 0xffff; - //} + counters[i].target &= 0xffff; - if(counters[i].mode & 0x100 ) { + if(counters[i].mode & 0x100) { - EECNT_LOG("EE counter %d target reached mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); - counters[i].mode|= 0x0400; // Target flag - hwIntcIrq(counters[i].interrupt); + EECNT_LOG("EE counter %d target reached mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); + counters[i].mode|= 0x0400; // Equal Target flag + hwIntcIrq(counters[i].interrupt); - if (counters[i].mode & 0x40) { //The PS2 only resets if the interrupt is enabled - Tested on PS2 - counters[i].count -= counters[i].target; // Reset on target - } - else counters[i].target += 0x10000000; - } - else counters[i].target += 0x10000000; - + if (counters[i].mode & 0x40) { //The PS2 only resets if the interrupt is enabled - Tested on PS2 + counters[i].count -= counters[i].target; // Reset on target + } + else counters[i].target |= 0x10000000; + } + else counters[i].target |= 0x10000000; } + if (counters[i].count > 0xffff) { if (counters[i].mode & 0x0200) { // Overflow interrupt EECNT_LOG("EE counter %d overflow mode %x count %x target %x\n", i, counters[i].mode, counters[i].count, counters[i].target); - counters[i].mode|= 0x0800; // Overflow flag + counters[i].mode |= 0x0800; // Overflow flag hwIntcIrq(counters[i].interrupt); - //SysPrintf("counter[%d] overflow interrupt (%x)\n", i, cpuRegs.cycle); } counters[i].count -= 0x10000; - //if(counters[i].target > 0xffff) { - //SysPrintf("EE %x Correcting target on overflow\n", i); - counters[i].target &= 0xffff; - //} - } + counters[i].target &= 0xffff; + } } rcntSet(); } -void rcntWcount(int index, u32 value) { - u32 change = 0; +void rcntWcount(int index, u32 value) +{ EECNT_LOG("EE count write %d count %x with %x target %x eecycle %x\n", index, counters[index].count, value, counters[index].target, cpuRegs.eCycle); counters[index].count = value & 0xffff; - //if(counters[index].target > 0xffff) { - //SysPrintf("EE Counter %x count write, target > 0xffff\n", index); - counters[index].target &= 0xffff; - //} + counters[index].target &= 0xffff; //rcntUpd(index); + if((counters[index].mode & 0x3) != 0x3) { - change = cpuRegs.cycle - counters[index].sCycleT; + //counters[index].sCycleT = cpuRegs.cycle; + + u32 change = cpuRegs.cycle - counters[index].sCycleT; change -= (change / counters[index].rate) * counters[index].rate; counters[index].sCycleT = cpuRegs.cycle - change; } -/* else { - SysPrintf("EE Counter %x count write %x\n", index, value); - }*/ + rcntSet(); } void rcntWmode(int index, u32 value) { - u32 change = 0; - - if (value & 0xc00) { //Clear status flags, the ps2 only clears what is given in the value - counters[index].mode &= ~(value & 0xc00); - } - if(counters[index].mode & 0x80) { - if((counters[index].mode & 0x3) != 0x3){ - change = cpuRegs.cycle - counters[index].sCycleT; + if((counters[index].mode & 0x3) != 0x3) { + //counters[index].count += (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; + //counters[index].sCycleT = cpuRegs.cycle; + + u32 change = cpuRegs.cycle - counters[index].sCycleT; counters[index].count += (int)(change / counters[index].rate); change -= (change / counters[index].rate) * counters[index].rate; counters[index].sCycleT = cpuRegs.cycle - change; } - //if(change != 0) SysPrintf("Weee\n"); - //counters[index].sCycleT = cpuRegs.cycle - ((cpuRegs.cycle - counters[index].sCycleT) % counters[index].rate); -#ifdef PCSX2_DEVBUILD - if(!(value & 0x80)) SysPrintf("Stopping\n"); -#endif - } - else { -#ifdef PCSX2_DEVBUILD - SysPrintf("Counter %d not running c%x s%x c%x\n", index, counters[index].count, counters[index].sCycleT, cpuRegs.cycle); - if(value & 0x80) SysPrintf("Starting %d, v%x\n", index, value); -#endif - counters[index].sCycleT = cpuRegs.cycle; } + else counters[index].sCycleT = cpuRegs.cycle; - //if((value & 0x80) && !(counters[index].mode & 0x80)) rcntUpd(index); //Counter wasnt started, so set the start cycle + counters[index].mode &= ~(value & 0xc00); //Clear status flags, the ps2 only clears what is given in the value counters[index].mode = (counters[index].mode & 0xc00) | (value & 0x3ff); EECNT_LOG("EE counter set %d mode %x count %x\n", index, counters[index].mode, rcntCycle(index)); - /*if((value & 0x3) && (counters[index].mode & 0x3) != 0x3){ - //SysPrintf("Syncing %d with HBLANK clock\n", index); - counters[index].CycleT = counters[4].CycleT; - }*/ - switch (value & 0x3) { //Clock rate divisers *2, they use BUSCLK speed not PS2CLK case 0: counters[index].rate = 2; break; case 1: counters[index].rate = 32; break; case 2: counters[index].rate = 512; break; - case 3: counters[index].rate = PS2HBLANK; break; + case 3: counters[index].rate = SCANLINE_; break; } if((counters[index].mode & 0xF) == 0x7) { gates &= ~(1< 0xffff) && (counters[index].target & 0xffff) > rcntCycle(index)) { + /*if ((value & 0x580) == 0x580) { // If we need to compare the target value again, correct the target //SysPrintf("EE Correcting target %x after mode write\n", index); counters[index].target &= 0xffff; }*/ @@ -618,82 +550,73 @@ void rcntWmode(int index, u32 value) rcntSet(); } -void rcntStartGate(unsigned int mode){ +void rcntStartGate(unsigned int mode, u32 sCycle) { int i; - if(mode == 0){ - for(i = 0; i < 4; i++){ //Update counters using the hblank as the clock - if((counters[i].mode & 0x83) == 0x83) counters[i].count++; - } - } + for (i=0; i <=3; i++) { //Gates for counters - for(i=0; i <=3; i++){ //Gates for counters - if(!(gates & (1<> 4); - switch((counters[i].mode & 0x30) >> 4) { - case 0x0: //Count When Signal is low (off) + + switch (counters[i].mode & 0x30) { + case 0x00: //Count When Signal is low (off) + counters[i].mode |= 0x80; + counters[i].count += (int)((cpuRegs.cycle - counters[i].sCycleT) / counters[i].rate); + counters[i].sCycle = sCycle; + counters[i].sCycleT = sCycle; + break; + case 0x20: counters[i].count = rcntRcount(i); - rcntUpd(i); - counters[i].mode &= ~0x80; break; - case 0x1: //Reset and start counting on Vsync start + case 0x10: //Reset and start counting on Vsync start + case 0x30: //Reset and start counting on Vsync start and end counters[i].mode |= 0x80; - rcntReset(i); + counters[i].count = 0; + counters[i].sCycle = sCycle; + counters[i].sCycleT = sCycle; counters[i].target &= 0xffff; break; - case 0x2: //Reset and start counting on Vsync end - //Do Nothing - break; - case 0x3: //Reset and start counting on Vsync start and end - counters[i].mode |= 0x80; - rcntReset(i); - counters[i].target &= 0xffff; - break; - default: - SysPrintf("EE Start Counter %x Gate error\n", i); - break; } } } -void rcntEndGate(unsigned int mode) { + +void rcntEndGate(unsigned int mode, u32 sCycle) { int i; for(i=0; i <=3; i++) { //Gates for counters - if(!(gates & (1<> 4); - switch((counters[i].mode & 0x30) >> 4){ - case 0x0: //Count When Signal is low (off) - rcntUpd(i); - counters[i].mode |= 0x80; + + switch (counters[i].mode & 0x30) { + case 0x00: //Count When Signal is low (off) + counters[i].mode &= ~0x80; + counters[i].sCycle = sCycle; + counters[i].sCycleT = sCycle; break; - case 0x1: //Reset and start counting on Vsync start - //Do Nothing + case 0x10: + counters[i].count = rcntRcount(i); break; - case 0x2: //Reset and start counting on Vsync end + case 0x20: //Reset and start counting on Vsync end + case 0x30: //Reset and start counting on Vsync start and end counters[i].mode |= 0x80; - rcntReset(i); + counters[i].count = 0; + counters[i].sCycle = sCycle; + counters[i].sCycleT = sCycle; counters[i].target &= 0xffff; break; - case 0x3: //Reset and start counting on Vsync start and end - counters[i].mode |= 0x80; - rcntReset(i); - counters[i].target &= 0xffff; - break; - default: - SysPrintf("EE Start Counter %x Gate error\n", i); - break; } } } + void rcntWtarget(int index, u32 value) { EECNT_LOG("EE target write %d target %x value %x\n", index, counters[index].target, value); counters[index].target = value & 0xffff; + if (counters[index].target <= rcntCycle(index)/* && counters[index].target != 0*/) { //SysPrintf("EE Saving target %d from early trigger, target = %x, count = %x\n", index, counters[index].target, rcntCycle(index)); - counters[index].target += 0x10000000; + counters[index].target |= 0x10000000; } rcntSet(); } @@ -717,9 +640,9 @@ u32 rcntRcount(int index) { u32 rcntCycle(int index) { - if ((counters[index].mode & 0x80)) + if ((counters[index].mode & 0x80)) return (u32)counters[index].count + (int)((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); - else + else return (u32)counters[index].count; } diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index dce1d12154..a7049bb064 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -26,19 +26,82 @@ typedef struct { u32 CycleT, sCycleT; } Counter; +//------------------------------------------------------------------ +// SPEED HACKS!!! (1 is normal) (They have inverse affects, only set 1 at a time) +//------------------------------------------------------------------ +#define HBLANK_COUNTER_SPEED 1 //Set to '3' to double the speed of games like KHII +//#define HBLANK_TIMER_SLOWDOWN 1 //Set to '2' to increase the speed of games like God of War (FPS will be less, but game will be faster) + +//------------------------------------------------------------------ +// NTSC Timing Information!!! (some scanline info is guessed) +//------------------------------------------------------------------ +#define SCANLINE_NTSC (u32)(PS2CLK / 15734.25)//18743 +#define HRENDER_TIME_NTSC (u32)(SCANLINE_NTSC / 2)//15528 //time from hblank end to hblank start (PS2CLK / 18991.368423051722991900181367568) +#define HBLANK_TIME_NTSC (u32)(SCANLINE_NTSC / 2)//3215 //time from hblank start to hblank end (PS2CLK / 91738.91105912572817760653181028) +#define VSYNC_NTSC (u32)(PS2CLK / 59.94) //hz +#define VSYNC_HALF_NTSC (u32)(VSYNC_NTSC / 2) //hz + +#define SCANLINES_TOTAL_NTSC 525 // total number of scanlines +#define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame +#define SCANLINES_VRENDER_NTSC 240 // scanlines in a half-frame (because of interlacing) +#define SCANLINES_VBLANK1_NTSC 19 // scanlines used for vblank1 (even interlace) +#define SCANLINES_VBLANK2_NTSC 20 // scanlines used for vblank2 (odd interlace) + +//------------------------------------------------------------------ +// PAL Timing Information!!! (some scanline info is guessed) +//------------------------------------------------------------------ +#define SCANLINE_PAL (u32)(PS2CLK / 15625)//18874 +#define HRENDER_TIME_PAL (u32)(SCANLINE_PAL / 2)//15335 //time from hblank end to hblank start +#define HBLANK_TIME_PAL (u32)(SCANLINE_PAL / 2)//3539 //time from hblank start to hblank end +#define VSYNC_PAL (u32)(PS2CLK / 50) //hz +#define VSYNC_HALF_PAL (u32)(VSYNC_PAL / 2) //hz + +#define SCANLINES_TOTAL_PAL 625 // total number of scanlines +#define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame +#define SCANLINES_VRENDER_PAL 288 // scanlines in a half-frame (because of interlacing) +#define SCANLINES_VBLANK1_PAL 19 // scanlines used for vblank1 (even interlace) +#define SCANLINES_VBLANK2_PAL 20 // scanlines used for vblank2 (odd interlace) + +//------------------------------------------------------------------ +// Timing (PAL/NTSC) Information!!! +//------------------------------------------------------------------ +#define SCANLINE_ ((Config.PsxType&1) ? SCANLINE_PAL : SCANLINE_NTSC) +#define HRENDER_TIME_ ((Config.PsxType&1) ? HRENDER_TIME_PAL : HRENDER_TIME_NTSC) +#define HBLANK_TIME_ ((Config.PsxType&1) ? HBLANK_TIME_PAL : HBLANK_TIME_NTSC) +#define VSYNC_ ((Config.PsxType&1) ? VSYNC_PAL : VSYNC_NTSC) +#define VSYNC_HALF_ ((Config.PsxType&1) ? VSYNC_HALF_PAL : VSYNC_HALF_NTSC) + +#define SCANLINES_TOTAL_ ((Config.PsxType&1) ? SCANLINES_TOTAL_PAL : SCANLINES_TOTAL_NTSC) +#define SCANLINES_VSYNC_ ((Config.PsxType&1) ? SCANLINES_VSYNC_PAL : SCANLINES_VSYNC_NTSC) +#define SCANLINES_VRENDER_ ((Config.PsxType&1) ? SCANLINES_VRENDER_PAL : SCANLINES_VRENDER_NTSC) +#define SCANLINES_VBLANK1_ ((Config.PsxType&1) ? SCANLINES_VBLANK1_PAL : SCANLINES_VBLANK1_NTSC) +#define SCANLINES_VBLANK2_ ((Config.PsxType&1) ? SCANLINES_VBLANK2_PAL : SCANLINES_VBLANK2_NTSC) + +//------------------------------------------------------------------ +// vSync and hBlank Timing Modes +//------------------------------------------------------------------ +#define MODE_VRENDER 0x0 //Set during the Render/Frame Scanlines +#define MODE_VBLANK 0x1 //Set during the Blanking Scanlines +#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 + + extern Counter counters[6]; extern u32 nextCounter, nextsCounter; void rcntInit(); void rcntUpdate(); -void rcntStartGate(unsigned int mode); -void rcntEndGate(unsigned int mode); +void rcntStartGate(unsigned int mode, u32 sCycle); +void rcntEndGate(unsigned int mode, u32 sCycle); void rcntWcount(int index, u32 value); void rcntWmode(int index, u32 value); void rcntWtarget(int index, u32 value); void rcntWhold(int index, u32 value); -u32 rcntRcount(int index); -u32 rcntCycle(int index); +u32 rcntRcount(int index); +u32 rcntCycle(int index); int rcntFreeze(gzFile f, int Mode); void UpdateVSyncRate();