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
This commit is contained in:
j4ck.fr0st 2010-07-30 17:51:05 +00:00
parent 1d2f4283d1
commit 6ed3357066
5 changed files with 104 additions and 13 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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] = 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,8 +512,23 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (!ops[i].skip)
{
JitILTables::CompileInstruction(ops[i]);
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

View File

@ -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();

View File

@ -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);
}