- Better IOP synchronization when using the X2 and X3 IOP hacks. Still not perfect, though (music may run a little behind or ahead of the games). I'll look into it tomorrow first thing.

- IOP Counter optimizations.  The IOP counter code now only updates counters actually being modified instead of blindly updating all counters.

git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@259 a6443dda-0b58-4228-96e9-037be469359c
This commit is contained in:
Jake.Stine 2008-10-31 20:32:12 +00:00 committed by Gregory Hainaut
parent 1bd9f54c9b
commit cd653603e5
5 changed files with 73 additions and 62 deletions

View File

@ -48,54 +48,58 @@ static void psxRcntReset32(u32 index) {
psxRcntUpd32(index); psxRcntUpd32(index);
} }
static void psxRcntSet() { __forceinline static void _rcntSet( int i, int bitwise )
{
// thanks to being forceinline'd, this conditional will always be optimized
// to a constant by VC (confirmed via disassembler):
u64 overflowCap = (bitwise==32) ? 0x100000000 : 0x10000;
u64 c; u64 c;
#ifdef _DEBUG
if(bitwise == 32)
assert( (i < 6) && (i >= 3) );
else
assert( i < 3 );
#endif
if(psxCounters[i].rate == PSXHBLANK) return;
c = (u64)((overflowCap - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) psxNextCounter = (u32)c;
//if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue;
c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) psxNextCounter = (u32)c;
}
static void psxRcntSet() {
int i; int i;
psxNextCounter = 0xffffffff; psxNextCounter = 0xffffffff;
psxNextsCounter = psxRegs.cycle; psxNextsCounter = psxRegs.cycle;
for (i=0; i<3; i++) { for (i=0; i<3; i++) {
if(psxCounters[i].rate == PSXHBLANK) continue; _rcntSet( i, 16 );
c = (u64)((0x10000 - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) {
psxNextCounter = (u32)c;
}
//if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue;
c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) {
psxNextCounter = (u32)c;
}
} }
for (i=3; i<6; i++) { for (i=3; i<6; i++) {
if(psxCounters[i].rate == PSXHBLANK) continue; _rcntSet( i, 32 );
c = (u64)((0x100000000 - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) {
psxNextCounter = (u32)c;
}
//if((psxCounters[i].mode & 0x10) == 0 || psxCounters[i].target > 0xffffffff) continue;
c = (u64)((psxCounters[i].target - psxCounters[i].count) * psxCounters[i].rate) - (psxRegs.cycle - psxCounters[i].sCycleT);
if (c < psxNextCounter) {
psxNextCounter = (u32)c;
}
} }
if(SPU2async) if(SPU2async)
{ {
c = (u32)(psxCounters[6].CycleT - (psxRegs.cycle - psxCounters[6].sCycleT)) ; u32 c = (psxCounters[6].CycleT - (psxRegs.cycle - psxCounters[6].sCycleT)) ;
if (c < psxNextCounter) { if (c < psxNextCounter) {
psxNextCounter = (u32)c; psxNextCounter = c;
} }
} }
if(USBasync) if(USBasync)
{ {
c = (u32)(psxCounters[7].CycleT - (psxRegs.cycle - psxCounters[7].sCycleT)) ; u32 c = (psxCounters[7].CycleT - (psxRegs.cycle - psxCounters[7].sCycleT)) ;
if (c < psxNextCounter) { if (c < psxNextCounter) {
psxNextCounter = (u32)c; psxNextCounter = c;
} }
} }
} }
@ -223,9 +227,10 @@ void psxCheckStartGate(int counter) { //Check Gate events when Vsync Starts
psxCounters[6].sCycleT = psxRegs.cycle; psxCounters[6].sCycleT = psxRegs.cycle;
}*/ }*/
} }
if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate
if(counter < 3){ //Gates for 16bit counters if(counter < 3){ //Gates for 16bit counters
if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate
//SysPrintf("PSX Gate %x\n", i); //SysPrintf("PSX Gate %x\n", i);
switch((psxCounters[i].mode & 0x6) >> 1) { switch((psxCounters[i].mode & 0x6) >> 1) {
case 0x0: //GATE_ON_count case 0x0: //GATE_ON_count
@ -250,7 +255,6 @@ void psxCheckStartGate(int counter) { //Check Gate events when Vsync Starts
} }
if(counter >= 3){ //Gates for 32bit counters if(counter >= 3){ //Gates for 32bit counters
if((psxCounters[i].mode & 0x1) == 0) return; //Ignore Gate
//SysPrintf("PSX Gate %x\n", i); //SysPrintf("PSX Gate %x\n", i);
switch((psxCounters[i].mode & 0x6) >> 1) { switch((psxCounters[i].mode & 0x6) >> 1) {
case 0x0: //GATE_ON_count case 0x0: //GATE_ON_count
@ -411,7 +415,6 @@ void _testRcnt32(int i) {
} }
extern int spu2interrupts[2];
void psxRcntUpdate() { void psxRcntUpdate() {
int i; int i;
u32 change = 0; u32 change = 0;
@ -440,13 +443,14 @@ void psxRcntUpdate() {
if(SPU2async) if(SPU2async)
{ {
if((psxRegs.cycle - psxCounters[6].sCycleT) >= psxCounters[6].CycleT){ if((psxRegs.cycle - psxCounters[6].sCycleT) >= psxCounters[6].CycleT)
SPU2async(psxRegs.cycle - psxCounters[6].sCycleT); {
//SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT); SPU2async(psxRegs.cycle - psxCounters[6].sCycleT);
psxCounters[6].sCycleT = psxRegs.cycle; //SysPrintf("cycles sent to SPU2 %x\n", psxRegs.cycle - psxCounters[6].sCycleT);
psxCounters[6].CycleT = ((Config.Hacks & 0x4) ? 768 : 9216); psxCounters[6].sCycleT = psxRegs.cycle;
} psxCounters[6].CycleT = ((Config.Hacks & 0x4) ? 768 : 9216);
}
} }
if(USBasync) if(USBasync)
@ -480,7 +484,7 @@ void psxRcntWcount16(int index, u32 value) {
} }
if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 16 IOP\n"); if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 16 IOP\n");
psxRcntUpd16(index); psxRcntUpd16(index);
psxRcntSet(); _rcntSet( index, 16 );
} }
void psxRcntWcount32(int index, u32 value) { void psxRcntWcount32(int index, u32 value) {
@ -503,7 +507,7 @@ void psxRcntWcount32(int index, u32 value) {
} }
if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 32 IOP\n"); if(psxCounters[index].rate == PSXHBLANK)SysPrintf("Whoops 32 IOP\n");
//psxRcntUpd32(index); //psxRcntUpd32(index);
psxRcntSet(); _rcntSet( index, 32 );
} }
void psxRcnt0Wmode(u32 value) { void psxRcnt0Wmode(u32 value) {
@ -511,9 +515,11 @@ void psxRcnt0Wmode(u32 value) {
PSXCNT_LOG("IOP writeCmode[0] = %lx\n", value); PSXCNT_LOG("IOP writeCmode[0] = %lx\n", value);
#endif #endif
#if 0
if (value & 0x1c00) { if (value & 0x1c00) {
SysPrintf("Counter 0 Value write %x\n", value & 0x1c00); SysPrintf("Counter 0 Value write %x\n", value & 0x1c00);
} }
#endif
psxCounters[0].mode = value; psxCounters[0].mode = value;
psxCounters[0].mode|= 0x0400; psxCounters[0].mode|= 0x0400;
@ -537,7 +543,7 @@ void psxRcnt0Wmode(u32 value) {
//SysPrintf("IOP 16 Correcting target 0 after mode write\n"); //SysPrintf("IOP 16 Correcting target 0 after mode write\n");
psxCounters[0].target &= 0xffff; psxCounters[0].target &= 0xffff;
} }
psxRcntSet(); _rcntSet( 0, 16 );
//} //}
} }
@ -572,7 +578,7 @@ void psxRcnt1Wmode(u32 value) {
//SysPrintf("IOP 16 Correcting target 1 after mode write\n"); //SysPrintf("IOP 16 Correcting target 1 after mode write\n");
psxCounters[1].target &= 0xffff; psxCounters[1].target &= 0xffff;
} }
psxRcntSet(); _rcntSet( 1, 16 );
//} //}
} }
@ -610,7 +616,7 @@ void psxRcnt2Wmode(u32 value) {
//SysPrintf("IOP 16 Correcting target 2 after mode write\n"); //SysPrintf("IOP 16 Correcting target 2 after mode write\n");
psxCounters[2].target &= 0xffff; psxCounters[2].target &= 0xffff;
} }
psxRcntSet(); _rcntSet( 2, 16 );
} }
void psxRcnt3Wmode(u32 value) { void psxRcnt3Wmode(u32 value) {
@ -644,7 +650,7 @@ void psxRcnt3Wmode(u32 value) {
//SysPrintf("IOP 32 Correcting target 3 after mode write\n"); //SysPrintf("IOP 32 Correcting target 3 after mode write\n");
psxCounters[3].target &= 0xffffffff; psxCounters[3].target &= 0xffffffff;
} }
psxRcntSet(); _rcntSet( 3, 32 );
//} //}
} }
@ -689,7 +695,7 @@ void psxRcnt4Wmode(u32 value) {
//SysPrintf("IOP 32 Correcting target 4 after mode write\n"); //SysPrintf("IOP 32 Correcting target 4 after mode write\n");
psxCounters[4].target &= 0xffffffff; psxCounters[4].target &= 0xffffffff;
} }
psxRcntSet(); _rcntSet( 4, 32 );
} }
void psxRcnt5Wmode(u32 value) { void psxRcnt5Wmode(u32 value) {
@ -733,7 +739,7 @@ void psxRcnt5Wmode(u32 value) {
//SysPrintf("IOP 32 Correcting target 5 after mode write\n"); //SysPrintf("IOP 32 Correcting target 5 after mode write\n");
psxCounters[5].target &= 0xffffffff; psxCounters[5].target &= 0xffffffff;
} }
psxRcntSet(); _rcntSet( 5, 32 );
} }
void psxRcntWtarget16(int index, u32 value) { void psxRcntWtarget16(int index, u32 value) {
@ -746,7 +752,7 @@ void psxRcntWtarget16(int index, u32 value) {
psxCounters[index].target += 0x1000000000; psxCounters[index].target += 0x1000000000;
} }
psxRcntSet(); _rcntSet( index, 16 );
} }
void psxRcntWtarget32(int index, u32 value) { void psxRcntWtarget32(int index, u32 value) {
@ -761,7 +767,7 @@ void psxRcntWtarget32(int index, u32 value) {
psxCounters[index].target += 0x1000000000; psxCounters[index].target += 0x1000000000;
} }
psxRcntSet(); _rcntSet( index, 32 );
} }
u16 psxRcntRcount16(int index) { u16 psxRcntRcount16(int index) {

View File

@ -25,7 +25,6 @@
// Dma8 in PsxSpd.c // Dma8 in PsxSpd.c
// Dma11/12 in PsxSio2.c // Dma11/12 in PsxSio2.c
//static int spudmaenable[2]; //static int spudmaenable[2];
int spu2interrupts[2];
int iopsifbusy[2] = { 0, 0 }; int iopsifbusy[2] = { 0, 0 };
void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU
int size; int size;

View File

@ -161,13 +161,16 @@ static void _psxTestInterrupts() {
PSX_TESTINT(21, usbInterrupt); PSX_TESTINT(21, usbInterrupt);
} }
#define IOP_WAIT_CYCLE 256 // was (and is again!) 64 // Higher Wait cycle values should, in theory, reduce IOP overhead without much
// drawback. The IOP is almost always forced to perform branch tests at import-
// ant intervals regardless of this value (such as counter or irq events, hsyncs,
// etc.)
#define IOP_WAIT_CYCLE 256
void psxBranchTest() void psxBranchTest()
{ {
// g_psxNextBranchCycle is initialized for us by iPsxBranchTest.
g_psxNextBranchCycle = psxRegs.cycle; g_psxNextBranchCycle = psxRegs.cycle;
if( EEsCycle >= 0 ) g_psxNextBranchCycle += IOP_WAIT_CYCLE; //if( EEsCycle >= 0 ) g_psxNextBranchCycle += IOP_WAIT_CYCLE;
if ((int)(psxRegs.cycle - psxNextsCounter) >= psxNextCounter) if ((int)(psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
psxRcntUpdate(); psxRcntUpdate();

View File

@ -435,6 +435,12 @@ void cpuBranchTest()
//#endif //#endif
_cpuTestTIMR(); _cpuTestTIMR();
// Signal for an immediate branch test! This is important! The IOP must
// be able to act on the state the EE has given it before executing any
// additional code. Otherwise things won't be anywhere near "in sync."
psxBranchTest();
EEsCycle += cpuRegs.cycle - EEoCycle; EEsCycle += cpuRegs.cycle - EEoCycle;
EEoCycle = cpuRegs.cycle; EEoCycle = cpuRegs.cycle;

View File

@ -987,19 +987,16 @@ static void iPsxBranchTest(u32 newpc, u32 cpuBranch)
MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles MOV32RtoM((uptr)&psxRegs.cycle, ECX); // update cycles
} }
else { else {
SUB32ItoM((uptr)&EEsCycle, s_psxBlockCycles*PSXCYCLE_MULT*8); // 8 EE clocks for every IOP clock. SUB32ItoM((uptr)&EEsCycle, ((u32)(s_psxBlockCycles*PSXCYCLE_MULT))*8); // 8 EE clocks for every IOP clock.
ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles*PSXCYCLE_MULT); ADD32ItoM((uptr)&psxRegs.cycle, s_psxBlockCycles*PSXCYCLE_MULT);
return; return;
} }
// check if we've caught up with the EE // check if we've caught up with the EE
SUB32ItoM((uptr)&EEsCycle, s_psxBlockCycles*PSXCYCLE_MULT*8); // 8 EE clocks for every IOP clock. SUB32ItoM((uptr)&EEsCycle, ((u32)(s_psxBlockCycles*PSXCYCLE_MULT))*8); // 8 EE clocks for every IOP clock.
j8Ptr[2] = JGE8(0); j8Ptr[2] = JGE8(0);
// Break the Block-execute Loop here. // Break the Block-execute Loop here.
// (but not without running another branch test! And do it regardless
// because the EE needs at least one IOP branch test or else bad things happen)
CALLFunc((uptr)psxBranchTest);
if( REC_INC_STACK ) if( REC_INC_STACK )
ADD64ItoR(ESP, REC_INC_STACK); ADD64ItoR(ESP, REC_INC_STACK);