Counters changes: reverted back to my counters code from svn241 and fixed the DMC1 bug as well as alot of other stuff (including some of the problems Jake.Stine found out in Issue 32)

git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@246 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
cottonvibes 2008-10-29 05:03:19 +00:00 committed by Gregory Hainaut
parent f69a63b489
commit 4da570c671
2 changed files with 332 additions and 346 deletions

View File

@ -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(iEnd<iExpectedEnd);
} while (iEnd<iExpectedEnd);
iStart = iExpectedEnd; //remember the expected value frame. improves smoothness
}
@ -228,99 +183,7 @@ extern void DummyExecuteVU1Block(void);
//static u32 lastWasSkip=0;
//extern u32 unpacktotal;
#include "VU.h"
void VSync()
{
if (counters[5].mode & 0x10000) { // VSync End (22 hsyncs)
// swap the vsync field
u32 newfield = (*(u32*)(PS2MEM_GS+0x1000)&0x2000) ? 0 : 0x2000;
*(u32*)(PS2MEM_GS+0x1000) = (*(u32*)(PS2MEM_GS+0x1000) & ~(1<<13)) | newfield;
iFrame++;
// wait until GS stops
if( CHECK_MULTIGS ) {
GSRingBufSimplePacket(GS_RINGTYPE_VSYNC, newfield, 0, 0);
}
else {
GSvsync(newfield);
// update here on single thread mode *OBSOLETE*
if( PAD1update != NULL ) PAD1update(0);
if( PAD2update != NULL ) PAD2update(1);
}
counters[5].mode&= ~0x10000;
hwIntcIrq(3);
psxVBlankEnd();
if(gates)rcntEndGate(0x8);
SysUpdate();
// used to limit frames
switch(CHECK_FRAMELIMIT) {
case PCSX2_FRAMELIMIT_LIMIT:
FrameLimiter();
break;
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;
// 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<<i) ) {
//SysPrintf("Stopped accidental update of ee counter %x when using a gate\n", i);
continue;
}
if ( gates & (1<<i) ) continue;
if ((counters[i].mode & 0x80) && (counters[i].mode & 0x3) != 0x3) {
change = cpuRegs.cycle - counters[i].sCycleT;
//counters[i].count += (cpuRegs.cycle - counters[i].sCycleT) / counters[i].rate;
//counters[i].sCycleT = cpuRegs.cycle;
u32 change = cpuRegs.cycle - counters[i].sCycleT;
counters[i].count += (int)(change / counters[i].rate);
change -= (change / counters[i].rate) * counters[i].rate;
counters[i].sCycleT = cpuRegs.cycle - change;
}
else change = 0;
counters[i].sCycleT = cpuRegs.cycle - change;
//if(change > 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<<index);
SysPrintf("Gate Disabled\n");
SysPrintf("Counters: Gate Disabled\n");
//counters[index].mode &= ~0x80;
}
else if (counters[index].mode & 0x4) {
// SysPrintf("Gate enable on counter %x mode %x\n", index, counters[index].mode);
gates |= 1<<index;
counters[index].mode &= ~0x80;
rcntReset(index);
gates |= (1<<index);
counters[index].mode &= ~0x80;
rcntReset(index);
}
else gates &= ~(1<<index);
/*if((counters[index].target > 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<<i))) continue;
if ((mode == 0) && ((counters[i].mode & 0x83) == 0x83)) counters[i].count += HBLANK_COUNTER_SPEED; //Update counters using the hblank as the clock
if (!(gates & (1<<i))) continue;
if ((counters[i].mode & 0x8) != mode) continue;
//SysPrintf("Gate %d mode %d Start\n", i, (counters[i].mode & 0x30) >> 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<<i))) continue;
if (!(gates & (1<<i))) continue;
if ((counters[i].mode & 0x8) != mode) continue;
//SysPrintf("Gate %d mode %d End\n", i, (counters[i].mode & 0x30) >> 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;
}

View File

@ -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();