Implemented MMU Demand Paging

* Emulated correct behaviour of DSI and ISI exceptions
* Added memory exception checks
* Added fast TLB cache implementation (written by booto)
* Added "Enable MMU" option in the game properties
* Renamed old TLBHack to "MMU speed hack"

Thanks to booto (PowerPC) and nash (testing) who spent many weeks of their time helping me make this work.  Also thanks to shuffle2 for finding and converting the map file of the original target.

There are two options for MMU emulation found under the game properties.  "Enable MMU" is the accurate emulation option.  "MMU speed hack" is the old TLBHack renamed. Most games will work with one or the other.  Some games can work with both options ticked.

Only the JIT recompiler and Interpreter work with the MMU code.  JITIL is not supported (too hard for me to add).

The speed optimised code still needs a lot more work and is disabled for now.

Fixes issue 2546
Fixes issue 2583
Fixes issue 2704



git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5994 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau
2010-07-29 12:17:47 +00:00
parent b70f134c88
commit 9ff5e836eb
34 changed files with 1025 additions and 646 deletions
+1
View File
@@ -290,6 +290,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default
+1 -1
View File
@@ -55,7 +55,7 @@ void Console_Submit(const char *cmd)
{
#if MAX_LOGLEVEL >= INFO_LEVEL
u32 EA =
Memory::TranslatePageAddress(addr, Memory::FLAG_NO_EXCEPTION);
Memory::TranslateAddress(addr, Memory::FLAG_NO_EXCEPTION);
INFO_LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
#endif
}
+9
View File
@@ -183,6 +183,15 @@ bool Init()
SCoreStartupParameter &_CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
g_CoreStartupParameter = _CoreParameter;
// TODO: Reenable JIT instructions
if (g_CoreStartupParameter.bMMU)
{
g_CoreStartupParameter.bJITLoadStoreOff = true;
g_CoreStartupParameter.bJITLoadStorePairedOff = true;
g_CoreStartupParameter.bJITLoadStoreFloatingOff = true;
}
// FIXME DEBUG_LOG(BOOT, dump_params());
Host_SetWaitCursor(true);
+3 -2
View File
@@ -32,7 +32,7 @@
SCoreStartupParameter::SCoreStartupParameter()
: hInstance(0), hMainWindow(0),
bJITNoBlockCache(false), bJITBlockLinking(false),
bJITNoBlockCache(false), bJITBlockLinking(true),
bJITOff(false),
bJITLoadStoreOff(false), bJITLoadStorelXzOff(false),
bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false),
@@ -48,7 +48,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bEnableCheats(false),
bRunCompareServer(false), bRunCompareClient(false),
iTLBHack(0), SelectedLanguage(0),
bWii(false),
bWii(false), bMMU(false),
bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true),
iRenderWindowXPos(0), iRenderWindowYPos(0),
@@ -72,6 +72,7 @@ void SCoreStartupParameter::LoadDefaults()
bEnableFPRF = false;
bWii = false;
SelectedLanguage = 0;
bMMU = false;
iTLBHack = 0;
iPosX = 100;
+1
View File
@@ -77,6 +77,7 @@ struct SCoreStartupParameter
bool bRunCompareServer;
bool bRunCompareClient;
bool bMMU;
int iTLBHack;
int SelectedLanguage;
+29 -133
View File
@@ -58,6 +58,7 @@ namespace Memory
/* Enable the Translation Lookaside Buffer functions. TLBHack = 1 in Dolphin.ini or a
<GameID>.ini file will set this to true */
bool bFakeVMEM = false;
bool bMMU = false;
// ==============
@@ -348,6 +349,7 @@ bool Init()
{
bool wii = SConfig::GetInstance().m_LocalCoreStartupParameter.bWii;
bFakeVMEM = SConfig::GetInstance().m_LocalCoreStartupParameter.iTLBHack == 1;
bMMU = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU;
u32 flags = 0;
if (wii) flags |= MV_WII_ONLY;
@@ -416,28 +418,37 @@ u32 Read_Instruction(const u32 em_address)
return inst.hex;
}
u32 Read_Opcode_JIT(const u32 _Address)
u32 Read_Opcode_JIT(u32 _Address)
{
#ifdef FAST_ICACHE
if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 &&
(_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
if (bMMU && !bFakeVMEM && (_Address >> 28) == 0x7)
{
PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0;
_Address = Memory::TranslateAddress(_Address, Memory::XCheckTLBFlag::FLAG_OPCODE);
if (_Address == 0)
{
return 0;
}
}
u32 inst = Read_Opcode(_Address);
u32 inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
// if a crash occured after that message
// that means that we've compiled outdated code from the cache instead of memory
// that means that we have compiled outdated code from the cache instead of memory
// this could happen if a game forgot to icbi the new code
#if defined(_DEBUG) || defined(DEBUGFAST)
u32 inst_mem = Memory::ReadUnchecked_U32(_Address);
if (inst_mem != inst)
ERROR_LOG(POWERPC, "JIT: compiling outdated code. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst);
inst = Read_Opcode_JIT_LC(_Address);
if (inst_mem != inst)
{
ERROR_LOG(POWERPC, "JIT: self-modifying code detected. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst);
PanicAlert("JIT: self-modifying code detected. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst);
Write_Opcode_JIT(_Address, inst_mem);
}
#endif
return inst;
}
@@ -451,6 +462,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address)
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{
PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
ERROR_LOG(MEMMAP, "iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0;
}
u8* iCache;
@@ -505,132 +517,14 @@ void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
#endif
}
// =======================================================
/* Functions to detect and trace memory read/write errors. Turn of JIT LoadStore to
make it work, and add a return 0 at the beginning of CheckDTLB to avoid closing
Dolphin just as it starts to get interesting. You can also try to change
the TitleID write in IOCTL_ES_GETTITLEID to 0x00000000, otherwise it will never even
get to making the bad dev/di request.
I'm currently at (---, 8021347c) : Write32: Program wrote [0x7fd5d340] to [0x933e00f8],
0x8021347c seems to write the out buffer to a 0x933e.... address before it is copies
to the 0x133e.... address for the Ioctlv. But why does it generate this bad address
when it made a good one 120 milliseconds earlier?
*/
// -------------
bool ValidMemory(const u32 _Address)
void GenerateISIException_JIT(u32 _EffectiveAddress)
{
switch (_Address >> 24)
{
case 0x00:
case 0x01:
case 0x80:
case 0x81:
case 0xC0:
case 0xC1:
return true;
GenerateISIException(_EffectiveAddress);
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
return true;
else
return false;
case 0x7e:
case 0x7f:
if (bFakeVMEM)
return true;
else
return false;
case 0xE0:
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
return true;
else
return false;
case 0xCC:
case 0xCD:
case 0xC8:
return true;
}
return false;
// Remove the invalid instruction from the icache, forcing a recompile
Write_Opcode_JIT(_EffectiveAddress, JIT_ICACHE_INVALID_WORD);
}
void CheckForBadAddresses(u32 Address, u32 Data, bool Read, int Bits)
{
if (!ValidMemory(Address))
{
if(Read)
{
WARN_LOG(CONSOLE, "Read%i: Program tried to read [%08x] from [%08x]", Bits, Address);
}
else
{
ERROR_LOG(CONSOLE, "Write%i: Program tried to write [%08x] to [%08x]", Bits, Data, Address);
}
}
if (Address == 0)
{
if(Read)
{
WARN_LOG(CONSOLE, "Read%i: Program read [0x%08x] from [0x%08x] * * * 0 * * *", Bits, Data, Address);
}
else
{
WARN_LOG(CONSOLE, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * 0 * * *", Bits, Data, Address);
}
}
// Try to figure out where the dev/di Ioctl arguments are stored (including buffer out), so we can
// find the bad one
if(
Data == 0x1090f4c0 // good out buffer right before it, for sound/smashbros_sound.brsar
|| Data == 0x10913b00 // second one
|| Data == 0x7fd5d340 // first bad out buffer
|| Data == 0x133e00f8 // the address that store the bad 0x7fd5d340, this changes every time
|| Data == 0x2a24aa // menu2\sc_title_en.pac byte size
|| (
(PC == 0x8021347c || PC == 0x801f6a20 || PC == 0x800202d0 || PC == 0x80229964
|| PC == 0x801d88bc) /* this could be interesting, because the bad out buffer 0x7fd5d340
is 0x80000000 - size = 0x7fd5d340 perhaps some function read 0x80000000, I dunno */
&& Data == 0x80000000)
)
{
if(Read)
{
ERROR_LOG(CONSOLE, "Read%i: Program read [0x%08x] from [0x%08x] * * * * * * * * * * * *", Bits, Data, Address);
}
else
{
ERROR_LOG(CONSOLE, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * * * * * * * * * *", Bits,Data, Address);
}
}
}
void CheckForBadAddresses8(u32 Address, u8 Data, bool Read)
{CheckForBadAddresses(Address, (u32)Data, Read, 8);}
void CheckForBadAddresses16(u32 Address, u16 Data, bool Read)
{CheckForBadAddresses(Address, (u32)Data, Read, 16);}
void CheckForBadAddresses32(u32 Address, u32 Data, bool Read)
{CheckForBadAddresses(Address, (u32)Data, Read, 32);}
void CheckForBadAddresses64(u32 Address, u64 Data, bool Read)
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
{
memcpy(GetPointer(_Address), _pData, _iSize);
@@ -709,7 +603,6 @@ void GetString(std::string& _string, const u32 em_address)
_string = stringBuffer;
}
// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit
// programs don't have problems directly addressing any part of memory.
u8 *GetPointer(const u32 _Address)
@@ -743,7 +636,10 @@ u8 *GetPointer(const u32 _Address)
case 0x7E:
case 0x7F:
return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK));
if (bFakeVMEM)
return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK));
else
return 0;
case 0xE0:
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
+8 -4
View File
@@ -51,7 +51,7 @@ namespace Memory
// so be sure to load it into a 64-bit register.
extern u8 *base;
// These are guarenteed to point to "low memory" addresses (sub-32-bit).
// These are guaranteed to point to "low memory" addresses (sub-32-bit).
extern u8 *m_pRAM;
extern u8 *m_pEXRAM;
extern u8 *m_pL1Cache;
@@ -75,7 +75,7 @@ enum
#ifdef _M_IX86
MEMVIEW32_MASK = 0x3FFFFFFF,
#endif
};
};
// Init and Shutdown
bool IsInitialized();
@@ -169,11 +169,15 @@ enum XCheckTLBFlag
FLAG_WRITE,
FLAG_OPCODE,
};
u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag);
u32 TranslateBlockAddress(u32 _Address);
u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag);
void InvalidateTLBEntry(u32 _Address);
void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite);
void GenerateISIException(u32 _EffectiveAdress);
void GenerateISIException_JIT(u32 _EffectiveAdress);
extern u32 pagetable_base;
extern u32 pagetable_hashmask;
};
#endif
File diff suppressed because it is too large Load Diff
+1
View File
@@ -2797,6 +2797,7 @@ DEFINE_LUA_FUNCTION(emulua_loadrom, "filename")
game_ini.Get("Core", "CPUOnThread", &StartUp.bCPUThread, StartUp.bCPUThread);
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
// Wii settings
if (StartUp.bWii)
@@ -82,32 +82,54 @@ void SingleStepInner(void)
static UGeckoInstruction instCode;
NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = Memory::Read_Opcode(PC);
instCode.hex = Memory::Read_Opcode(PC);
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) //If FPU is enabled, just execute
m_opTable[instCode.OPCD](instCode);
else
if (instCode.hex != 0)
{
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
UReg_MSR& msr = (UReg_MSR&)MSR;
if (msr.FP) //If FPU is enabled, just execute
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions();
m_EndBlock = true;
// check if we have to generate a FPU unavailable exception
if (!PPCTables::UsesFPU(instCode))
{
m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
}
else
{
// Memory exception on instruction fetch
PowerPC::CheckExceptions();
m_EndBlock = true;
}
last_pc = PC;
PC = NPC;
#if defined(_DEBUG) || defined(DEBUGFAST)
if (PowerPC::ppcState.gpr[1] == 0)
{
printf("%i Corrupt stack", PowerPC::ppcState.DebugCount);
}
#if defined(_DEBUG) || defined(DEBUGFAST)
PowerPC::ppcState.DebugCount++;
#endif
patches();
@@ -224,11 +246,15 @@ void Run()
void unknown_instruction(UGeckoInstruction _inst)
{
char disasm[256];
DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
printf("Last PC = %08x : %s\n", last_pc, disasm);
Dolphin_Debugger::PrintCallstack();
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
if (_inst.hex != 0)
{
char disasm[256];
DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
printf("Last PC = %08x : %s\n", last_pc, disasm);
Dolphin_Debugger::PrintCallstack();
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR);
}
}
} // namespace
File diff suppressed because it is too large Load Diff
@@ -153,7 +153,6 @@ float Helper_Dequantize(const u32 _Addr, const EQuantizeType _quantizeType,
fResult = 0;
break;
}
return fResult;
}
@@ -170,12 +169,23 @@ void psq_l(UGeckoInstruction _inst)
if (_inst.W == 0)
{
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
rPS1(_inst.RS) = Helper_Dequantize(EA+c, ldType, ldScale);
float ps0 = Helper_Dequantize(EA, ldType, ldScale);
float ps1 = Helper_Dequantize(EA+c, ldType, ldScale);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = ps1;
}
else
{
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale);
float ps0 = Helper_Dequantize(EA, ldType, ldScale);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = 1.0f;
}
}
@@ -193,12 +203,23 @@ void psq_lu(UGeckoInstruction _inst)
if (_inst.W == 0)
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
float ps1 = Helper_Dequantize( EA+c, ldType, ldScale );
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = ps1;
}
else
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = 1.0f;
}
m_GPR[_inst.RA] = EA;
@@ -246,6 +267,10 @@ void psq_stu(UGeckoInstruction _inst)
{
Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale);
}
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
m_GPR[_inst.RA] = EA;
}
@@ -262,13 +287,29 @@ void psq_lx(UGeckoInstruction _inst)
if (_inst.Wx == 0)
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
float ps1 = Helper_Dequantize( EA+c, ldType, ldScale );
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = ps1;
}
else
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = 1.0f;
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
float ps1 = 1.0f;
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = ps1;
}
}
@@ -307,12 +348,23 @@ void psq_lux(UGeckoInstruction _inst)
if (_inst.Wx == 0)
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale );
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
float ps1 = Helper_Dequantize( EA+c, ldType, ldScale );
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = ps1;
}
else
{
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale );
float ps0 = Helper_Dequantize( EA, ldType, ldScale );
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
rPS0(_inst.RS) = ps0;
rPS1(_inst.RS) = 1.0f;
}
m_GPR[_inst.RA] = EA;
@@ -338,6 +390,10 @@ void psq_stux(UGeckoInstruction _inst)
{
Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale);
}
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
m_GPR[_inst.RA] = EA;
} // namespace=======
@@ -63,40 +63,40 @@ static GekkoOPTemplate primarytable[] =
{28, Interpreter::andi_rc, {"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
{29, Interpreter::andis_rc, {"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}},
{32, Interpreter::lwz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{33, Interpreter::lwzu, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{34, Interpreter::lbz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{35, Interpreter::lbzu, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{40, Interpreter::lhz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{41, Interpreter::lhzu, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{32, Interpreter::lwz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}},
{33, Interpreter::lwzu, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}},
{34, Interpreter::lbz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}},
{35, Interpreter::lbzu, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}},
{40, Interpreter::lhz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}},
{41, Interpreter::lhzu, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}},
{42, Interpreter::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}},
{43, Interpreter::lhau, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}},
{42, Interpreter::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}},
{43, Interpreter::lhau, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}},
{44, Interpreter::sth, {"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
{45, Interpreter::sthu, {"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
{36, Interpreter::stw, {"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
{37, Interpreter::stwu, {"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
{38, Interpreter::stb, {"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}},
{39, Interpreter::stbu, {"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}},
{44, Interpreter::sth, {"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{45, Interpreter::sthu, {"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{36, Interpreter::stw, {"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{37, Interpreter::stwu, {"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{38, Interpreter::stb, {"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{39, Interpreter::stbu, {"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}},
{46, Interpreter::lmw, {"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
{47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}},
{46, Interpreter::lmw, {"lmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}},
{47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}},
{48, Interpreter::lfs, {"lfs", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU}},
{49, Interpreter::lfsu, {"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{50, Interpreter::lfd, {"lfd", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU}},
{51, Interpreter::lfdu, {"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{48, Interpreter::lfs, {"lfs", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{49, Interpreter::lfsu, {"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{50, Interpreter::lfd, {"lfd", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{51, Interpreter::lfdu, {"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{52, Interpreter::stfs, {"stfs", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU}},
{53, Interpreter::stfsu, {"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{54, Interpreter::stfd, {"stfd", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU}},
{55, Interpreter::stfdu, {"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{52, Interpreter::stfs, {"stfs", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{53, Interpreter::stfsu, {"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{54, Interpreter::stfd, {"stfd", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{55, Interpreter::stfdu, {"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{56, Interpreter::psq_l, {"psq_l", OPTYPE_PS, FL_IN_A | FL_USE_FPU}},
{57, Interpreter::psq_lu, {"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{60, Interpreter::psq_st, {"psq_st", OPTYPE_PS, FL_IN_A | FL_USE_FPU}},
{61, Interpreter::psq_stu, {"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU}},
{56, Interpreter::psq_l, {"psq_l", OPTYPE_PS, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{57, Interpreter::psq_lu, {"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{60, Interpreter::psq_st, {"psq_st", OPTYPE_PS, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
{61, Interpreter::psq_stu, {"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}},
//missing: 0, 5, 6, 9, 22, 30, 62, 58
{0, Interpreter::unknown_instruction, {"unknown_instruction", OPTYPE_UNKNOWN, 0}},
@@ -151,10 +151,10 @@ static GekkoOPTemplate table4_2[] =
static GekkoOPTemplate table4_3[] =
{
{6, Interpreter::psq_lx, {"psq_lx", OPTYPE_PS, FL_USE_FPU}},
{7, Interpreter::psq_stx, {"psq_stx", OPTYPE_PS, FL_USE_FPU}},
{38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU}},
{39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU}},
{6, Interpreter::psq_lx, {"psq_lx", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
{7, Interpreter::psq_stx, {"psq_stx", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
{38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
{39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
};
static GekkoOPTemplate table19[] =
@@ -207,63 +207,63 @@ static GekkoOPTemplate table31[] =
{1014, Interpreter::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}},
//load word
{23, Interpreter::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{55, Interpreter::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
{23, Interpreter::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{55, Interpreter::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load halfword
{279, Interpreter::lhzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{311, Interpreter::lhzux, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
{279, Interpreter::lhzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{311, Interpreter::lhzux, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load halfword signextend
{343, Interpreter::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{375, Interpreter::lhaux, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
{343, Interpreter::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{375, Interpreter::lhaux, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load byte
{87, Interpreter::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{119, Interpreter::lbzux, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}},
{87, Interpreter::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{119, Interpreter::lbzux, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load byte reverse
{534, Interpreter::lwbrx, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{790, Interpreter::lhbrx, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}},
{534, Interpreter::lwbrx, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{790, Interpreter::lhbrx, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
// Conditional load/store (Wii SMP)
{150, Interpreter::stwcxd, {"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}},
{20, Interpreter::lwarx, {"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0}},
{150, Interpreter::stwcxd, {"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0 | FL_LOADSTORE}},
{20, Interpreter::lwarx, {"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE}},
//load string (Inst these)
{533, Interpreter::lswx, {"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}},
{597, Interpreter::lswi, {"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}},
{533, Interpreter::lswx, {"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D | FL_LOADSTORE}},
{597, Interpreter::lswi, {"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D | FL_LOADSTORE}},
//store word
{151, Interpreter::stwx, {"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
{183, Interpreter::stwux, {"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
{151, Interpreter::stwx, {"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{183, Interpreter::stwux, {"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store halfword
{407, Interpreter::sthx, {"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
{439, Interpreter::sthux, {"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
{407, Interpreter::sthx, {"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{439, Interpreter::sthux, {"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store byte
{215, Interpreter::stbx, {"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
{247, Interpreter::stbux, {"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}},
{215, Interpreter::stbx, {"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{247, Interpreter::stbux, {"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store bytereverse
{662, Interpreter::stwbrx, {"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}},
{918, Interpreter::sthbrx, {"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}},
{662, Interpreter::stwbrx, {"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
{918, Interpreter::sthbrx, {"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B | FL_LOADSTORE}},
{661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL}},
{725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL}},
{661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}},
{725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}},
// fp load/store
{535, Interpreter::lfsx, {"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}},
{567, Interpreter::lfsux, {"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU}},
{599, Interpreter::lfdx, {"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}},
{631, Interpreter::lfdux, {"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU}},
{535, Interpreter::lfsx, {"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{567, Interpreter::lfsux, {"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{599, Interpreter::lfdx, {"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{631, Interpreter::lfdux, {"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{663, Interpreter::stfsx, {"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}},
{695, Interpreter::stfsux, {"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU}},
{727, Interpreter::stfdx, {"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}},
{759, Interpreter::stfdux, {"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU}},
{983, Interpreter::stfiwx, {"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}},
{663, Interpreter::stfsx, {"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{695, Interpreter::stfsux, {"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{727, Interpreter::stfdx, {"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{759, Interpreter::stfdux, {"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{983, Interpreter::stfiwx, {"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}},
{19, Interpreter::mfcr, {"mfcr", OPTYPE_SYSTEM, FL_OUT_D}},
{83, Interpreter::mfmsr, {"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}},
+88 -38
View File
@@ -175,17 +175,22 @@ void Jit64::Init()
where this cause problems, so I'm enabling this by default, since I seem to get perhaps as much as 20% more
fps with this option enabled. If you suspect that this option cause problems you can also disable it from the
debugging window. */
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
jo.enableBlocklink = false;
SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = false;
Core::g_CoreStartupParameter.bSkipIdle = false;
}
else
{
jo.enableBlocklink = true;
if (!Core::g_CoreStartupParameter.bJITBlockLinking)
{
jo.enableBlocklink = false;
}
else
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
}
#ifdef _M_X64
jo.enableFastMem = SConfig::GetInstance().m_LocalCoreStartupParameter.bUseFastMem;
jo.enableFastMem = Core::g_CoreStartupParameter.bUseFastMem;
#else
jo.enableFastMem = false;
#endif
@@ -194,16 +199,11 @@ void Jit64::Init()
jo.optimizeGatherPipe = true;
jo.fastInterrupts = false;
jo.accurateSinglePrecision = true;
js.memcheck = Core::g_CoreStartupParameter.bMMU;
gpr.SetEmitter(this);
fpr.SetEmitter(this);
if (Core::g_CoreStartupParameter.bJITBlockLinking)
{
jo.enableBlocklink = false;
SuccessAlert("Your game was started without JIT Block Linking");
}
trampolines.Init();
AllocCodeSpace(CODE_SIZE);
@@ -218,7 +218,6 @@ void Jit64::ClearCache()
ClearCodeSpace();
}
void Jit64::Shutdown()
{
FreeCodeSpace();
@@ -349,11 +348,10 @@ void Jit64::WriteRfiExitDestInEAX()
JMP(asm_routines.testExceptions, true);
}
void Jit64::WriteExceptionExit(u32 exception)
void Jit64::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);
}
@@ -361,7 +359,6 @@ void STACKALIGN Jit64::Run()
{
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr();
//Will return when PowerPC::state changes
}
void Jit64::SingleStep()
@@ -370,7 +367,7 @@ void Jit64::SingleStep()
pExecAddr();
}
void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address)
void Jit64::Trace()
{
char regs[500] = "";
char fregs[750] = "";
@@ -392,11 +389,11 @@ void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address)
strncat(fregs, reg, 750);
}
#endif
const PPCAnalyst::CodeOp &op = code_buf->codebuffer[0];
char ppcInst[256];
DisassembleGekko(op.inst.hex, em_address, ppcInst, 256);
NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, op.inst.hex, ppcInst);
NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs);
}
void STACKALIGN Jit64::Jit(u32 em_address)
@@ -410,21 +407,36 @@ void STACKALIGN Jit64::Jit(u32 em_address)
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
}
const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
{
int blockSize = code_buf->GetSize();
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
// 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;
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
// Comment out the following to disable breakpoints (speed-up)
blockSize = 1;
Trace(code_buf, em_address);
broken_block = true;
Trace();
}
if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR);
if (Core::g_CoreStartupParameter.bMMU && (em_address >> 28) == 0x7)
{
if (!Memory::TranslateAddress(em_address, Memory::XCheckTLBFlag::FLAG_OPCODE))
{
// Memory exception occurred during instruction fetch
memory_exception = true;
}
}
int size = 0;
js.isLastInstruction = false;
js.blockStart = em_address;
@@ -435,7 +447,12 @@ const u8* Jit64::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.
u32 nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buf, blockSize);
u32 nextPC = em_address;
if (!memory_exception)
{
// If there is a memory exception inside a block (broken_block==true), compile up to that instruction.
nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize);
}
PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
@@ -465,16 +482,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
SetJumpTarget(b1);
}
if (false && jo.fastInterrupts)
{
// This does NOT yet work.
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
FixupBranch b1 = J_CC(CC_Z);
MOV(32, M(&PC), Imm32(js.blockStart));
JMP(asm_routines.testExceptions, true);
SetJumpTarget(b1);
}
// Conditionally add profiling code.
if (Profiler::g_ProfileBlocks) {
ADD(32, M(&b->runCount), Imm8(1));
@@ -498,18 +505,22 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
gpr.Start(js.gpa);
fpr.Start(js.fpa);
js.downcountAmount = js.st.numCycles;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address);
js.downcountAmount = 0;
if (!Core::g_CoreStartupParameter.bEnableDebugging)
js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address);
js.skipnext = false;
js.blockSize = size;
js.compilerPC = nextPC;
// Translate instructions
for (int i = 0; i < (int)size; i++)
{
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)
{
// WARNING - cmp->branch merging will screw this up.
@@ -539,8 +550,40 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
}
if (!ops[i].skip)
{
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
{
// If a memory exception occurs, the exception handler will read
// from PC. Update PC with the latest value in case that happens.
MOV(32, M(&PC), Imm32(ops[i].address));
}
if (js.memcheck && (opinfo->flags & FL_USE_FPU))
{
//This instruction 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);
// If a FPU exception occurs, the exception handler will read
// from PC. Update PC with the latest value in case that happens.
MOV(32, M(&PC), Imm32(ops[i].address));
SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
JMP(asm_routines.fpException, true);
SetJumpTarget(b1);
}
Jit64Tables::CompileInstruction(ops[i]);
if (js.memcheck && (opinfo->flags & FL_LOADSTORE))
{
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
FixupBranch noMemException = J_CC(CC_Z);
WriteExceptionExit();
SetJumpTarget(noMemException);
}
}
#if defined(_DEBUG) || defined(DEBUGFAST)
if (gpr.SanityCheck() || fpr.SanityCheck())
{
@@ -558,7 +601,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (js.cancel)
break;
}
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging)
if (memory_exception)
{
ABI_CallFunctionC(reinterpret_cast<void *>(&Memory::GenerateISIException_JIT), js.compilerPC);
WriteExceptionExit();
}
if (broken_block)
{
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
+15 -3
View File
@@ -52,6 +52,16 @@
Core::g_CoreStartupParameter.bJIT##type##Off) \
{Default(inst); return;}
#define MEMCHECK_START \
FixupBranch memException; \
if (js.memcheck) \
{ TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); \
memException = J_CC(CC_NZ); }
#define MEMCHECK_END \
if (js.memcheck) \
SetJumpTarget(memException);
class Jit64 : public JitBase
{
private:
@@ -69,6 +79,8 @@ private:
int block_flags;
bool isLastInstruction;
bool memcheck;
bool broken_block;
int fifoBytesThisBlock;
@@ -105,12 +117,12 @@ public:
JitBlockCache *GetBlockCache() { return &blocks; }
void NotifyBreakpoint(u32 em_address, bool set);
void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address);
void Trace();
void ClearCache();
const u8 *GetDispatcher() {
return asm_routines.dispatcher; // asm_routines.dispatcher
return asm_routines.dispatcher;
}
const CommonAsmRoutines *GetAsmRoutines() {
return &asm_routines;
@@ -132,7 +144,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();
@@ -389,8 +389,6 @@ void CompileInstruction(PPCAnalyst::CodeOp & op)
#endif
info->compileCount++;
info->lastUse = jit->js.compilerPC;
} else {
PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC);
}
}
@@ -129,8 +129,6 @@ void Jit64AsmRoutineManager::Generate()
//FP blocks test for FPU available, jump here if false
fpException = AlignCode4();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC));
@@ -47,7 +47,9 @@ void Jit64::sc(UGeckoInstruction inst)
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
WriteExceptionExit(EXCEPTION_SYSCALL);
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
WriteExceptionExit();
}
void Jit64::rfi(UGeckoInstruction inst)
@@ -238,7 +238,8 @@ void Jit64::cmpXX(UGeckoInstruction inst)
}
}
if (!merge_branch) {
if (!merge_branch)
{
// Keep the normal code separate for clarity.
CMP(32, gpr.R(a), comparand);
@@ -256,6 +257,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
// TODO: If we ever care about SO, borrow a trick from
// http://maws.mameworld.info/maws/mamesrc/src/emu/cpu/powerpc/drc_ops.c : bt, adc
} else {
js.downcountAmount++;
int test_bit = 8 >> (js.next_inst.BI & 3);
bool condition = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? false : true;
CMP(32, gpr.R(a), comparand);
+13 -10
View File
@@ -357,13 +357,13 @@ void JitIL::SingleStep()
pExecAddr();
}
void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address)
void JitIL::Trace()
{
char regs[500] = "";
char fregs[750] = "";
#ifdef JIT_LOG_GPR
for (unsigned int i = 0; i < 32; i++)
for (int i = 0; i < 32; i++)
{
char reg[50];
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]);
@@ -372,18 +372,18 @@ void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address)
#endif
#ifdef JIT_LOG_FPR
for (unsigned int i = 0; i < 32; i++)
for (int i = 0; i < 32; i++)
{
char reg[50];
sprintf(reg, "f%02d: %016x ", i, riPS0(i));
strncat(fregs, reg, 750);
}
#endif
const PPCAnalyst::CodeOp &op = code_buf->codebuffer[0];
char ppcInst[256];
DisassembleGekko(op.inst.hex, em_address, ppcInst, 256);
NOTICE_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, op.inst.hex, ppcInst);
NOTICE_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs);
}
void STACKALIGN JitIL::Jit(u32 em_address)
@@ -401,11 +401,14 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
{
int blockSize = code_buf->GetSize();
// A broken block is a block that does not end in a branch
bool broken_block = false;
if (Core::g_CoreStartupParameter.bEnableDebugging)
{
// Comment out the following to disable breakpoints (speed-up)
blockSize = 1;
Trace(code_buf, em_address);
Trace();
}
if (em_address == 0)
@@ -420,7 +423,7 @@ 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, code_buf, blockSize);
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

Some files were not shown because too many files have changed in this diff Show More