Fixed the bug in r740 that broke speedhacks; and improved the PERF support a bit more using bitfields and more correct mode tests.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@745 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-03-11 07:40:23 +00:00
parent 0bcb9cc0e3
commit dc3d9f4bfc
6 changed files with 115 additions and 78 deletions

View File

@ -145,59 +145,104 @@ void WriteTLB(int i)
}
//////////////////////////////////////////////////////////////////////////////////////////
// Performance Counters Update Stuff!
//
// Note regarding updates of PERF and TIMR registers: never allow increment to be 0.
// That happens when a game loads the MFC0 twice in the same recompiled block (before the
// cpuRegs.cycles update), and can cause games to lock up since it's an unexpected result.
//
// PERF Overflow exceptions: The exception is raised when the MSB of the Performance
// Counter Register is set (basic arithmetic overflow, which means it does *not* include
// when the bit is later cleared).
// Counter Register is set. I'm assuming the exception continues to re-raise until the
// app clears the bit manually (needs testing).
//
// PERF Events:
// * Event 0 on PCR 0 is unused (counter disable)
// * Event 15 is usable as a specific counter disable bit (since CTE affects both counters)
// * Events 16-31 are reserved (act as counter disable)
//
// Most event mode aren't supported, and issue a warning and do a standard instruction
// count. But only mode 1 (instruction counter) has been found to be used by games thus far.
//
__forceinline void COP0_UpdatePCR0()
__forceinline void COP0_UpdatePCR()
{
if((cpuRegs.PERF.n.pccr & 0x800003E0) == 0x80000020)
if( cpuRegs.CP0.n.Status.b.ERL || !cpuRegs.PERF.n.pccr.b.CTE ) return;
// TODO : Implement memory mode checks here (kernel/super/user)
// For now we just assume user mode.
if( cpuRegs.PERF.n.pccr.b.U0 && (cpuRegs.PERF.n.pccr.b.Event0 != 0 && cpuRegs.PERF.n.pccr.b.Event0 < 15) )
{
u32 incr = cpuRegs.cycle-s_iLastPERFCycle[0];
// ----------------------------------
// Update Performance Counter 0
// ----------------------------------
if( cpuRegs.PERF.n.pccr.b.Event0 != 1 )
Console::Notice( "COP0 - PCR0 Unsupported Update Event Mode = 0x%x", params cpuRegs.PERF.n.pccr.b.Event0 );
u32 incr = cpuRegs.cycle - s_iLastPERFCycle[0];
if( incr == 0 ) incr++;
u32 prev = cpuRegs.PERF.n.pcr0;
// use prev/XOR method for one-time exceptions (but likely less correct)
//u32 prev = cpuRegs.PERF.n.pcr0;
cpuRegs.PERF.n.pcr0 += incr;
s_iLastPERFCycle[0] = cpuRegs.cycle;
if( cpuRegs.PERF.n.pccr & (1UL<<31) ) // MSB is the overflow enable bit.
//prev ^= (1UL<<31); // XOR is fun!
//if( (prev & cpuRegs.PERF.n.pcr0) & (1UL<<31) )
if( cpuRegs.PERF.n.pcr0 & 0x80000000 )
{
prev ^= (1UL<<31); // XOR is fun!
if( (prev & cpuRegs.PERF.n.pcr0) & (1UL<<31) )
// TODO: Vector to the appropriate exception here.
// This code *should* be correct, but is untested (and other parts of the emu are
// not prepared to handle proper Level 2 exception vectors yet)
/*if( delay_slot )
{
// TODO: Vector to the appropriate exception here.
cpuRegs.CP0.ErrorEPC = cpuRegs.pc - 4;
cpuRegs.CP0.Cause.BD2 = 1;
}
else
{
cpuRegs.CP0.ErrorEPC = cpuRegs.pc;
cpuRegs.CP0.Cause.BD2 = 0;
}
if( cpuRegs.CP0.Status.DEV )
{
// Bootstrap vector
cpuRegs.pc = 0xbfc00280;
}
else
{
cpuRegs.pc = 0x80000080;
}
cpuRegs.CP0.Status.ERL = 1;
cpuRegs.CP0.Cause.EXC2 = 2;*/
}
}
}
__forceinline void COP0_UpdatePCR1()
{
if((cpuRegs.PERF.n.pccr & 0x800F8000) == 0x80008000)
if( cpuRegs.PERF.n.pccr.b.U1 && cpuRegs.PERF.n.pccr.b.Event1 < 15)
{
u32 incr = cpuRegs.cycle-s_iLastPERFCycle[1];
// ----------------------------------
// Update Performance Counter 1
// ----------------------------------
if( cpuRegs.PERF.n.pccr.b.Event1 != 1 )
Console::Notice( "COP0 - PCR1 Unsupported Update Event Mode = 0x%x", params cpuRegs.PERF.n.pccr.b.Event1 );
u32 incr = cpuRegs.cycle - s_iLastPERFCycle[1];
if( incr == 0 ) incr++;
u32 prev = cpuRegs.PERF.n.pcr1;
cpuRegs.PERF.n.pcr1 += incr;
s_iLastPERFCycle[1] = cpuRegs.cycle;
if( cpuRegs.PERF.n.pccr & (1UL<<31) ) // MSB is the overflow enable bit.
if( cpuRegs.PERF.n.pcr1 & 0x80000000 )
{
prev ^= (1UL<<31); // XOR? I don't even know OR! Harhar!
if( (prev & cpuRegs.PERF.n.pcr1) & (1UL<<31) )
{
// TODO: Vector to the appropriate exception here.
}
// See PCR0 comments for notes on exceptions
}
}
}
namespace R5900 {
namespace Interpreter {
namespace OpcodeImpl {
@ -221,16 +266,16 @@ void MFC0()
switch(_Imm_ & 0x3F)
{
case 0: // MFPS [LSB is clear]
cpuRegs.GPR.r[_Rt_].SD[0] = (s32)cpuRegs.PERF.n.pccr;
cpuRegs.GPR.r[_Rt_].SD[0] = (s32)cpuRegs.PERF.n.pccr.val;
break;
case 1: // MFPC [LSB is set] - read PCR0
COP0_UpdatePCR0();
COP0_UpdatePCR();
cpuRegs.GPR.r[_Rt_].SD[0] = (s32)cpuRegs.PERF.n.pcr0;
break;
case 3: // MFPC [LSB is set] - read PCR1
COP0_UpdatePCR1();
COP0_UpdatePCR();
cpuRegs.GPR.r[_Rt_].SD[0] = (s32)cpuRegs.PERF.n.pcr1;
break;
}
@ -269,9 +314,8 @@ void MTC0()
{
case 0: // MTPS [LSB is clear]
// Updates PCRs and sets the PCCR.
COP0_UpdatePCR0();
COP0_UpdatePCR1();
cpuRegs.PERF.n.pccr = cpuRegs.GPR.r[_Rt_].UL[0];
COP0_UpdatePCR();
cpuRegs.PERF.n.pccr.val = cpuRegs.GPR.r[_Rt_].UL[0];
break;
case 1: // MTPC [LSB is set] - set PCR0

View File

@ -25,8 +25,7 @@ extern void WriteTLB(int i);
extern void UnmapTLB(int i);
extern void MapTLB(int i);
extern void COP0_UpdatePCR0();
extern void COP0_UpdatePCR1();
extern void COP0_UpdatePCR();
#endif /* __COP0_H__ */

View File

@ -392,8 +392,7 @@ static __forceinline void _cpuTestPERF()
// around twice on us btween updates. Hence this function is called from the cpu's
// Counters update.
COP0_UpdatePCR0();
COP0_UpdatePCR1();
COP0_UpdatePCR();
}
// Checks the COP0.Status for exception enablings.

View File

@ -52,8 +52,35 @@ union GPRregs {
};
union PERFregs {
struct {
u32 pccr, pcr0, pcr1, pad;
struct
{
union
{
struct
{
u32 pad0:1; // LSB should always be zero (or undefined)
u32 EXL0:1; // enable PCR0 during Level 1 exception handling
u32 K0:1; // enable PCR0 during Kernel Mode execution
u32 S0:1; // enable PCR0 during Supervisor mode execution
u32 U0:1; // enable PCR0 during User-mode execution
u32 Event0:5; // PCR0 event counter (all values except 1 ignored at this time)
u32 pad1:1; // more zero/undefined padding [bit 10]
u32 EXL1:1; // enable PCR1 during Level 1 exception handling
u32 K1:1; // enable PCR1 during Kernel Mode execution
u32 S1:1; // enable PCR1 during Supervisor mode execution
u32 U1:1; // enable PCR1 during User-mode execution
u32 Event1:5; // PCR1 event counter (all values except 1 ignored at this time)
u32 Reserved:11;
u32 CTE:1; // Counter enable bit, no counting if set to zero.
} b;
u32 val;
} pccr;
u32 pcr0, pcr1, pad;
} n;
u32 r[4];
};

View File

@ -162,44 +162,13 @@ void recMFC0( void )
{
case 0:
MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pccr);
break;
break;
case 1:
/*MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr);
MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr0);
AND32ItoR(ECX, 0x800003E0);
CMP32ItoR(ECX, 0x80000020);
j8Ptr[0] = JNE8(0);
MOV32MtoR(EDX, (uptr)&cpuRegs.cycle);
SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[0]);
ADD32RtoR(EAX, EDX);
MOV32RtoM((uptr)&s_iLastPERFCycle[0], EDX);
MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr0, EAX);
x86SetJ8(j8Ptr[0]);*/
CALLFunc( (uptr)COP0_UpdatePCR0 );
break;
case 3:
/*MOV32MtoR(ECX, (uptr)&cpuRegs.PERF.n.pccr);
MOV32MtoR(EAX, (uptr)&cpuRegs.PERF.n.pcr1);
AND32ItoR(ECX, 0x800F8000);
CMP32ItoR(ECX, 0x80008000);
j8Ptr[0] = JNE8(0);
MOV32MtoR(EDX, (uptr)&cpuRegs.cycle);
SUB32MtoR(EAX, (uptr)&s_iLastPERFCycle[1]);
ADD32RtoR(EAX, EDX);
MOV32RtoM((uptr)&s_iLastPERFCycle[1], EDX);
MOV32RtoM((uptr)&cpuRegs.PERF.n.pcr1, EAX);
x86SetJ8(j8Ptr[0]);*/
CALLFunc( (uptr)COP0_UpdatePCR1 );
break;
CALLFunc( (uptr)COP0_UpdatePCR );
CALLFunc( (uptr)COP0_UpdatePCR );
break;
}
_deleteEEreg(_Rt_, 0);
MOV32RtoM((uptr)&cpuRegs.GPR.r[_Rt_].UL[0],EAX);
@ -308,8 +277,7 @@ void recMTC0()
switch(_Imm_ & 0x3F)
{
case 0:
CALLFunc( (uptr)COP0_UpdatePCR0 );
CALLFunc( (uptr)COP0_UpdatePCR1 );
CALLFunc( (uptr)COP0_UpdatePCR );
MOV32ItoM((uptr)&cpuRegs.PERF.n.pccr, g_cpuConstRegs[_Rt_].UL[0]);
break;
@ -356,8 +324,7 @@ void recMTC0()
switch(_Imm_ & 0x3F)
{
case 0:
CALLFunc( (uptr)COP0_UpdatePCR0 );
CALLFunc( (uptr)COP0_UpdatePCR1 );
CALLFunc( (uptr)COP0_UpdatePCR );
_eeMoveGPRtoM((uptr)&cpuRegs.PERF.n.pccr, _Rt_);
break;

View File

@ -1198,9 +1198,10 @@ u32 eeScaleBlockCycles()
jNO_DEFAULT
}
const u32 temp = s_nBlockCycles *
const u32 temp = s_nBlockCycles * (
(s_nBlockCycles <= (10<<3)) ? scalarLow :
((s_nBlockCycles > (21<<3)) ? scalarHigh : scalarMid );
((s_nBlockCycles > (21<<3)) ? scalarHigh : scalarMid )
);
return temp >> (3+2);
}