/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2003 Pcsx2 Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "Common.h" #include "PsxCommon.h" #include "GS.h" int gates = 0; extern u8 psxhblankgate; int hblankend = 0; Counter counters[6]; u32 nextCounter, nextsCounter; // 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 - (cpuRegs.cycle % counters[index].rate); } void rcntUpd(int index) { counters[index].sCycle = cpuRegs.cycle - (cpuRegs.cycle % counters[index].rate); rcntUpdTarget(index); } void rcntReset(int index) { counters[index].count = 0; counters[index].mode&= ~0x00400C00; rcntUpd(index); } void rcntSet() { u32 c; int i; nextCounter = 0xffffffff; nextsCounter = cpuRegs.cycle; for (i = 0; i < 4; i++) { if (!(counters[i].mode & 0x80)) continue; // Stopped c = (0xffff - rcntCycle(i)) * counters[i].rate; if (c < nextCounter) { nextCounter = c; } // the + 10 is just in case of overflow if(eecntmask & (1< 0 ) { if( iFrame > g_TestRun.frame ) { // take a snapshot if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) { if( g_TestRun.snapdone ) { g_TestRun.curimage++; g_TestRun.snapdone = 0; g_TestRun.frame += 20; if( g_TestRun.curimage >= g_TestRun.numimages ) { // exit SysClose(); exit(0); } } else { // query for the image GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture); } } else { // exit SysClose(); exit(0); } } } GSVSYNC(); if( g_SaveGSStream == 1 ) { freezeData fP; g_SaveGSStream = 2; gsFreeze(g_fGSSave, 1); if (GSfreeze(FREEZE_SIZE, &fP) == -1) { gzclose(g_fGSSave); g_SaveGSStream = 0; } else { fP.data = (s8*)malloc(fP.size); if (fP.data == NULL) { gzclose(g_fGSSave); g_SaveGSStream = 0; } else { if (GSfreeze(FREEZE_SAVE, &fP) == -1) { gzclose(g_fGSSave); g_SaveGSStream = 0; } else { gzwrite(g_fGSSave, &fP.size, sizeof(fP.size)); if (fP.size) { gzwrite(g_fGSSave, fP.data, fP.size); free(fP.data); } } } } } else if( g_SaveGSStream == 2 ) { if( --g_nLeftGSFrames <= 0 ) { gzclose(g_fGSSave); g_fGSSave = NULL; g_SaveGSStream = 0; SysPrintf("Done saving GS stream\n"); } } #endif // used to limit frames switch(CHECK_FRAMELIMIT) { case PCSX2_FRAMELIMIT_LIMIT: FrameLimiter(); break; case PCSX2_FRAMELIMIT_SKIP: case PCSX2_FRAMELIMIT_VUSKIP: { // the 6 was after trial and error static u32 uPrevTimes[6] = {0}, uNextFrame = 0, uNumFrames = 0, uTotalTime = 0; static u32 uLastTime = 0; static int nConsecutiveSkip = 0, nConsecutiveRender = 0; extern u32 g_bVUSkip; static int changed = 0; static int nNoSkipFrames = 0; u32 uExpectedTime; u32 uCurTime = timeGetTime(); u32 uDeltaTime = uCurTime - uLastTime; assert( GSsetFrameSkip != NULL ); if( uLastTime > 0 ) { if( uNumFrames == ARRAYSIZE(uPrevTimes) ) uTotalTime -= uPrevTimes[uNextFrame]; uPrevTimes[uNextFrame] = uDeltaTime; uNextFrame = (uNextFrame + 1) % ARRAYSIZE(uPrevTimes); uTotalTime += uDeltaTime; if( uNumFrames < ARRAYSIZE(uPrevTimes) ) ++uNumFrames; } uExpectedTime = (Config.PsxType&1) ? (ARRAYSIZE(uPrevTimes) * 1000 / 50 -1) : (ARRAYSIZE(uPrevTimes) * 1000 / 60 - 1); if( nNoSkipFrames > 0 ) --nNoSkipFrames; // hmm... this might be more complicated than it needs to be if( changed != 0 ) { if( changed > 0 ) { ++nConsecutiveRender; --changed; if( nConsecutiveRender > 20 && uTotalTime + 1 < uExpectedTime ) { Sleep(uExpectedTime-uTotalTime); nNoSkipFrames = ARRAYSIZE(uPrevTimes); } } else { ++nConsecutiveSkip; ++changed; } } else { if( nNoSkipFrames == 0 && nConsecutiveRender > 3 && nConsecutiveSkip < 20 && (CHECK_MULTIGS? (uTotalTime >= uExpectedTime + uDeltaTime/4 && (uTotalTime >= uExpectedTime + uDeltaTime*3/4 || nConsecutiveSkip==0)) : (uTotalTime >= uExpectedTime + (uDeltaTime/4))) ) { if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) { Cpu->ExecuteVU1Block = DummyExecuteVU1Block; } if( nConsecutiveSkip == 0 ) { if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 1, 0, 0); else GSsetFrameSkip(1); } changed = -3; nConsecutiveSkip++; } else { if( CHECK_FRAMELIMIT == PCSX2_FRAMELIMIT_VUSKIP ) { Cpu->ExecuteVU1Block = recExecuteVU1Block; } if( nConsecutiveSkip ) { if( CHECK_MULTIGS ) GSRingBufSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); else GSsetFrameSkip(0); nConsecutiveRender = 0; } changed = 3; nConsecutiveRender++; nConsecutiveSkip = 0; if( nConsecutiveRender > 20 && uTotalTime + 1 < uExpectedTime ) { Sleep(uExpectedTime-uTotalTime); nNoSkipFrames = ARRAYSIZE(uPrevTimes); } } } uLastTime = uCurTime; break; } } //counters[5].mode&= ~0x10000; //UpdateVSyncRate(); //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); counters[5].mode|= 0x10000; if (!(GSCSRr & 0x8)){ GSCSRr|= 0x8; } if (!(GSIMR&0x800) ) gsIrq(); hwIntcIrq(2); psxVSyncStart(); if(Config.Patch) applypatch(1); if(gates)rcntStartGate(0x8); // __Log("%u %u 0\n", cpuRegs.cycle-s_lastvsync[1], timeGetTime()-s_lastvsync[0]); // s_lastvsync[0] = timeGetTime(); // s_lastvsync[1] = cpuRegs.cycle; } } void rcntUpdate() { int i; for (i=0; i<=3; i++) { if (!(counters[i].mode & 0x80)) continue; // Stopped counters[i].count += (int)((cpuRegs.cycle - counters[i].sCycleT) / counters[i].rate); counters[i].sCycleT = cpuRegs.cycle - (cpuRegs.cycle % counters[i].rate); } for (i=0; i<=3; i++) { if (!(counters[i].mode & 0x80)) continue; // Stopped if ((counters[i].count & ~0x3) == (counters[i].target & ~0x3)) { // Target interrupt /*if (rcntCycle(i) != counters[i].target){ SysPrintf("rcntcycle = %d, target = %d, cyclet = %d\n", rcntCycle(i), counters[i].target, counters[i].sCycleT); counters[i].sCycleT += (rcntCycle(i) - counters[i].target) * counters[i].rate; SysPrintf("rcntcycle = %d, target = %d, cyclet = %d\n", rcntCycle(i), counters[i].target, counters[i].sCycleT); }*/ //if ((eecntmask & (1 << i)) == 0) { counters[i].mode|= 0x0400; // Target flag if(counters[i].mode & 0x100) { hwIntcIrq(counters[i].interrupt); } //eecntmask |= (1 << i); //} if (counters[i].mode & 0x40) { // Reset on target counters[i].count = 0; eecntmask &= ~(1 << i); //rcntUpd(i); } } if (counters[i].count >= 0xffff) { eecntmask &= ~(1 << i); counters[i].mode|= 0x0800; // Overflow flag if (counters[i].mode & 0x0200) { // Overflow interrupt hwIntcIrq(counters[i].interrupt); // SysPrintf("counter[%d] overflow interrupt (%x)\n", i, cpuRegs.cycle); } counters[i].count = 0; //rcntUpd(i); } // rcntUpd(i); } if ((cpuRegs.cycle - counters[4].sCycleT) >= counters[4].CycleT && hblankend == 1){ if (!(GSCSRr & 0x4)){ GSCSRr |= 4; // signal } if (!(GSIMR&0x400) ) gsIrq(); if(gates)rcntEndGate(0); if(psxhblankgate)psxCheckEndGate(0); hblankend = 0; counters[4].CycleT = counters[4].rate; } if ((cpuRegs.cycle - counters[4].sCycleT) >= counters[4].CycleT) { counters[4].sCycleT = cpuRegs.cycle; counters[4].sCycle = cpuRegs.cycle; counters[4].CycleT = counters[4].rate-PS2HBLANKEND; counters[4].Cycle = counters[4].rate; counters[4].count = 0; if(gates)rcntStartGate(0); if(psxhblankgate)psxCheckStartGate(0); hblankend = 1; } if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT && (counters[5].mode & 0x10000)){ counters[5].CycleT = counters[5].rate; VSync(); } if ((cpuRegs.cycle - counters[5].sCycleT) >= counters[5].CycleT) { counters[5].sCycleT = cpuRegs.cycle; counters[5].sCycle = cpuRegs.cycle; counters[5].CycleT = counters[5].rate-PS2VBLANKEND; counters[5].Cycle = counters[5].rate; counters[5].count = 0; VSync(); } rcntSet(); } void rcntWcount(int index, u32 value) { //SysPrintf ("writeCcount[%d] = %x\n", index, value); #ifdef EECNT_LOG 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); #endif //if((u16)value < counters[index].target) //eecntmask &= ~(1 << index); counters[index].count = value & 0xffff; rcntUpd(index); rcntSet(); } void rcntWmode(int index, u32 value) { if (value & 0xc00) { //Clear status flags, the ps2 only clears what is given in the value eecntmask &= ~(1 << index); counters[index].mode &= ~((value & 0xc00)); } //if((value & 0x3ff) != (counters[index].mode & 0x3ff))eecntmask &= ~(1 << index); counters[index].mode = (counters[index].mode & 0xc00) | (value & 0x3ff); #ifdef EECNT_LOG EECNT_LOG("EE counter set %d mode %x\n", index, counters[index].mode); #endif 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; } if((counters[index].mode & 0xF) == 0x7) { gates &= ~(1<> 4); switch((counters[i].mode & 0x30) >> 4){ case 0x0: //Count When Signal is low (off) counters[i].count = rcntRcount(i); rcntUpd(i); counters[i].mode &= ~0x80; break; case 0x1: //Reset and start counting on Vsync start counters[i].mode |= 0x80; rcntReset(i); 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); break; default: SysPrintf("EE Start Counter %x Gate error\n", i); break; } } } void rcntEndGate(int mode){ 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; break; case 0x1: //Reset and start counting on Vsync start //Do Nothing break; case 0x2: //Reset and start counting on Vsync end counters[i].mode |= 0x80; rcntReset(i); break; case 0x3: //Reset and start counting on Vsync start and end counters[i].mode |= 0x80; rcntReset(i); break; default: SysPrintf("EE Start Counter %x Gate error\n", i); break; } } } void rcntWtarget(int index, u32 value) { eecntmask &= ~(1 << index); counters[index].target = value & 0xffff; #ifdef EECNT_LOG EECNT_LOG("EE target write %d target %x value %x\n", index, counters[index].target, value); #endif rcntSet(); } void rcntWhold(int index, u32 value) { #ifdef EECNT_LOG EECNT_LOG("EE hold write %d value %x\n", index, value); #endif counters[index].hold = value; } u16 rcntRcount(int index) { u16 ret; if ((counters[index].mode & 0x80)) { ret = counters[index].count + (int)((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); }else{ ret = counters[index].count; } return (u16)ret; } u32 rcntCycle(int index) { if ((counters[index].mode & 0x80)) { return (u32)counters[index].count + (int)((cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate); }else{ return (u32)counters[index].count; } } int rcntFreeze(gzFile f, int Mode) { gzfreezel(counters); gzfreeze(&nextCounter, sizeof(nextCounter)); gzfreeze(&nextsCounter, sizeof(nextsCounter)); return 0; }