summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorj4ck.fr0st <j4ck.fr0st@gmail.com>2010-07-30 17:51:05 +0000
committerj4ck.fr0st <j4ck.fr0st@gmail.com>2010-07-30 17:51:05 +0000
commit6ed3357066c1434e623331ae76585b67d7bed61a (patch)
treefc849b7d26d6a398c3da23aaeefcf4ed7b1bbb24 /Source
parent1d2f4283d1da9fb221d52ebf54f203a83bb64b5c (diff)
Experimental: Implement skid's MMU Demand Paging in JitIL.
This one needs a lot of testing, since I don't have any games that need it, except Rogue Leader (GSWP64) - and I didn't do more "testing" than watching the stormtroopers dance due to speed reasons (altho it seems twice as fast as JIT for me; it does spit out a lot more warnings too) btw, ITS OVER 6000!!111 git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6006 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR.h13
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp42
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp59
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h2
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp1
5 files changed, 104 insertions, 13 deletions
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
index 9a8ea53c89..970e2cd52f 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h
@@ -163,6 +163,10 @@ enum Opcode {
ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong,
// just a branch
+ // used for MMU, at least until someone
+ // has a better idea of integrating it
+ FPExceptionCheckStart, FPExceptionCheckEnd,
+ ISIException,
// "Opcode" representing a register too far away to
// reference directly; this is a size optimization
Tramp,
@@ -389,6 +393,15 @@ public:
InstLoc EmitSystemCall(InstLoc pc) {
return FoldUOp(SystemCall, pc);
}
+ InstLoc EmitFPExceptionCheckStart(InstLoc pc) {
+ return EmitUOp(FPExceptionCheckStart, pc);
+ }
+ InstLoc EmitFPExceptionCheckEnd(InstLoc pc) {
+ return EmitUOp(FPExceptionCheckEnd, pc);
+ }
+ InstLoc EmitISIException(InstLoc dest) {
+ return EmitUOp(ISIException, dest);
+ }
InstLoc EmitRFIExit() {
return FoldZeroOp(RFIExit, 0);
}
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
index 2f1f9b726c..c33feb2614 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp
@@ -705,6 +705,9 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
case RFIExit:
case InterpreterBranch:
case ShortIdleLoop:
+ case FPExceptionCheckStart:
+ case FPExceptionCheckEnd:
+ case ISIException:
case Int3:
case Tramp:
// No liveness effects
@@ -1607,10 +1610,9 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
}
case SystemCall: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
- Jit->Cleanup();
Jit->OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
Jit->MOV(32, M(&PC), Imm32(InstLoc + 4));
- Jit->JMP(((JitIL *)jit)->asm_routines.testExceptions, true);
+ Jit->WriteExceptionExit();
break;
}
case InterpreterBranch: {
@@ -1627,14 +1629,46 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->AND(32, R(EAX), Imm32(~mask));
Jit->AND(32, R(ECX), Imm32(mask));
Jit->OR(32, R(EAX), R(ECX));
- // MSR &= 0xFFFDFFFF; //TODO: VERIFY
- Jit->AND(32, R(EAX), Imm32(0xFFFDFFFF));
+ // MSR &= 0xFFFBFFFF; // Mask used to clear the bit MSR[13]
+ Jit->AND(32, R(EAX), Imm32(0xFFFBFFFF));
Jit->MOV(32, M(&MSR), R(EAX));
// NPC = SRR0;
Jit->MOV(32, R(EAX), M(&SRR0));
Jit->WriteRfiExitDestInEAX();
break;
}
+ case FPExceptionCheckStart: {
+ unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
+ //This instruction uses FPU - needs to add FP exception bailout
+ Jit->TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit
+ FixupBranch b1 = Jit->J_CC(CC_NZ);
+
+ // If a FPU exception occurs, the exception handler will read
+ // from PC. Update PC with the latest value in case that happens.
+ Jit->MOV(32, M(&PC), Imm32(InstLoc));
+ Jit->SUB(32, M(&CoreTiming::downcount), Jit->js.downcountAmount > 127 ? Imm32(Jit->js.downcountAmount) : Imm8(Jit->js.downcountAmount));
+ Jit->JMP(Jit->asm_routines.fpException, true);
+ Jit->SetJumpTarget(b1);
+ break;
+ }
+ case FPExceptionCheckEnd: {
+ unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
+ Jit->TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
+ FixupBranch noMemException = Jit->J_CC(CC_Z);
+
+ // If a memory exception occurs, the exception handler will read
+ // from PC. Update PC with the latest value in case that happens.
+ Jit->MOV(32, M(&PC), Imm32(InstLoc));
+ Jit->WriteExceptionExit();
+ Jit->SetJumpTarget(noMemException);
+ break;
+ }
+ case ISIException: {
+ unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
+ Jit->ABI_CallFunctionC(reinterpret_cast<void *>(&Memory::GenerateISIException_JIT), InstLoc);
+ Jit->WriteExceptionExit();
+ break;
+ }
case Int3: {
Jit->INT3();
break;
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
index c285efc9c3..f9d7679f23 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp
@@ -172,7 +172,11 @@ void JitIL::Init()
}
else
{
- jo.enableBlocklink = true; // Speed boost, but not 100% safe
+ if (!Core::g_CoreStartupParameter.bJITBlockLinking)
+ jo.enableBlocklink = false;
+ else
+ // Speed boost, but not 100% safe
+ jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
}
#ifdef _M_X64
@@ -185,6 +189,7 @@ void JitIL::Init()
jo.optimizeGatherPipe = true;
jo.fastInterrupts = false;
jo.accurateSinglePrecision = false;
+ js.memcheck = Core::g_CoreStartupParameter.bMMU;
trampolines.Init();
AllocCodeSpace(CODE_SIZE);
@@ -336,11 +341,10 @@ void JitIL::WriteRfiExitDestInEAX()
JMP(asm_routines.testExceptions, true);
}
-void JitIL::WriteExceptionExit(u32 exception)
+void JitIL::WriteExceptionExit()
{
Cleanup();
- OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception));
- MOV(32, M(&PC), Imm32(js.compilerPC + 4));
+ SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.testExceptions, true);
}
@@ -401,6 +405,9 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{
int blockSize = code_buf->GetSize();
+ // Memory exception on instruction fetch
+ bool memory_exception = false;
+
// A broken block is a block that does not end in a branch
bool broken_block = false;
@@ -414,7 +421,21 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
- int size;
+ if (Core::g_CoreStartupParameter.bMMU &&
+ (em_address >> 28) != 0x0 &&
+ (em_address >> 28) != 0x8 &&
+ (em_address >> 28) != 0x9 &&
+ (em_address >> 28) != 0xC &&
+ (em_address >> 28) != 0xD)
+ {
+ if (!Memory::TranslateAddress(em_address, Memory::FLAG_OPCODE))
+ {
+ // Memory exception occurred during instruction fetch
+ memory_exception = true;
+ }
+ }
+
+ int size = 0;
js.isLastInstruction = false;
js.blockStart = em_address;
js.fifoBytesThisBlock = 0;
@@ -423,7 +444,12 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
//Analyze the block, collect all instructions it is made of (including inlining,
//if that is enabled), reorder instructions for optimal performance, and join joinable instructions.
- b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize);
+ b->exitAddress[0] = em_address;
+ if (!memory_exception)
+ {
+ // If there is a memory exception inside a block (broken_block==true), compile up to that instruction.
+ b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize);
+ }
PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr
@@ -459,8 +485,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
ibuild.Reset();
- js.downcountAmount = js.st.numCycles;
-
+ js.downcountAmount = 0;
if (!Core::g_CoreStartupParameter.bEnableDebugging)
js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address);
@@ -470,6 +495,9 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
js.compilerPC = ops[i].address;
js.op = &ops[i];
js.instructionNumber = i;
+ const GekkoOPInfo *opinfo = GetOpInfo(ops[i].inst);
+ js.downcountAmount += (opinfo->numCyclesMinusOne + 1);
+
if (i == (int)size - 1)
{
js.isLastInstruction = true;
@@ -484,10 +512,25 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (!ops[i].skip)
{
+ if (js.memcheck && (opinfo->flags & FL_USE_FPU))
+ {
+ ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address));
+ }
+
JitILTables::CompileInstruction(ops[i]);
+
+ if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
+ {
+ ibuild.EmitFPExceptionCheckEnd(ibuild.EmitIntConst(ops[i].address));
+ }
}
}
+ if (memory_exception)
+ {
+ ibuild.EmitISIException(ibuild.EmitIntConst(em_address));
+ }
+
// Perform actual code generation
WriteCode();
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h
index f493bc3214..732978bd93 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h
@@ -112,7 +112,7 @@ public:
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInEAX(int exit_num);
- void WriteExceptionExit(u32 exception);
+ void WriteExceptionExit();
void WriteRfiExitDestInEAX();
void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup();
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
index 10b05703ec..3623b06551 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp
@@ -125,6 +125,7 @@ void JitIL::cmpXX(UGeckoInstruction inst)
rhs = ibuild.EmitIntConst(inst.SIMM_16);
res = ibuild.EmitICmpCRSigned(lhs, rhs);
}
+ js.downcountAmount++; //TODO: should this be somewhere else?
ibuild.EmitStoreCR(res, inst.CRFD);
}