Merge branch 'JIT-Exceptions'

* JIT-Exceptions:
  JitIL code cleanup
  Changed the JIT code to make the FPU exception timing more accurate.  The exception is now triggered at the first FP instruction instead of the start of the block. Rearranged the JIT exception code for a tiny speed-up.  Only external exceptions are checked at the end of the block.  All other exceptions are checked at the time they occur.

Fixes issue 5382.

Conflicts:
	Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp
This commit is contained in:
skidau 2012-05-01 20:35:12 +10:00
commit 75fbbcae40
14 changed files with 146 additions and 98 deletions

View File

@ -333,16 +333,47 @@ void Jit64::WriteExitDestInEAX()
void Jit64::WriteRfiExitDestInEAX() void Jit64::WriteRfiExitDestInEAX()
{ {
MOV(32, M(&PC), R(EAX)); MOV(32, M(&PC), R(EAX));
MOV(32, M(&NPC), R(EAX));
Cleanup(); Cleanup();
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.testExceptions, true); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, asm_routines.outerLoop, true);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
} }
void Jit64::WriteExceptionExit() void Jit64::WriteExceptionExit()
{ {
Cleanup(); Cleanup();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.testExceptions, true); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, asm_routines.outerLoop, true);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
}
void Jit64::WriteExternalExceptionExit()
{
Cleanup();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
J_CC(CC_Z, asm_routines.outerLoop, true);
//Landing pad for drec space
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
} }
void STACKALIGN Jit64::Run() void STACKALIGN Jit64::Run()
@ -421,8 +452,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (em_address == 0) if (em_address == 0)
{ {
Core::SetState(Core::CORE_PAUSE); // Memory exception occurred during instruction fetch
PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR); memory_exception = true;
} }
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT)) if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
@ -435,6 +466,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
int size = 0; int size = 0;
js.firstFPInstructionFound = false;
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = em_address; js.blockStart = em_address;
js.fifoBytesThisBlock = 0; js.fifoBytesThisBlock = 0;
@ -472,16 +504,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (ImHereDebug) if (ImHereDebug)
ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful
if (js.fpa.any)
{
// This block uses FPU - needs to add FP exception bailout
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit
FixupBranch b1 = J_CC(CC_NZ);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(asm_routines.fpException, true);
SetJumpTarget(b1);
}
// Conditionally add profiling code. // Conditionally add profiling code.
if (Profiler::g_ProfileBlocks) { if (Profiler::g_ProfileBlocks) {
ADD(32, M(&b->runCount), Imm8(1)); ADD(32, M(&b->runCount), Imm8(1));
@ -557,8 +579,11 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (!ops[i].skip) if (!ops[i].skip)
{ {
if (js.memcheck && (opinfo->flags & FL_USE_FPU)) if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound)
{ {
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
//This instruction uses FPU - needs to add FP exception bailout //This instruction uses FPU - needs to add FP exception bailout
TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
FixupBranch b1 = J_CC(CC_NZ); FixupBranch b1 = J_CC(CC_NZ);
@ -566,9 +591,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
// If a FPU exception occurs, the exception handler will read // If a FPU exception occurs, the exception handler will read
// from PC. Update PC with the latest value in case that happens. // from PC. Update PC with the latest value in case that happens.
MOV(32, M(&PC), Imm32(ops[i].address)); MOV(32, M(&PC), Imm32(ops[i].address));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
JMP(asm_routines.fpException, true); WriteExceptionExit();
SetJumpTarget(b1); SetJumpTarget(b1);
js.firstFPInstructionFound = true;
} }
// Add an external exception check if the instruction writes to the FIFO. // Add an external exception check if the instruction writes to the FIFO.
@ -577,7 +605,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
gpr.Flush(FLUSH_ALL); gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL);
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER)); TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
FixupBranch clearInt = J_CC(CC_NZ); FixupBranch clearInt = J_CC(CC_NZ);
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
FixupBranch noExtException = J_CC(CC_Z); FixupBranch noExtException = J_CC(CC_Z);
@ -587,7 +615,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
FixupBranch noCPInt = J_CC(CC_Z); FixupBranch noCPInt = J_CC(CC_Z);
MOV(32, M(&PC), Imm32(ops[i].address)); MOV(32, M(&PC), Imm32(ops[i].address));
WriteExceptionExit(); WriteExternalExceptionExit();
SetJumpTarget(noCPInt); SetJumpTarget(noCPInt);
SetJumpTarget(noExtIntEnable); SetJumpTarget(noExtIntEnable);
@ -597,14 +625,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING)
{ {
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
MOV(32, M(&PC), Imm32(ops[i].address)); MOV(32, M(&PC), Imm32(ops[i].address));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints)); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints));
TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF));
FixupBranch noBreakpoint = J_CC(CC_Z); FixupBranch noBreakpoint = J_CC(CC_Z);
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
WriteExit(ops[i].address, 0); WriteExit(ops[i].address, 0);
SetJumpTarget(noBreakpoint); SetJumpTarget(noBreakpoint);
} }
@ -636,7 +664,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst); NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst);
} }
#endif #endif
if (js.skipnext) { if (js.skipnext) {
js.skipnext = false; js.skipnext = false;
i++; // Skip next instruction i++; // Skip next instruction
@ -650,6 +677,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
MOV(32, M(&NPC), Imm32(js.compilerPC)); MOV(32, M(&NPC), Imm32(js.compilerPC));
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI)); OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI));
// Remove the invalid instruction from the icache, forcing a recompile // Remove the invalid instruction from the icache, forcing a recompile

View File

@ -65,32 +65,6 @@
class Jit64 : public JitBase class Jit64 : public JitBase
{ {
private: private:
struct JitState
{
u32 compilerPC;
u32 next_compilerPC;
u32 blockStart;
bool cancel;
bool skipnext;
UGeckoInstruction next_inst; // for easy peephole opt.
int blockSize;
int instructionNumber;
int downcountAmount;
int block_flags;
bool isLastInstruction;
bool memcheck;
int fifoBytesThisBlock;
PPCAnalyst::BlockStats st;
PPCAnalyst::BlockRegStats gpa;
PPCAnalyst::BlockRegStats fpa;
PPCAnalyst::CodeOp *op;
JitBlock *curBlock;
};
GPRRegCache gpr; GPRRegCache gpr;
FPURegCache fpr; FPURegCache fpr;
@ -103,8 +77,6 @@ public:
Jit64() : code_buffer(32000) {} Jit64() : code_buffer(32000) {}
~Jit64() {} ~Jit64() {}
JitState js;
void Init(); void Init();
void Shutdown(); void Shutdown();
@ -143,6 +115,7 @@ public:
void WriteExit(u32 destination, int exit_num); void WriteExit(u32 destination, int exit_num);
void WriteExitDestInEAX(); void WriteExitDestInEAX();
void WriteExceptionExit(); void WriteExceptionExit();
void WriteExternalExceptionExit();
void WriteRfiExitDestInEAX(); void WriteRfiExitDestInEAX();
void WriteCallInterpreter(UGeckoInstruction _inst); void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup(); void Cleanup();

View File

@ -70,7 +70,7 @@ void Jit64AsmRoutineManager::Generate()
MOV(64, R(R15), Imm64((u64)jit->GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough MOV(64, R(R15), Imm64((u64)jit->GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough
#endif #endif
const u8 *outerLoop = GetCodePtr(); outerLoop = GetCodePtr();
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance)); ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time
@ -194,24 +194,13 @@ void Jit64AsmRoutineManager::Generate()
#endif #endif
JMP(dispatcherNoCheck); // no point in special casing this JMP(dispatcherNoCheck); // no point in special casing this
//FP blocks test for FPU available, jump here if false
fpException = AlignCode4();
LOCK();
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));
JMP(dispatcher, true);
SetJumpTarget(bail); SetJumpTarget(bail);
doTiming = GetCodePtr(); doTiming = GetCodePtr();
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance)); testExternalExceptions = GetCodePtr();
testExceptions = GetCodePtr();
MOV(32, R(EAX), M(&PC)); MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX)); MOV(32, M(&NPC), R(EAX));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions));
MOV(32, R(EAX), M(&NPC)); MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX)); MOV(32, M(&PC), R(EAX));

View File

@ -151,7 +151,7 @@ void Jit64::lXXx(UGeckoInstruction inst)
// ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0 // ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0
//MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC)); //MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC));
JMP(asm_routines.testExceptions, true); WriteExceptionExit();
SetJumpTarget(noIdle); SetJumpTarget(noIdle);

View File

@ -119,6 +119,7 @@ void Jit64::mtmsr(UGeckoInstruction inst)
gpr.Flush(FLUSH_ALL); gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL);
WriteExit(js.compilerPC + 4, 0); WriteExit(js.compilerPC + 4, 0);
js.firstFPInstructionFound = false;
} }
void Jit64::mfmsr(UGeckoInstruction inst) void Jit64::mfmsr(UGeckoInstruction inst)

View File

@ -1268,8 +1268,8 @@ static const unsigned alwaysUsedList[] = {
StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8, StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8,
Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR,
BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop,
SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart, SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck,
FPExceptionCheckEnd, ISIException, ExtExceptionCheck, BreakPointCheck, DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck,
Int3, Tramp, Nop Int3, Tramp, Nop
}; };
static const unsigned extra8RegList[] = { static const unsigned extra8RegList[] = {

View File

@ -167,7 +167,7 @@ enum Opcode {
// used for exception checking, at least until someone // used for exception checking, at least until someone
// has a better idea of integrating it // has a better idea of integrating it
FPExceptionCheckStart, FPExceptionCheckEnd, FPExceptionCheck, DSIExceptionCheck,
ISIException, ExtExceptionCheck, BreakPointCheck, ISIException, ExtExceptionCheck, BreakPointCheck,
// "Opcode" representing a register too far away to // "Opcode" representing a register too far away to
// reference directly; this is a size optimization // reference directly; this is a size optimization
@ -402,11 +402,11 @@ public:
InstLoc EmitSystemCall(InstLoc pc) { InstLoc EmitSystemCall(InstLoc pc) {
return FoldUOp(SystemCall, pc); return FoldUOp(SystemCall, pc);
} }
InstLoc EmitFPExceptionCheckStart(InstLoc pc) { InstLoc EmitFPExceptionCheck(InstLoc pc) {
return EmitUOp(FPExceptionCheckStart, pc); return EmitUOp(FPExceptionCheck, pc);
} }
InstLoc EmitFPExceptionCheckEnd(InstLoc pc) { InstLoc EmitDSIExceptionCheck(InstLoc pc) {
return EmitUOp(FPExceptionCheckEnd, pc); return EmitUOp(DSIExceptionCheck, pc);
} }
InstLoc EmitISIException(InstLoc dest) { InstLoc EmitISIException(InstLoc dest) {
return EmitUOp(ISIException, dest); return EmitUOp(ISIException, dest);

View File

@ -759,8 +759,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
case RFIExit: case RFIExit:
case InterpreterBranch: case InterpreterBranch:
case ShortIdleLoop: case ShortIdleLoop:
case FPExceptionCheckStart: case FPExceptionCheck:
case FPExceptionCheckEnd: case DSIExceptionCheck:
case ISIException: case ISIException:
case ExtExceptionCheck: case ExtExceptionCheck:
case BreakPointCheck: case BreakPointCheck:
@ -1869,7 +1869,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->WriteRfiExitDestInOpArg(R(EAX)); Jit->WriteRfiExitDestInOpArg(R(EAX));
break; break;
} }
case FPExceptionCheckStart: { case FPExceptionCheck: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
//This instruction uses FPU - needs to add FP exception bailout //This instruction uses FPU - needs to add FP exception bailout
Jit->TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit Jit->TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
@ -1883,7 +1883,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->SetJumpTarget(b1); Jit->SetJumpTarget(b1);
break; break;
} }
case FPExceptionCheckEnd: { case DSIExceptionCheck: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
FixupBranch noMemException = Jit->J_CC(CC_Z); FixupBranch noMemException = Jit->J_CC(CC_Z);
@ -1926,13 +1926,13 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
case ExtExceptionCheck: { case ExtExceptionCheck: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER)); Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT));
FixupBranch clearInt = Jit->J_CC(CC_NZ); FixupBranch clearInt = Jit->J_CC(CC_NZ);
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT));
FixupBranch noExtException = Jit->J_CC(CC_Z); FixupBranch noExtException = Jit->J_CC(CC_Z);
Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000));
FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); FixupBranch noExtIntEnable = Jit->J_CC(CC_Z);
Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP || ProcessorInterface::INT_CAUSE_PE_TOKEN || ProcessorInterface::INT_CAUSE_PE_FINISH)); Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH));
FixupBranch noCPInt = Jit->J_CC(CC_Z); FixupBranch noCPInt = Jit->J_CC(CC_Z);
Jit->MOV(32, M(&PC), Imm32(InstLoc)); Jit->MOV(32, M(&PC), Imm32(InstLoc));

View File

@ -527,7 +527,10 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
} }
if (em_address == 0) if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); {
// Memory exception occurred during instruction fetch
memory_exception = true;
}
if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT)) if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT))
{ {
@ -644,7 +647,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{ {
if (js.memcheck && (opinfo->flags & FL_USE_FPU)) if (js.memcheck && (opinfo->flags & FL_USE_FPU))
{ {
ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address)); ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address));
} }
if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end())
@ -661,7 +664,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
{ {
ibuild.EmitFPExceptionCheckEnd(ibuild.EmitIntConst(ops[i].address)); ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address));
} }
} }
} }

View File

@ -40,12 +40,14 @@ public:
const u8 *enterCode; const u8 *enterCode;
const u8 *outerLoop;
const u8 *dispatcher; const u8 *dispatcher;
const u8 *dispatcherNoCheck; const u8 *dispatcherNoCheck;
const u8 *dispatcherPcInEAX; const u8 *dispatcherPcInEAX;
const u8 *fpException; const u8 *fpException;
const u8 *testExceptions; const u8 *testExceptions;
const u8 *testExternalExceptions;
const u8 *dispatchPcInEAX; const u8 *dispatchPcInEAX;
const u8 *doTiming; const u8 *doTiming;

View File

@ -58,10 +58,13 @@ protected:
int instructionNumber; int instructionNumber;
int downcountAmount; int downcountAmount;
bool firstFPInstructionFound;
bool isLastInstruction; bool isLastInstruction;
bool forceUnsafeLoad; bool forceUnsafeLoad;
bool memcheck; bool memcheck;
bool skipnext;
bool broken_block; bool broken_block;
int block_flags;
int fifoBytesThisBlock; int fifoBytesThisBlock;

View File

@ -298,9 +298,6 @@ void CheckExceptions()
// Read volatile data once // Read volatile data once
u32 exceptions = ppcState.Exceptions; u32 exceptions = ppcState.Exceptions;
if (!exceptions)
return;
// Example procedure: // Example procedure:
// set SRR0 to either PC or NPC // set SRR0 to either PC or NPC
//SRR0 = NPC; //SRR0 = NPC;
@ -311,7 +308,7 @@ void CheckExceptions()
// clear MSR as specified // clear MSR as specified
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
// set to exception type entry point // set to exception type entry point
//NPC = 0x80000x00; //NPC = 0x00000x00;
if (exceptions & EXCEPTION_ISI) if (exceptions & EXCEPTION_ISI)
{ {
@ -320,7 +317,7 @@ void CheckExceptions()
SRR1 = (MSR & 0x87C0FFFF) | (1 << 30); SRR1 = (MSR & 0x87C0FFFF) | (1 << 30);
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000400; PC = NPC = 0x00000400;
INFO_LOG(POWERPC, "EXCEPTION_ISI"); INFO_LOG(POWERPC, "EXCEPTION_ISI");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ISI); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ISI);
@ -332,7 +329,7 @@ void CheckExceptions()
SRR1 = (MSR & 0x87C0FFFF) | 0x20000; SRR1 = (MSR & 0x87C0FFFF) | 0x20000;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000700; PC = NPC = 0x00000700;
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM"); INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PROGRAM); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PROGRAM);
@ -343,7 +340,7 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000C00; PC = NPC = 0x00000C00;
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC); INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_SYSCALL); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_SYSCALL);
@ -355,7 +352,7 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000800; PC = NPC = 0x00000800;
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_FPU_UNAVAILABLE); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_FPU_UNAVAILABLE);
@ -366,7 +363,7 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000300; PC = NPC = 0x00000300;
//DSISR and DAR regs are changed in GenerateDSIException() //DSISR and DAR regs are changed in GenerateDSIException()
INFO_LOG(POWERPC, "EXCEPTION_DSI"); INFO_LOG(POWERPC, "EXCEPTION_DSI");
@ -380,7 +377,7 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000600; PC = NPC = 0x00000600;
//TODO crazy amount of DSISR options to check out //TODO crazy amount of DSISR options to check out
@ -398,7 +395,7 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000500; PC = NPC = 0x00000500;
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
@ -411,7 +408,58 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000900; PC = NPC = 0x00000900;
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);
}
}
}
void CheckExternalExceptions()
{
// Read volatile data once
u32 exceptions = ppcState.Exceptions;
if (!exceptions)
return;
// Example procedure:
// set SRR0 to either PC or NPC
//SRR0 = NPC;
// save specified MSR bits
//SRR1 = MSR & 0x87C0FFFF;
// copy ILE bit to LE
//MSR |= (MSR >> 16) & 1;
// clear MSR as specified
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
// set to exception type entry point
//NPC = 0x80000x00;
// EXTERNAL INTERRUPT
if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...
{
if (exceptions & EXCEPTION_EXTERNAL_INT)
{
// Pokemon gets this "too early", it hasn't a handler yet
SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36;
PC = NPC = 0x00000500;
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???");
}
else if (exceptions & EXCEPTION_DECREMENTER)
{
SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36;
PC = NPC = 0x00000900;
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);

View File

@ -102,6 +102,7 @@ void SetMode(CoreMode _coreType);
void SingleStep(); void SingleStep();
void CheckExceptions(); void CheckExceptions();
void CheckExternalExceptions();
void CheckBreakPoints(); void CheckBreakPoints();
void RunLoop(); void RunLoop();
void Start(); void Start();