Timers: Fix up some timer behaviour

This commit is contained in:
refractionpcsx2 2024-05-01 00:26:59 +01:00
parent 999f0cc84f
commit 3b63445f07
2 changed files with 44 additions and 37 deletions

View File

@ -220,11 +220,13 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
const u64 Render = HalfFrame - Blank; const u64 Render = HalfFrame - Blank;
const u64 GSBlank = Scanline * ((ntsc_hblank ? 3.5 : 3) + extra_scanlines); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start const u64 GSBlank = Scanline * ((ntsc_hblank ? 3.5 : 3) + extra_scanlines); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start
// Important! The hRender/hBlank timers should be 50/50 for best results. // Important! The hRender/hBlank timer ratio below is set according to PS2 tests.
// (this appears to be what the real EE's timing crystal does anyway) // in EE Cycles taken from PAL system:
// 18876 cycles for hsync
u64 hBlank = Scanline / 2; // 15796 cycles for hsync are low (render)
u64 hRender = Scanline - hBlank; // Ratio: 83.68298368298368
u64 hRender = Scanline * 0.8368298368298368f;
u64 hBlank = Scanline - hRender;
if (!IsInterlacedVideoMode()) if (!IsInterlacedVideoMode())
{ {
@ -592,10 +594,9 @@ __fi void rcntUpdate_hScanline()
//iopEventAction = 1; //iopEventAction = 1;
if (hsyncCounter.Mode == MODE_HBLANK) if (hsyncCounter.Mode == MODE_HBLANK)
{ //HBLANK Start { //HBLANK End / HRENDER Begin
rcntEndGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT);
rcntStartGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT); psxHBlankEnd();
psxHBlankStart();
// Setup the hRender's start and end cycle information: // Setup the hRender's start and end cycle information:
hsyncCounter.sCycle += vSyncInfo.hBlank; // start (absolute cycle value) hsyncCounter.sCycle += vSyncInfo.hBlank; // start (absolute cycle value)
@ -603,7 +604,7 @@ __fi void rcntUpdate_hScanline()
hsyncCounter.Mode = MODE_HRENDER; hsyncCounter.Mode = MODE_HRENDER;
} }
else else
{ //HBLANK END / HRENDER Begin { //HBLANK START / HRENDER End
if (!CSRreg.HSINT) if (!CSRreg.HSINT)
{ {
CSRreg.HSINT = true; CSRreg.HSINT = true;
@ -611,9 +612,8 @@ __fi void rcntUpdate_hScanline()
gsIrq(); gsIrq();
} }
rcntEndGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT); rcntStartGate(false, hsyncCounter.sCycle + hsyncCounter.CycleT);
psxHBlankStart();
psxHBlankEnd();
// set up the hblank's start and end cycle information: // set up the hblank's start and end cycle information:
hsyncCounter.sCycle += vSyncInfo.hRender; // start (absolute cycle value) hsyncCounter.sCycle += vSyncInfo.hRender; // start (absolute cycle value)
@ -816,10 +816,14 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
break; break;
case 0x1: // Reset on Vsync start case 0x1: // Reset on Vsync start
case 0x3: // Reset on Vsync start and end case 0x3: // Reset on Vsync start and end
{
counters[i].count = 0; counters[i].count = 0;
counters[i].target &= 0xffff; counters[i].target &= 0xffff;
const u32 change = (sCycle - counters[i].sCycleT) / counters[i].rate;
counters[i].sCycleT = sCycle - ((sCycle - counters[i].sCycleT) - (change * counters[i].rate));
EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", i, EECNT_LOG("EE Counter[%d] %s StartGate Type%d, count = %x", i,
isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count); isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count);
}
break; break;
} }
} }
@ -858,10 +862,14 @@ static __fi void rcntEndGate(bool isVblank, u32 sCycle)
case 0x2: // Reset on Vsync end case 0x2: // Reset on Vsync end
case 0x3: // Reset on Vsync start and end case 0x3: // Reset on Vsync start and end
{
EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", i, EECNT_LOG("EE Counter[%d] %s EndGate Type%d, count = %x", i,
isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count); isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count);
counters[i].count = 0; counters[i].count = 0;
counters[i].target &= 0xffff; counters[i].target &= 0xffff;
const u32 change = (sCycle - counters[i].sCycleT) / counters[i].rate;
counters[i].sCycleT = sCycle - ((sCycle - counters[i].sCycleT) - (change * counters[i].rate));
}
break; break;
} }
} }
@ -871,14 +879,11 @@ static __fi void rcntEndGate(bool isVblank, u32 sCycle)
static __fi void rcntWmode(int index, u32 value) static __fi void rcntWmode(int index, u32 value)
{ {
if (rcntCanCount(index)) if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3)
{ {
if (counters[index].mode.ClockSource != 0x3) const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate;
{ counters[index].count += change;
const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; counters[index].sCycleT += change * counters[index].rate;
counters[index].count += change;
counters[index].sCycleT += change * counters[index].rate;
}
} }
else else
counters[index].sCycleT = cpuRegs.cycle; counters[index].sCycleT = cpuRegs.cycle;
@ -906,13 +911,10 @@ 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: // re-calculate the start cycle of the counter based on elapsed time since the last counter update:
if (rcntCanCount(index)) if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3)
{ {
if (counters[index].mode.ClockSource != 0x3) const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate;
{ counters[index].sCycleT += change * counters[index].rate;
const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate;
counters[index].sCycleT += change * counters[index].rate;
}
} }
else else
counters[index].sCycleT = cpuRegs.cycle; counters[index].sCycleT = cpuRegs.cycle;
@ -922,7 +924,7 @@ static __fi void rcntWcount(int index, u32 value)
// reset the target, and make sure we don't get a premature target. // reset the target, and make sure we don't get a premature target.
counters[index].target &= 0xffff; counters[index].target &= 0xffff;
if (counters[index].count > counters[index].target) if (counters[index].count >= counters[index].target)
counters[index].target |= EECNT_FUTURE_TARGET; counters[index].target |= EECNT_FUTURE_TARGET;
_rcntSet(index); _rcntSet(index);
@ -938,15 +940,14 @@ static __fi void rcntWtarget(int index, u32 value)
// If the target is behind the current count, set it up so that the counter must // If the target is behind the current count, set it up so that the counter must
// overflow first before the target fires: // overflow first before the target fires:
if (rcntCanCount(index)) if (rcntCanCount(index) && counters[index].mode.ClockSource != 0x3)
{ {
if (counters[index].mode.ClockSource != 0x3) const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate;
{ counters[index].count += change;
const u32 change = (cpuRegs.cycle - counters[index].sCycleT) / counters[index].rate; counters[index].sCycleT += change * counters[index].rate;
counters[index].count += change;
counters[index].sCycleT += change * counters[index].rate;
}
} }
else
counters[index].sCycleT = cpuRegs.cycle;
if (counters[index].target <= counters[index].count) if (counters[index].target <= counters[index].count)
counters[index].target |= EECNT_FUTURE_TARGET; counters[index].target |= EECNT_FUTURE_TARGET;
@ -972,7 +973,7 @@ __fi u32 rcntRcount(int index)
// Spams the Console. // Spams the Console.
EECNT_LOG("EE Counter[%d] readCount32 = %x", index, ret); EECNT_LOG("EE Counter[%d] readCount32 = %x", index, ret);
return ret; return (u16)ret;
} }
template <uint page> template <uint page>

View File

@ -524,7 +524,8 @@ void psxRcntWcount16(int index, u16 value)
const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate;
psxCounters[index].sCycleT += change * psxCounters[index].rate; psxCounters[index].sCycleT += change * psxCounters[index].rate;
} }
else
psxCounters[index].sCycleT = psxRegs.cycle;
psxCounters[index].count = value & 0xffff; psxCounters[index].count = value & 0xffff;
psxCounters[index].target &= 0xffff; psxCounters[index].target &= 0xffff;
@ -554,7 +555,8 @@ void psxRcntWcount32(int index, u32 value)
const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate; const u32 change = (psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate;
psxCounters[index].sCycleT += change * psxCounters[index].rate; psxCounters[index].sCycleT += change * psxCounters[index].rate;
} }
else
psxCounters[index].sCycleT = psxRegs.cycle;
psxCounters[index].count = value; psxCounters[index].count = value;
psxCounters[index].target &= 0xffffffff; psxCounters[index].target &= 0xffffffff;
@ -752,6 +754,8 @@ void psxRcntWtarget16(int index, u32 value)
psxCounters[index].count += change; psxCounters[index].count += change;
psxCounters[index].sCycleT += change * psxCounters[index].rate; psxCounters[index].sCycleT += change * psxCounters[index].rate;
} }
else
psxCounters[index].sCycleT = psxRegs.cycle;
// protect the target from an early arrival. // protect the target from an early arrival.
// if the target is behind the current count, then set the target overflow // if the target is behind the current count, then set the target overflow
@ -786,6 +790,8 @@ void psxRcntWtarget32(int index, u32 value)
psxCounters[index].count += change; psxCounters[index].count += change;
psxCounters[index].sCycleT += change * psxCounters[index].rate; psxCounters[index].sCycleT += change * psxCounters[index].rate;
} }
else
psxCounters[index].sCycleT = psxRegs.cycle;
// protect the target from an early arrival. // protect the target from an early arrival.
// if the target is behind the current count, then set the target overflow // 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. // flag, so that the target won't be active until after the next overflow.