mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
0bcb9cc0e3
commit
dc3d9f4bfc
106
pcsx2/COP0.cpp
106
pcsx2/COP0.cpp
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue