Added preliminary support for the Gekko CPU Performance Monitor. Fixes Harry Potter and the Prisoner of Azkaban.

This commit is contained in:
skidau 2012-04-28 20:42:45 +10:00
parent 75fbbcae40
commit cdace9d776
7 changed files with 175 additions and 25 deletions

View File

@ -493,7 +493,41 @@ union UReg_SPR1
}; };
}; };
// MMCR0 - Monitor Mode Control Register 0 format
union UReg_MMCR0
{
u32 Hex;
struct
{
u32 PMC2SELECT : 6;
u32 PMC1SELECT : 7;
u32 PMCTRIGGER : 1;
u32 PMCINTCONTROL : 1;
u32 PMC1INTCONTROL : 1;
u32 THRESHOLD : 6;
u32 INTONBITTRANS : 1;
u32 RTCSELECT : 2;
u32 DISCOUNT : 1;
u32 ENINT : 1;
u32 DMR : 1;
u32 DMS : 1;
u32 DU : 1;
u32 DP : 1;
u32 DIS : 1;
};
};
// MMCR1 - Monitor Mode Control Register 1 format
union UReg_MMCR1
{
u32 Hex;
struct
{
u32 : 22;
u32 PMC4SELECT : 5;
u32 PMC3SELECT : 5;
};
};
// Write Pipe Address Register // Write Pipe Address Register
union UReg_WPAR union UReg_WPAR
@ -669,7 +703,17 @@ enum
SPR_ECID_U = 924, SPR_ECID_U = 924,
SPR_ECID_M = 925, SPR_ECID_M = 925,
SPR_ECID_L = 926, SPR_ECID_L = 926,
SPR_L2CR = 1017 SPR_L2CR = 1017,
SPR_UMMCR0 = 936,
SPR_MMCR0 = 952,
SPR_PMC1 = 953,
SPR_PMC2 = 954,
SPR_UMMCR1 = 940,
SPR_MMCR1 = 956,
SPR_PMC3 = 957,
SPR_PMC4 = 958,
}; };
// Exceptions // Exceptions
@ -681,6 +725,7 @@ enum
#define EXCEPTION_ALIGNMENT 0x00000020 #define EXCEPTION_ALIGNMENT 0x00000020
#define EXCEPTION_FPU_UNAVAILABLE 0x00000040 #define EXCEPTION_FPU_UNAVAILABLE 0x00000040
#define EXCEPTION_PROGRAM 0x00000080 #define EXCEPTION_PROGRAM 0x00000080
#define EXCEPTION_PERFORMANCE_MONITOR 0x00000100
inline s32 SignExt16(s16 x) {return (s32)(s16)x;} inline s32 SignExt16(s16 x) {return (s32)(s16)x;}
inline s32 SignExt26(u32 x) {return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);} inline s32 SignExt26(u32 x) {return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);}

View File

@ -295,6 +295,11 @@ void Jit64::Cleanup()
{ {
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe); ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
CMP(32, M(&MMCR0), Imm32(0));
FixupBranch mmcr0 = J_CC(CC_Z);
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
SetJumpTarget(mmcr0);
} }
void Jit64::WriteExit(u32 destination, int exit_num) void Jit64::WriteExit(u32 destination, int exit_num)
@ -654,6 +659,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
WriteExceptionExit(); WriteExceptionExit();
SetJumpTarget(noMemException); SetJumpTarget(noMemException);
} }
if (opinfo->flags & FL_LOADSTORE)
++jit->js.numLoadStoreInst;
if (opinfo->flags & FL_USE_FPU)
++jit->js.numFloatingPointInst;
} }
#if defined(_DEBUG) || defined(DEBUGFAST) #if defined(_DEBUG) || defined(DEBUGFAST)

View File

@ -93,6 +93,10 @@ void Jit64::mfspr(UGeckoInstruction inst)
case SPR_DEC: case SPR_DEC:
case SPR_TL: case SPR_TL:
case SPR_TU: case SPR_TU:
case SPR_PMC1:
case SPR_PMC2:
case SPR_PMC3:
case SPR_PMC4:
Default(inst); Default(inst);
return; return;
default: default:

View File

@ -390,6 +390,11 @@ void JitIL::Cleanup()
{ {
if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0)
ABI_CallFunction((void *)&GPFifo::CheckGatherPipe); ABI_CallFunction((void *)&GPFifo::CheckGatherPipe);
CMP(32, M(&MMCR0), Imm32(0));
FixupBranch mmcr0 = J_CC(CC_Z);
ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst);
SetJumpTarget(mmcr0);
} }
void JitIL::WriteExit(u32 destination, int exit_num) void JitIL::WriteExit(u32 destination, int exit_num)
@ -666,6 +671,12 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{ {
ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address)); ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address));
} }
if (opinfo->flags & FL_LOADSTORE)
++jit->js.numLoadStoreInst;
if (opinfo->flags & FL_USE_FPU)
++jit->js.numFloatingPointInst;
} }
} }

View File

@ -57,6 +57,8 @@ protected:
int blockSize; int blockSize;
int instructionNumber; int instructionNumber;
int downcountAmount; int downcountAmount;
u32 numLoadStoreInst;
u32 numFloatingPointInst;
bool firstFPInstructionFound; bool firstFPInstructionFound;
bool isLastInstruction; bool isLastInstruction;

View File

@ -289,6 +289,68 @@ void Stop()
Host_UpdateDisasmDialog(); Host_UpdateDisasmDialog();
} }
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst)
{
switch (MMCR0.PMC1SELECT)
{
case 0: // No change
break;
case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC1] += cycles;
break;
default:
break;
}
switch (MMCR0.PMC2SELECT)
{
case 0: // No change
break;
case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC2] += cycles;
break;
case 11: // Number of loads and stores completed
PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores;
break;
default:
break;
}
switch (MMCR1.PMC3SELECT)
{
case 0: // No change
break;
case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC3] += cycles;
break;
case 11: // Number of FPU instructions completed
PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst;
break;
default:
break;
}
switch (MMCR1.PMC4SELECT)
{
case 0: // No change
break;
case 1: // Processor cycles
PowerPC::ppcState.spr[SPR_PMC4] += cycles;
break;
default:
break;
}
if (MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 80000000) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
if (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 80000000) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
if (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 80000000) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
if (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 80000000) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR;
}
void CheckExceptions() void CheckExceptions()
{ {
// Make sure we are checking against the latest EXI status. This is required // Make sure we are checking against the latest EXI status. This is required
@ -453,6 +515,17 @@ void CheckExternalExceptions()
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
} }
else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR)
{
SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36;
NPC = 0x80000F00;
INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PERFORMANCE_MONITOR);
}
else if (exceptions & EXCEPTION_DECREMENTER) else if (exceptions & EXCEPTION_DECREMENTER)
{ {
SRR0 = NPC; SRR0 = NPC;

View File

@ -117,12 +117,16 @@ void ExpandCR();
void OnIdle(u32 _uThreadAddr); void OnIdle(u32 _uThreadAddr);
void OnIdleIL(); void OnIdleIL();
void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst);
// Easy register access macros. // Easy register access macros.
#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0])
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
#define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4]) #define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4])
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) #define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
#define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0])
#define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1])
#define PC PowerPC::ppcState.pc #define PC PowerPC::ppcState.pc
#define NPC PowerPC::ppcState.npc #define NPC PowerPC::ppcState.npc
#define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr) #define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr)