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

View File

@ -290,6 +290,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false); ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false); ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, 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", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default

View File

@ -55,7 +55,7 @@ void Console_Submit(const char *cmd)
{ {
#if MAX_LOGLEVEL >= INFO_LEVEL #if MAX_LOGLEVEL >= INFO_LEVEL
u32 EA = 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); INFO_LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA);
#endif #endif
} }

View File

@ -183,6 +183,15 @@ bool Init()
SCoreStartupParameter &_CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; SCoreStartupParameter &_CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter;
g_CoreStartupParameter = _CoreParameter; 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()); // FIXME DEBUG_LOG(BOOT, dump_params());
Host_SetWaitCursor(true); Host_SetWaitCursor(true);

View File

@ -32,7 +32,7 @@
SCoreStartupParameter::SCoreStartupParameter() SCoreStartupParameter::SCoreStartupParameter()
: hInstance(0), hMainWindow(0), : hInstance(0), hMainWindow(0),
bJITNoBlockCache(false), bJITBlockLinking(false), bJITNoBlockCache(false), bJITBlockLinking(true),
bJITOff(false), bJITOff(false),
bJITLoadStoreOff(false), bJITLoadStorelXzOff(false), bJITLoadStoreOff(false), bJITLoadStorelXzOff(false),
bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false), bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false),
@ -48,7 +48,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bEnableCheats(false), bEnableCheats(false),
bRunCompareServer(false), bRunCompareClient(false), bRunCompareServer(false), bRunCompareClient(false),
iTLBHack(0), SelectedLanguage(0), iTLBHack(0), SelectedLanguage(0),
bWii(false), bWii(false), bMMU(false),
bConfirmStop(false), bHideCursor(false), bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true), bAutoHideCursor(false), bUsePanicHandlers(true),
iRenderWindowXPos(0), iRenderWindowYPos(0), iRenderWindowXPos(0), iRenderWindowYPos(0),
@ -72,6 +72,7 @@ void SCoreStartupParameter::LoadDefaults()
bEnableFPRF = false; bEnableFPRF = false;
bWii = false; bWii = false;
SelectedLanguage = 0; SelectedLanguage = 0;
bMMU = false;
iTLBHack = 0; iTLBHack = 0;
iPosX = 100; iPosX = 100;

View File

@ -77,6 +77,7 @@ struct SCoreStartupParameter
bool bRunCompareServer; bool bRunCompareServer;
bool bRunCompareClient; bool bRunCompareClient;
bool bMMU;
int iTLBHack; int iTLBHack;
int SelectedLanguage; int SelectedLanguage;

View File

@ -58,6 +58,7 @@ namespace Memory
/* Enable the Translation Lookaside Buffer functions. TLBHack = 1 in Dolphin.ini or a /* Enable the Translation Lookaside Buffer functions. TLBHack = 1 in Dolphin.ini or a
<GameID>.ini file will set this to true */ <GameID>.ini file will set this to true */
bool bFakeVMEM = false; bool bFakeVMEM = false;
bool bMMU = false;
// ============== // ==============
@ -348,6 +349,7 @@ bool Init()
{ {
bool wii = SConfig::GetInstance().m_LocalCoreStartupParameter.bWii; bool wii = SConfig::GetInstance().m_LocalCoreStartupParameter.bWii;
bFakeVMEM = SConfig::GetInstance().m_LocalCoreStartupParameter.iTLBHack == 1; bFakeVMEM = SConfig::GetInstance().m_LocalCoreStartupParameter.iTLBHack == 1;
bMMU = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU;
u32 flags = 0; u32 flags = 0;
if (wii) flags |= MV_WII_ONLY; if (wii) flags |= MV_WII_ONLY;
@ -416,28 +418,37 @@ u32 Read_Instruction(const u32 em_address)
return inst.hex; return inst.hex;
} }
u32 Read_Opcode_JIT(const u32 _Address) u32 Read_Opcode_JIT(u32 _Address)
{ {
#ifdef FAST_ICACHE #ifdef FAST_ICACHE
if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && if (bMMU && !bFakeVMEM && (_Address >> 28) == 0x7)
(_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{ {
PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); _Address = Memory::TranslateAddress(_Address, Memory::XCheckTLBFlag::FLAG_OPCODE);
return 0; if (_Address == 0)
{
return 0;
}
} }
u32 inst = Read_Opcode(_Address); u32 inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
#else #else
u32 inst = Memory::ReadUnchecked_U32(_Address); u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif #endif
// if a crash occured after that message // 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 // this could happen if a game forgot to icbi the new code
#if defined(_DEBUG) || defined(DEBUGFAST) #if defined(_DEBUG) || defined(DEBUGFAST)
u32 inst_mem = Memory::ReadUnchecked_U32(_Address); u32 inst_mem = Memory::ReadUnchecked_U32(_Address);
if (inst_mem != inst) if (inst_mem != inst)
ERROR_LOG(POWERPC, "JIT: compiling outdated code. addr=%x, mem=%x, cache=%x", _Address, 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 #endif
return inst; return inst;
} }
@ -451,6 +462,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address)
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{ {
PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
ERROR_LOG(MEMMAP, "iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0; return 0;
} }
u8* iCache; u8* iCache;
@ -505,132 +517,14 @@ void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
#endif #endif
} }
void GenerateISIException_JIT(u32 _EffectiveAddress)
// =======================================================
/* 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)
{ {
switch (_Address >> 24) GenerateISIException(_EffectiveAddress);
{
case 0x00:
case 0x01:
case 0x80:
case 0x81:
case 0xC0:
case 0xC1:
return true;
case 0x10: // Remove the invalid instruction from the icache, forcing a recompile
case 0x11: Write_Opcode_JIT(_EffectiveAddress, JIT_ICACHE_INVALID_WORD);
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;
} }
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) void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
{ {
memcpy(GetPointer(_Address), _pData, _iSize); memcpy(GetPointer(_Address), _pData, _iSize);
@ -709,7 +603,6 @@ void GetString(std::string& _string, const u32 em_address)
_string = stringBuffer; _string = stringBuffer;
} }
// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit // 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. // programs don't have problems directly addressing any part of memory.
u8 *GetPointer(const u32 _Address) u8 *GetPointer(const u32 _Address)
@ -743,7 +636,10 @@ u8 *GetPointer(const u32 _Address)
case 0x7E: case 0x7E:
case 0x7F: 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: case 0xE0:
if (_Address < (0xE0000000 + L1_CACHE_SIZE)) if (_Address < (0xE0000000 + L1_CACHE_SIZE))

View File

@ -51,7 +51,7 @@ namespace Memory
// so be sure to load it into a 64-bit register. // so be sure to load it into a 64-bit register.
extern u8 *base; 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_pRAM;
extern u8 *m_pEXRAM; extern u8 *m_pEXRAM;
extern u8 *m_pL1Cache; extern u8 *m_pL1Cache;
@ -169,11 +169,15 @@ enum XCheckTLBFlag
FLAG_WRITE, FLAG_WRITE,
FLAG_OPCODE, FLAG_OPCODE,
}; };
u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag); u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag);
u32 TranslateBlockAddress(u32 _Address); 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_base;
extern u32 pagetable_hashmask; extern u32 pagetable_hashmask;
}; };
#endif #endif

View File

@ -185,10 +185,6 @@ inline void ReadFromHardware(T &_var, u32 em_address, u32 effective_address, Mem
{ {
_var = bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK])); _var = bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK]));
} }
else if (em_address >= 0xE0000000)
{
PanicAlert("READ: Invalid address: %08x", em_address);
}
else if (bFakeVMEM && ((em_address &0xF0000000) == 0x70000000)) else if (bFakeVMEM && ((em_address &0xF0000000) == 0x70000000))
{ {
// fake VMEM // fake VMEM
@ -197,30 +193,29 @@ inline void ReadFromHardware(T &_var, u32 em_address, u32 effective_address, Mem
else else
{ {
// MMU // MMU
u32 tlb_addr = TranslateBlockAddress(em_address); u32 tlb_addr = TranslateAddress(em_address, flag);
if (tlb_addr == 0) if (tlb_addr == 0)
{ {
tlb_addr = TranslatePageAddress(em_address, flag); if (flag == FLAG_READ)
if (tlb_addr != 0) {
_var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK])); GenerateDSIException(em_address, false);
else }
PanicAlert("READ: Invalid address: %08x", em_address);
} }
else else
{
_var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK])); _var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK]));
}
} }
// Debugging: CheckForBadAddresses##_type(em_address, _var, true);
} }
template <typename T> template <typename T>
inline void WriteToHardware(u32 em_address, const T data, u32 effective_address, Memory::XCheckTLBFlag flag) inline void WriteToHardware(u32 em_address, const T data, u32 effective_address, Memory::XCheckTLBFlag flag)
{ {
// Debugging: CheckForBadAddresses##_type(em_address, data, false);
// First, let's check for FIFO writes, since they are probably the most common // First, let's check for FIFO writes, since they are probably the most common
// reason we end up in this function: // reason we end up in this function:
if (em_address == 0xCC008000) { if (em_address == 0xCC008000)
{
switch (sizeof(T)) { switch (sizeof(T)) {
case 1: GPFifo::Write8((u8)data, em_address); return; case 1: GPFifo::Write8((u8)data, em_address); return;
case 2: GPFifo::Write16((u16)data, em_address); return; case 2: GPFifo::Write16((u16)data, em_address); return;
@ -243,22 +238,26 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
} }
return; return;
} }
else if (em_address <= 0xcc009000) { else if (em_address <= 0xcc009000)
{
hwWrite(data, em_address); hwWrite(data, em_address);
return; return;
} }
/* WIIMODE */ /* WIIMODE */
else if (((em_address & 0xFF000000) == 0xCD000000) && else if (((em_address & 0xFF000000) == 0xCD000000) &&
(em_address <= 0xcd009000)) { (em_address <= 0xcd009000))
{
hwWriteWii(data,em_address); hwWriteWii(data,em_address);
return; return;
} }
else if (((em_address & 0xFFF00000) == 0xCD800000) && else if (((em_address & 0xFFF00000) == 0xCD800000) &&
(em_address <= 0xCD809000)) { (em_address <= 0xCD809000))
{
hwWriteIOBridge(data,em_address); hwWriteIOBridge(data,em_address);
return; return;
} }
else { else
{
ERROR_LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", em_address, data, PC); ERROR_LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", em_address, data, PC);
_dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", em_address); _dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", em_address);
} }
@ -268,6 +267,11 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
((em_address & 0xF0000000) == 0x00000000)) ((em_address & 0xF0000000) == 0x00000000))
{ {
*(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data); *(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data);
// Required for games with self modifying code (e.g. Monster House)
if (Core::g_CoreStartupParameter.bMMU)
Write_Opcode_JIT(em_address, 0x14141414);
return; return;
} }
else if (((em_address & 0xF0000000) == 0x90000000) || else if (((em_address & 0xF0000000) == 0x90000000) ||
@ -282,11 +286,6 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
*(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data); *(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data);
return; return;
} }
else if (em_address >= 0xE0000000)
{
ERROR_LOG(MEMMAP,"WRITE: Cache address out of bounds (addr: %08x data: %08x)", em_address, data);
/* PanicAlert("WRITE: Cache address %08x out of bounds", em_address); */
}
else if (bFakeVMEM && ((em_address &0xF0000000) == 0x70000000)) else if (bFakeVMEM && ((em_address &0xF0000000) == 0x70000000))
{ {
// fake VMEM // fake VMEM
@ -295,18 +294,18 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
else else
{ {
// MMU // MMU
u32 tlb_addr = TranslateBlockAddress(em_address); u32 tlb_addr = TranslateAddress(em_address, flag);
if (tlb_addr == 0) if (tlb_addr == 0)
{ {
tlb_addr = TranslatePageAddress(em_address, flag); if (flag == FLAG_WRITE)
if (tlb_addr != 0) {
*(T*)&m_pRAM[tlb_addr & RAM_MASK] = bswap(data); GenerateDSIException(em_address, true);
else }
PanicAlert("WRITE: Invalid address: %08x", em_address);
} }
else else
{
*(T*)&m_pRAM[tlb_addr & RAM_MASK] = bswap(data); *(T*)&m_pRAM[tlb_addr & RAM_MASK] = bswap(data);
}
} }
} }
// ===================== // =====================
@ -316,7 +315,7 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
/* These functions are primarily called by the Interpreter functions and are routed to the correct /* These functions are primarily called by the Interpreter functions and are routed to the correct
location through ReadFromHardware and WriteToHardware */ location through ReadFromHardware and WriteToHardware */
// ---------------- // ----------------
u32 Read_Opcode(const u32 _Address) u32 Read_Opcode(u32 _Address)
{ {
if (_Address == 0x00000000) if (_Address == 0x00000000)
{ {
@ -325,9 +324,19 @@ u32 Read_Opcode(const u32 _Address)
return 0x00000000; return 0x00000000;
} }
/*u32 _var = 0; if (Core::g_CoreStartupParameter.bMMU && (_Address >> 28) == 0x7)
ReadFromHardware<u32>(_var, _Address, _Address, FLAG_OPCODE); {
return _var;*/ // TODO: Check for MSR instruction address translation flag before translating
u32 tlb_addr = Memory::TranslateAddress(_Address, Memory::XCheckTLBFlag::FLAG_OPCODE);
if (tlb_addr == 0)
{
GenerateISIException(_Address);
return 0;
}
else
_Address = tlb_addr;
}
return PowerPC::ppcState.iCache.ReadInstruction(_Address); return PowerPC::ppcState.iCache.ReadInstruction(_Address);
} }
@ -587,40 +596,25 @@ union UPTE2
u32 pagetable_base = 0; u32 pagetable_base = 0;
u32 pagetable_hashmask = 0; u32 pagetable_hashmask = 0;
void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite) void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
{ {
if (_bWrite) if (_bWrite)
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE;
else else
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE; PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE;
PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAdress; PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAddress;
INFO_LOG(MEMMAP, "Generate DSI Exception 0x%08x", _EffectiveAdress);
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
} }
void GenerateISIException() void GenerateISIException(u32 _EffectiveAddress)
{ {
// shuffle2: ISI exception doesn't modify DSISR at all, to my knowledge... // Address of instruction could not be translated
//PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000; // maybe this was a typo for PPC_EXC_DSISR_PAGE? SRR1 = (1 << 30) | (MSR & 0x3fffff);
NPC = _EffectiveAddress;
// Instead, it modifies bits 1-4 in SRR1 depending on conditions:
// Bit 1: set if the translation of an attempted access is not found in the primary hash table entry group
// (HTEG), or in the rehashed secondary HTEG, or in the range of a IBAT register (page fault
// condition); otherwise cleared.
// Bit 2: cleared
// Bit 3: Set if the fetch access occurs to a direct-store segment (SR[T] = 1), to a noexecute
// segment (N bit set in segment descriptor), or to guarded memory
// when MSR[IR] = 1. Otherwise, cleared.
// Bit 4: Set if a memory access is not permitted by the page or IBAT protection
// mechanism, described in Chapter 7, "Memory Management" otherwise cleared.
// Only one of 1,3, or 4 may be set at a time
// For now let's just say that hash lookup failed
SRR1 = 0x10000000;
INFO_LOG(MEMMAP, "Generate ISI Exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
} }
@ -650,17 +644,166 @@ void SDRUpdated()
pagetable_hashmask = ((xx<<10)|0x3ff); pagetable_hashmask = ((xx<<10)|0x3ff);
} }
// Page Address Translation
u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) // TLB cache
//#define FAST_TLB_CACHE
#define TLB_SIZE 128
#define TLB_WAYS 2
#define NUM_TLBS 2
#define PAGE_SIZE 4096
#define PAGE_INDEX_SHIFT 12
#define PAGE_INDEX_MASK 0x3f
#define PAGE_TAG_SHIFT 18
#define TLB_FLAG_MOST_RECENT 0x01
#define TLB_FLAG_INVALID 0x02
typedef struct tlb_entry
{ {
// TLB cache u32 tag;
for (int i = 0; i < 16; i++) { u32 paddr;
if ((_Address & ~0xfff) == (PowerPC::ppcState.tlb_va[(PowerPC::ppcState.tlb_last + i) & 15])) { u8 flags;
u32 result = PowerPC::ppcState.tlb_pa[(PowerPC::ppcState.tlb_last + i) & 15] | (_Address & 0xfff); } tlb_entry;
PowerPC::ppcState.tlb_last = i;
return result; tlb_entry tlb[NUM_TLBS][TLB_SIZE/TLB_WAYS][TLB_WAYS];
u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr)
{
#ifdef FAST_TLB_CACHE
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
if(tlbe[0].tag == (vpa & ~0xfff) && !(tlbe[0].flags & TLB_FLAG_INVALID))
{
tlbe[0].flags |= TLB_FLAG_MOST_RECENT;
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
*paddr = tlbe[0].paddr | (vpa & 0xfff);
return 1;
}
if(tlbe[1].tag == (vpa & ~0xfff) && !(tlbe[1].flags & TLB_FLAG_INVALID))
{
tlbe[1].flags |= TLB_FLAG_MOST_RECENT;
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
*paddr = tlbe[1].paddr | (vpa & 0xfff);
return 1;
}
return 0;
#else
u32 _Address = vpa;
if (_Flag == FLAG_OPCODE)
{
for (int i = (PowerPC::ppcState.itlb_last); i > (PowerPC::ppcState.itlb_last - 128); i--)
{
if ((_Address & ~0xfff) == (PowerPC::ppcState.itlb_va[i & 127]))
{
u32 result = PowerPC::ppcState.itlb_pa[i & 127] | (_Address & 0xfff);
PowerPC::ppcState.itlb_last = i;
paddr = &result;
return 1;
}
} }
} }
else
{
for (int i = (PowerPC::ppcState.dtlb_last); i > (PowerPC::ppcState.dtlb_last - 128); i--)
{
if ((_Address & ~0xfff) == (PowerPC::ppcState.dtlb_va[i & 127]))
{
u32 result = PowerPC::ppcState.dtlb_pa[i & 127] | (_Address & 0xfff);
PowerPC::ppcState.dtlb_last = i;
paddr = &result;
return 1;
}
}
}
return 0;
#endif
}
void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
{
#ifdef FAST_TLB_CACHE
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
if((tlbe[0].flags & TLB_FLAG_MOST_RECENT) == 0)
{
tlbe[0].flags = TLB_FLAG_MOST_RECENT;
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[0].paddr = PTE2.RPN << PAGE_INDEX_SHIFT;
tlbe[0].tag = vpa & ~0xfff;
}
else
{
tlbe[1].flags = TLB_FLAG_MOST_RECENT;
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[1].paddr = PTE2.RPN << PAGE_INDEX_SHIFT;
tlbe[1].tag = vpa & ~0xfff;
}
#else
if (_Flag == FLAG_OPCODE)
{
// ITLB cache
PowerPC::ppcState.itlb_last++;
PowerPC::ppcState.itlb_last &= 127;
PowerPC::ppcState.itlb_pa[PowerPC::ppcState.itlb_last] = PTE2.RPN << PAGE_INDEX_SHIFT;
PowerPC::ppcState.itlb_va[PowerPC::ppcState.itlb_last] = vpa & ~0xfff;
}
else
{
// DTLB cache
PowerPC::ppcState.dtlb_last++;
PowerPC::ppcState.dtlb_last &= 127;
PowerPC::ppcState.dtlb_pa[PowerPC::ppcState.dtlb_last] = PTE2.RPN << PAGE_INDEX_SHIFT;
PowerPC::ppcState.dtlb_va[PowerPC::ppcState.dtlb_last] = vpa & ~0xfff;
}
#endif
}
void InvalidateTLBEntry(u32 vpa)
{
#ifdef FAST_TLB_CACHE
tlb_entry *tlbe = tlb[0][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
if(tlbe[0].tag == (vpa & ~0xfff))
{
tlbe[0].flags |= TLB_FLAG_INVALID;
}
if(tlbe[1].tag == (vpa & ~0xfff))
{
tlbe[1].flags |= TLB_FLAG_INVALID;
}
tlb_entry *tlbe_i = tlb[1][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
if(tlbe_i[0].tag == (vpa & ~0xfff))
{
tlbe_i[0].flags |= TLB_FLAG_INVALID;
}
if(tlbe_i[1].tag == (vpa & ~0xfff))
{
tlbe_i[1].flags |= TLB_FLAG_INVALID;
}
#else
u32 _Address = vpa;
for (int i = 0; i < 128; i++)
{
if ((_Address & ~0xfff) == (PowerPC::ppcState.dtlb_va[(PowerPC::ppcState.dtlb_last + i) & 127]))
{
PowerPC::ppcState.dtlb_pa[(PowerPC::ppcState.dtlb_last + i) & 127] = 0;
PowerPC::ppcState.dtlb_va[(PowerPC::ppcState.dtlb_last + i) & 127] = 0;
}
if ((_Address & ~0xfff) == (PowerPC::ppcState.itlb_va[(PowerPC::ppcState.itlb_last + i) & 127]))
{
PowerPC::ppcState.itlb_pa[(PowerPC::ppcState.itlb_last + i) & 127] = 0;
PowerPC::ppcState.itlb_va[(PowerPC::ppcState.itlb_last + i) & 127] = 0;
}
}
#endif
}
// Page Address Translation
u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
{
// TLB cache
u32 translatedAddress = 0;
if (LookupTLBPageAddress(_Flag, _Address, &translatedAddress))
return translatedAddress;
u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)]; u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)];
@ -673,7 +816,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
// hash function no 1 "xor" .360 // hash function no 1 "xor" .360
u32 hash1 = (VSID ^ page_index); u32 hash1 = (VSID ^ page_index);
u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; u32 pteg_addr = ((hash1 & pagetable_hashmask) << 6) | pagetable_base;
// hash1 // hash1
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
@ -688,11 +831,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
UPTE2 PTE2; UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
// TLB cache UpdateTLBEntry(_Flag, PTE2, _Address);
PowerPC::ppcState.tlb_last++;
PowerPC::ppcState.tlb_last &= 15;
PowerPC::ppcState.tlb_pa[PowerPC::ppcState.tlb_last] = PTE2.RPN << 12;
PowerPC::ppcState.tlb_va[PowerPC::ppcState.tlb_last] = _Address & ~0xfff;
// set the access bits // set the access bits
switch (_Flag) switch (_Flag)
@ -712,7 +851,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
// hash function no 2 "not" .360 // hash function no 2 "not" .360
hash1 = ~hash1; hash1 = ~hash1;
pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; pteg_addr = ((hash1 & pagetable_hashmask) << 6) | pagetable_base;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]); u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
@ -723,11 +862,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
UPTE2 PTE2; UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
// TLB cache UpdateTLBEntry(_Flag, PTE2, _Address);
PowerPC::ppcState.tlb_last++;
PowerPC::ppcState.tlb_last &= 15;
PowerPC::ppcState.tlb_pa[PowerPC::ppcState.tlb_last] = PTE2.RPN << 12;
PowerPC::ppcState.tlb_va[PowerPC::ppcState.tlb_last] = _Address & ~0xfff;
switch (_Flag) switch (_Flag)
{ {
@ -743,27 +878,6 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
} }
pteg_addr+=8; pteg_addr+=8;
} }
// If we got this far something went wrong and we save the exception data
switch(_Flag)
{
case FLAG_NO_EXCEPTION:
break;
case FLAG_READ:
GenerateDSIException(_Address, false);
break;
case FLAG_WRITE:
GenerateDSIException(_Address, true);
break;
case FLAG_OPCODE:
GenerateISIException();
break;
}
return 0; return 0;
} }
@ -778,53 +892,78 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag)
#define BAT_EA_4(v) ((v)&0xf0000000) #define BAT_EA_4(v) ((v)&0xf0000000)
// Block Address Translation // Block Address Translation
u32 TranslateBlockAddress(u32 addr) u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag)
{ {
u32 result = 0; u32 result = 0;
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
// TODO: Check for enhanced mode before switching to Wii mode
int bats = Core::g_CoreStartupParameter.bWii?8:4; int bats = Core::g_CoreStartupParameter.bWii?8:4;
for (int i = 0; i < bats; i++) { for (int i = 0; i < bats; i++) {
u32 bl17 = ~(BATU_BL(PowerPC::ppcState.spr[SPR_DBAT0U + i * 2])<<17); if (_Flag != FLAG_OPCODE)
u32 addr2 = addr & (bl17 | 0xf001ffff); {
u32 batu = (m_MSR.PR ? BATU_Vp : BATU_Vs); u32 bl17 = ~(BATU_BL(PowerPC::ppcState.spr[SPR_DBAT0U + i * 2]) << 17);
u32 addr2 = addr & (bl17 | 0xf001ffff);
u32 batu = (m_MSR.PR ? BATU_Vp : BATU_Vs);
if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_DBAT0U + i * 2])) { if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_DBAT0U + i * 2]))
// bat applies to this address {
if (PowerPC::ppcState.spr[SPR_DBAT0U + i * 2] & batu) { // bat applies to this address
// bat entry valid if (PowerPC::ppcState.spr[SPR_DBAT0U + i * 2] & batu)
u32 offset = BAT_EA_OFFSET(addr); {
u32 page = BAT_EA_11(addr); // bat entry valid
page &= ~bl17; u32 offset = BAT_EA_OFFSET(addr);
page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_DBAT0L + i * 2]); u32 page = BAT_EA_11(addr);
// fixme: check access rights page &= ~bl17;
result = page | offset; page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_DBAT0L + i * 2]);
return result; // fixme: check access rights
result = page | offset;
return result;
}
} }
} }
else
{
u32 bl17 = ~(BATU_BL(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2]) << 17);
u32 addr2 = addr & (bl17 | 0xf001ffff);
u32 batu = (m_MSR.PR ? BATU_Vp : BATU_Vs);
bl17 = ~(BATU_BL(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2])<<17); if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2]))
addr2 = addr & (bl17 | 0xf001ffff); {
batu = (m_MSR.PR ? BATU_Vp : BATU_Vs); // bat applies to this address
if (PowerPC::ppcState.spr[SPR_IBAT0U + i * 2] & batu)
if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2])) { {
// bat applies to this address // bat entry valid
if (PowerPC::ppcState.spr[SPR_IBAT0U + i * 2] & batu) { u32 offset = BAT_EA_OFFSET(addr);
// bat entry valid u32 page = BAT_EA_11(addr);
u32 offset = BAT_EA_OFFSET(addr); page &= ~bl17;
u32 page = BAT_EA_11(addr); page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_IBAT0L + i * 2]);
page &= ~bl17; // fixme: check access rights
page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_IBAT0L + i * 2]); result = page | offset;
// fixme: check access rights return result;
result = page | offset; }
return result;
} }
} }
} }
return 0; return 0;
} }
u32 TranslateAddress(const u32 _Address, const XCheckTLBFlag _Flag)
{
// TODO: Check for MSR data/instruction address translation flag before translating
u32 tlb_addr = TranslateBlockAddress(_Address, _Flag);
if (tlb_addr == 0)
{
tlb_addr = TranslatePageAddress(_Address, _Flag);
if (tlb_addr != 0)
{
return tlb_addr;
}
}
else
return tlb_addr;
return 0;
}
} // namespace } // namespace

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", "CPUOnThread", &StartUp.bCPUThread, StartUp.bCPUThread);
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF); 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); game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
// Wii settings // Wii settings
if (StartUp.bWii) if (StartUp.bWii)

View File

@ -84,30 +84,52 @@ void SingleStepInner(void)
NPC = PC + sizeof(UGeckoInstruction); NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = Memory::Read_Opcode(PC); instCode.hex = Memory::Read_Opcode(PC);
UReg_MSR& msr = (UReg_MSR&)MSR; if (instCode.hex != 0)
if (msr.FP) //If FPU is enabled, just execute
m_opTable[instCode.OPCD](instCode);
else
{ {
// check if we have to generate a FPU unavailable exception UReg_MSR& msr = (UReg_MSR&)MSR;
if (!PPCTables::UsesFPU(instCode)) if (msr.FP) //If FPU is enabled, just execute
{
m_opTable[instCode.OPCD](instCode); m_opTable[instCode.OPCD](instCode);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PowerPC::CheckExceptions();
m_EndBlock = true;
}
}
else else
{ {
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; // check if we have to generate a FPU unavailable exception
PowerPC::CheckExceptions(); if (!PPCTables::UsesFPU(instCode))
m_EndBlock = true; {
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; last_pc = PC;
PC = NPC; PC = NPC;
#if defined(_DEBUG) || defined(DEBUGFAST)
if (PowerPC::ppcState.gpr[1] == 0) if (PowerPC::ppcState.gpr[1] == 0)
{ {
printf("%i Corrupt stack", PowerPC::ppcState.DebugCount); printf("%i Corrupt stack", PowerPC::ppcState.DebugCount);
} }
#if defined(_DEBUG) || defined(DEBUGFAST)
PowerPC::ppcState.DebugCount++; PowerPC::ppcState.DebugCount++;
#endif #endif
patches(); patches();
@ -224,11 +246,15 @@ void Run()
void unknown_instruction(UGeckoInstruction _inst) void unknown_instruction(UGeckoInstruction _inst)
{ {
char disasm[256]; if (_inst.hex != 0)
DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256); {
printf("Last PC = %08x : %s\n", last_pc, disasm); char disasm[256];
Dolphin_Debugger::PrintCallstack(); DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256);
_dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); 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 } // namespace

View File

@ -58,100 +58,148 @@ u32 Helper_Get_EA_UX(const UGeckoInstruction _inst)
void lbz(UGeckoInstruction _inst) void lbz(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)Memory::Read_U8(Helper_Get_EA(_inst)); u32 temp = (u32)Memory::Read_U8(Helper_Get_EA(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
m_GPR[_inst.RD] = temp;
} }
void lbzu(UGeckoInstruction _inst) void lbzu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
m_GPR[_inst.RD] = (u32)Memory::Read_U8(uAddress); u32 temp = (u32)Memory::Read_U8(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lfd(UGeckoInstruction _inst) void lfd(UGeckoInstruction _inst)
{ {
riPS0(_inst.FD) = Memory::Read_U64(Helper_Get_EA(_inst)); u64 temp = Memory::Read_U64(Helper_Get_EA(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
riPS0(_inst.FD) = temp;
} }
void lfdu(UGeckoInstruction _inst) void lfdu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
riPS0(_inst.FD) = Memory::Read_U64(uAddress); u64 temp = Memory::Read_U64(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
riPS0(_inst.FD) = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lfdux(UGeckoInstruction _inst) void lfdux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
riPS0(_inst.FD) = Memory::Read_U64(uAddress); u64 temp = Memory::Read_U64(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
riPS0(_inst.FD) = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lfdx(UGeckoInstruction _inst) void lfdx(UGeckoInstruction _inst)
{ {
riPS0(_inst.FD) = Memory::Read_U64(Helper_Get_EA_X(_inst)); u64 temp = Memory::Read_U64(Helper_Get_EA_X(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
riPS0(_inst.FD) = temp;
} }
void lfs(UGeckoInstruction _inst) void lfs(UGeckoInstruction _inst)
{ {
u32 uTemp = Memory::Read_U32(Helper_Get_EA(_inst)); u32 uTemp = Memory::Read_U32(Helper_Get_EA(_inst));
double value = *(float*)&uTemp; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS0(_inst.FD) = value; {
rPS1(_inst.FD) = value; double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
}
} }
void lfsu(UGeckoInstruction _inst) void lfsu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
u32 uTemp = Memory::Read_U32(uAddress); u32 uTemp = Memory::Read_U32(uAddress);
double value = *(float*)&uTemp; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS0(_inst.FD) = value; {
rPS1(_inst.FD) = value; double value = *(float*)&uTemp;
m_GPR[_inst.RA] = uAddress; rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
m_GPR[_inst.RA] = uAddress;
}
} }
void lfsux(UGeckoInstruction _inst) void lfsux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
u32 uTemp = Memory::Read_U32(uAddress); u32 uTemp = Memory::Read_U32(uAddress);
double value = *(float*)&uTemp; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS0(_inst.FD) = value; {
rPS1(_inst.FD) = value; double value = *(float*)&uTemp;
m_GPR[_inst.RA] = uAddress; rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
m_GPR[_inst.RA] = uAddress;
}
} }
void lfsx(UGeckoInstruction _inst) void lfsx(UGeckoInstruction _inst)
{ {
u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst)); u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst));
double value = *(float*)&uTemp; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
rPS0(_inst.FD) = value; {
rPS1(_inst.FD) = value; double value = *(float*)&uTemp;
rPS0(_inst.FD) = value;
rPS1(_inst.FD) = value;
}
} }
void lha(UGeckoInstruction _inst) void lha(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)(s32)(s16)Memory::Read_U16(Helper_Get_EA(_inst)); u32 temp = (u32)(s32)(s16)Memory::Read_U16(Helper_Get_EA(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lhau(UGeckoInstruction _inst) void lhau(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
m_GPR[_inst.RD] = (u32)(s32)(s16)Memory::Read_U16(uAddress); u32 temp = (u32)(s32)(s16)Memory::Read_U16(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lhz(UGeckoInstruction _inst) void lhz(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)(u16)Memory::Read_U16(Helper_Get_EA(_inst)); u32 temp = (u32)(u16)Memory::Read_U16(Helper_Get_EA(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lhzu(UGeckoInstruction _inst) void lhzu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
m_GPR[_inst.RD] = (u32)(u16)Memory::Read_U16(uAddress); u32 temp = (u32)(u16)Memory::Read_U16(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
// FIXME: lmw should do a total rollback if a DSI occurs
void lmw(UGeckoInstruction _inst) void lmw(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA(_inst); u32 uAddress = Helper_Get_EA(_inst);
@ -160,14 +208,18 @@ void lmw(UGeckoInstruction _inst)
u32 TempReg = Memory::Read_U32(uAddress); u32 TempReg = Memory::Read_U32(uAddress);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{ {
PanicAlert("DSI exception in lmv."); PanicAlert("DSI exception in lmw");
NOTICE_LOG(POWERPC, "DSI exception in lmw");
return; return;
} }
else
m_GPR[iReg] = TempReg; {
m_GPR[iReg] = TempReg;
}
} }
} }
// FIXME: stmw should do a total rollback if a DSI occurs
void stmw(UGeckoInstruction _inst) void stmw(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA(_inst); u32 uAddress = Helper_Get_EA(_inst);
@ -175,14 +227,22 @@ void stmw(UGeckoInstruction _inst)
{ {
Memory::Write_U32(m_GPR[iReg], uAddress); Memory::Write_U32(m_GPR[iReg], uAddress);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
PanicAlert("DSI exception in stmw");
NOTICE_LOG(POWERPC, "DSI exception in stmw");
return; return;
}
} }
} }
void lwz(UGeckoInstruction _inst) void lwz(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA(_inst); u32 uAddress = Helper_Get_EA(_inst);
m_GPR[_inst.RD] = Memory::Read_U32(uAddress); u32 temp = Memory::Read_U32(uAddress);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
// hack to detect SelectThread loop // hack to detect SelectThread loop
// should probably run a pass through memory instead before execution // should probably run a pass through memory instead before execution
@ -204,8 +264,12 @@ void lwz(UGeckoInstruction _inst)
void lwzu(UGeckoInstruction _inst) void lwzu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
m_GPR[_inst.RD] = Memory::Read_U32(uAddress); u32 temp = Memory::Read_U32(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void stb(UGeckoInstruction _inst) void stb(UGeckoInstruction _inst)
@ -217,7 +281,10 @@ void stbu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
Memory::Write_U8((u8)m_GPR[_inst.RS], uAddress); Memory::Write_U8((u8)m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stfd(UGeckoInstruction _inst) void stfd(UGeckoInstruction _inst)
@ -229,7 +296,10 @@ void stfdu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
Memory::Write_U64(riPS0(_inst.FS), uAddress); Memory::Write_U64(riPS0(_inst.FS), uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stfs(UGeckoInstruction _inst) void stfs(UGeckoInstruction _inst)
@ -244,7 +314,10 @@ void stfsu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void sth(UGeckoInstruction _inst) void sth(UGeckoInstruction _inst)
@ -256,7 +329,10 @@ void sthu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
Memory::Write_U16((u16)m_GPR[_inst.RS], uAddress); Memory::Write_U16((u16)m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stw(UGeckoInstruction _inst) void stw(UGeckoInstruction _inst)
@ -268,7 +344,10 @@ void stwu(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_U(_inst); u32 uAddress = Helper_Get_EA_U(_inst);
Memory::Write_U32(m_GPR[_inst.RS], uAddress); Memory::Write_U32(m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void dcba(UGeckoInstruction _inst) void dcba(UGeckoInstruction _inst)
@ -315,7 +394,8 @@ void dcbtst(UGeckoInstruction _inst)
void dcbz(UGeckoInstruction _inst) void dcbz(UGeckoInstruction _inst)
{ {
// HACK but works... we think // HACK but works... we think
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32); if (!Core::g_CoreStartupParameter.bMMU)
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32); // Breaks Rogue Leader, fixes Super Mario Sunshine
} }
// eciwx/ecowx technically should access the specified device // eciwx/ecowx technically should access the specified device
@ -330,7 +410,9 @@ void eciwx(UGeckoInstruction _inst)
EA = b + m_GPR[_inst.RB]; EA = b + m_GPR[_inst.RB];
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
}
if (EA & 3) if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT;
@ -350,7 +432,9 @@ void ecowx(UGeckoInstruction _inst)
EA = b + m_GPR[_inst.RB]; EA = b + m_GPR[_inst.RB];
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
}
if (EA & 3) if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT;
@ -378,42 +462,70 @@ void icbi(UGeckoInstruction _inst)
void lbzux(UGeckoInstruction _inst) void lbzux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
m_GPR[_inst.RD] = (u32)Memory::Read_U8(uAddress); u32 temp = (u32)Memory::Read_U8(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lbzx(UGeckoInstruction _inst) void lbzx(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)Memory::Read_U8(Helper_Get_EA_X(_inst)); u32 temp = (u32)Memory::Read_U8(Helper_Get_EA_X(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lhaux(UGeckoInstruction _inst) void lhaux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
m_GPR[_inst.RD] = (s32)(s16)Memory::Read_U16(uAddress); s32 temp = (s32)(s16)Memory::Read_U16(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lhax(UGeckoInstruction _inst) void lhax(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (s32)(s16)Memory::Read_U16(Helper_Get_EA_X(_inst)); s32 temp = (s32)(s16)Memory::Read_U16(Helper_Get_EA_X(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lhbrx(UGeckoInstruction _inst) void lhbrx(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)Common::swap16(Memory::Read_U16(Helper_Get_EA_X(_inst))); u32 temp = (u32)Common::swap16(Memory::Read_U16(Helper_Get_EA_X(_inst)));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lhzux(UGeckoInstruction _inst) void lhzux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
m_GPR[_inst.RD] = (u32)Memory::Read_U16(uAddress); u32 temp = (u32)Memory::Read_U16(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lhzx(UGeckoInstruction _inst) void lhzx(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = (u32)Memory::Read_U16(Helper_Get_EA_X(_inst)); u32 temp = (u32)Memory::Read_U16(Helper_Get_EA_X(_inst));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lswx(UGeckoInstruction _inst) void lswx(UGeckoInstruction _inst)
@ -426,27 +538,42 @@ void lswx(UGeckoInstruction _inst)
void lwbrx(UGeckoInstruction _inst) void lwbrx(UGeckoInstruction _inst)
{ {
m_GPR[_inst.RD] = Common::swap32(Memory::Read_U32(Helper_Get_EA_X(_inst))); u32 temp = Common::swap32(Memory::Read_U32(Helper_Get_EA_X(_inst)));
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void lwzux(UGeckoInstruction _inst) void lwzux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
m_GPR[_inst.RD] = Memory::Read_U32(uAddress); u32 temp = Memory::Read_U32(uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
m_GPR[_inst.RA] = uAddress;
}
} }
void lwzx(UGeckoInstruction _inst) void lwzx(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_X(_inst); u32 uAddress = Helper_Get_EA_X(_inst);
m_GPR[_inst.RD] = Memory::Read_U32(uAddress); u32 temp = Memory::Read_U32(uAddress);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RD] = temp;
}
} }
void stbux(UGeckoInstruction _inst) void stbux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
Memory::Write_U8((u8)m_GPR[_inst.RS], uAddress); Memory::Write_U8((u8)m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stbx(UGeckoInstruction _inst) void stbx(UGeckoInstruction _inst)
@ -458,7 +585,10 @@ void stfdux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
Memory::Write_U64(riPS0(_inst.FS), uAddress); Memory::Write_U64(riPS0(_inst.FS), uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stfdx(UGeckoInstruction _inst) void stfdx(UGeckoInstruction _inst)
@ -482,7 +612,10 @@ void stfsux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress); Memory::Write_U32(ConvertToSingle(riPS0(_inst.FS)), uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stfsx(UGeckoInstruction _inst) void stfsx(UGeckoInstruction _inst)
@ -499,7 +632,10 @@ void sthux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
Memory::Write_U16((u16)m_GPR[_inst.RS], uAddress); Memory::Write_U16((u16)m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void sthx(UGeckoInstruction _inst) void sthx(UGeckoInstruction _inst)
@ -509,7 +645,7 @@ void sthx(UGeckoInstruction _inst)
// __________________________________________________________________________________________________ // __________________________________________________________________________________________________
// lswi - bizarro string instruction // lswi - bizarro string instruction
// // FIXME: Should rollback if a DSI occurs
void lswi(UGeckoInstruction _inst) void lswi(UGeckoInstruction _inst)
{ {
u32 EA; u32 EA;
@ -555,7 +691,7 @@ void lswi(UGeckoInstruction _inst)
// todo : optimize ? // todo : optimize ?
// __________________________________________________________________________________________________ // __________________________________________________________________________________________________
// stswi - bizarro string instruction // stswi - bizarro string instruction
// // FIXME: Should rollback if a DSI occurs
void stswi(UGeckoInstruction _inst) void stswi(UGeckoInstruction _inst)
{ {
u32 EA; u32 EA;
@ -581,7 +717,9 @@ void stswi(UGeckoInstruction _inst)
} }
Memory::Write_U8((m_GPR[r] >> (24 - i)) & 0xFF, EA); Memory::Write_U8((m_GPR[r] >> (24 - i)) & 0xFF, EA);
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return; return;
}
i += 8; i += 8;
if (i == 32) if (i == 32)
@ -612,10 +750,13 @@ void stwbrx(UGeckoInstruction _inst)
void lwarx(UGeckoInstruction _inst) void lwarx(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_X(_inst); u32 uAddress = Helper_Get_EA_X(_inst);
m_GPR[_inst.RD] = Memory::Read_U32(uAddress); u32 temp = Memory::Read_U32(uAddress);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
g_bReserve = true; {
g_reserveAddr = uAddress; m_GPR[_inst.RD] = temp;
g_bReserve = true;
g_reserveAddr = uAddress;
}
} }
void stwcxd(UGeckoInstruction _inst) void stwcxd(UGeckoInstruction _inst)
@ -626,9 +767,12 @@ void stwcxd(UGeckoInstruction _inst)
uAddress = Helper_Get_EA_X(_inst); uAddress = Helper_Get_EA_X(_inst);
if (uAddress == g_reserveAddr) { if (uAddress == g_reserveAddr) {
Memory::Write_U32(m_GPR[_inst.RS], uAddress); Memory::Write_U32(m_GPR[_inst.RS], uAddress);
g_bReserve = false; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
SetCRField(0, 2 | GetXER_SO()); {
return; g_bReserve = false;
SetCRField(0, 2 | GetXER_SO());
return;
}
} }
} }
@ -639,7 +783,10 @@ void stwux(UGeckoInstruction _inst)
{ {
u32 uAddress = Helper_Get_EA_UX(_inst); u32 uAddress = Helper_Get_EA_UX(_inst);
Memory::Write_U32(m_GPR[_inst.RS], uAddress); Memory::Write_U32(m_GPR[_inst.RS], uAddress);
m_GPR[_inst.RA] = uAddress; if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_GPR[_inst.RA] = uAddress;
}
} }
void stwx(UGeckoInstruction _inst) void stwx(UGeckoInstruction _inst)
@ -665,14 +812,7 @@ void tlbie(UGeckoInstruction _inst)
{ {
// Invalidate TLB entry // Invalidate TLB entry
u32 _Address = m_GPR[_inst.RB]; u32 _Address = m_GPR[_inst.RB];
for (int i = 0; i < 16; i++) Memory::InvalidateTLBEntry(_Address);
{
if ((_Address & ~0xfff) == (PowerPC::ppcState.tlb_va[(PowerPC::ppcState.tlb_last + i) & 15]))
{
PowerPC::ppcState.tlb_pa[(PowerPC::ppcState.tlb_last + i) & 15] = 0;
PowerPC::ppcState.tlb_va[(PowerPC::ppcState.tlb_last + i) & 15] = 0;
}
}
} }
void tlbsync(UGeckoInstruction _inst) void tlbsync(UGeckoInstruction _inst)

View File

@ -153,7 +153,6 @@ float Helper_Dequantize(const u32 _Addr, const EQuantizeType _quantizeType,
fResult = 0; fResult = 0;
break; break;
} }
return fResult; return fResult;
} }
@ -170,12 +169,23 @@ void psq_l(UGeckoInstruction _inst)
if (_inst.W == 0) if (_inst.W == 0)
{ {
rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale); float ps0 = Helper_Dequantize(EA, ldType, ldScale);
rPS1(_inst.RS) = Helper_Dequantize(EA+c, 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 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; rPS1(_inst.RS) = 1.0f;
} }
} }
@ -193,12 +203,23 @@ void psq_lu(UGeckoInstruction _inst)
if (_inst.W == 0) if (_inst.W == 0)
{ {
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); float ps0 = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, 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 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; rPS1(_inst.RS) = 1.0f;
} }
m_GPR[_inst.RA] = EA; m_GPR[_inst.RA] = EA;
@ -246,6 +267,10 @@ void psq_stu(UGeckoInstruction _inst)
{ {
Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale); Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale);
} }
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
m_GPR[_inst.RA] = EA; m_GPR[_inst.RA] = EA;
} }
@ -262,13 +287,29 @@ void psq_lx(UGeckoInstruction _inst)
if (_inst.Wx == 0) if (_inst.Wx == 0)
{ {
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); float ps0 = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, 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 else
{ {
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); float ps0 = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = 1.0f; 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) if (_inst.Wx == 0)
{ {
rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); float ps0 = Helper_Dequantize( EA, ldType, ldScale );
rPS1(_inst.RS) = Helper_Dequantize( EA+c, 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 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; rPS1(_inst.RS) = 1.0f;
} }
m_GPR[_inst.RA] = EA; m_GPR[_inst.RA] = EA;
@ -338,6 +390,10 @@ void psq_stux(UGeckoInstruction _inst)
{ {
Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale); Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale);
} }
if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI)
{
return;
}
m_GPR[_inst.RA] = EA; m_GPR[_inst.RA] = EA;
} // namespace======= } // namespace=======

View File

@ -63,40 +63,40 @@ static GekkoOPTemplate primarytable[] =
{28, Interpreter::andi_rc, {"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {46, Interpreter::lmw, {"lmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}},
{47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, {47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}},
{48, Interpreter::lfs, {"lfs", OPTYPE_LOADFP, 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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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 //missing: 0, 5, 6, 9, 22, 30, 62, 58
{0, Interpreter::unknown_instruction, {"unknown_instruction", OPTYPE_UNKNOWN, 0}}, {0, Interpreter::unknown_instruction, {"unknown_instruction", OPTYPE_UNKNOWN, 0}},
@ -151,10 +151,10 @@ static GekkoOPTemplate table4_2[] =
static GekkoOPTemplate table4_3[] = static GekkoOPTemplate table4_3[] =
{ {
{6, Interpreter::psq_lx, {"psq_lx", 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}}, {7, Interpreter::psq_stx, {"psq_stx", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
{38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU}}, {38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
{39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU}}, {39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}},
}; };
static GekkoOPTemplate table19[] = static GekkoOPTemplate table19[] =
@ -207,63 +207,63 @@ static GekkoOPTemplate table31[] =
{1014, Interpreter::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}}, {1014, Interpreter::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}},
//load word //load word
{23, Interpreter::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | 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}}, {55, Interpreter::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load halfword //load halfword
{279, Interpreter::lhzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | 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}}, {311, Interpreter::lhzux, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load halfword signextend //load halfword signextend
{343, Interpreter::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | 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}}, {375, Interpreter::lhaux, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load byte //load byte
{87, Interpreter::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | 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}}, {119, Interpreter::lbzux, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//load byte reverse //load byte reverse
{534, Interpreter::lwbrx, {"lwbrx", 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}}, {790, Interpreter::lhbrx, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}},
// Conditional load/store (Wii SMP) // Conditional load/store (Wii SMP)
{150, Interpreter::stwcxd, {"stwcxd", OPTYPE_STORE, FL_EVIL | 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}}, {20, Interpreter::lwarx, {"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE}},
//load string (Inst these) //load string (Inst these)
{533, Interpreter::lswx, {"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | 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}}, {597, Interpreter::lswi, {"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D | FL_LOADSTORE}},
//store word //store word
{151, Interpreter::stwx, {"stwx", OPTYPE_STORE, FL_IN_A0 | 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}}, {183, Interpreter::stwux, {"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store halfword //store halfword
{407, Interpreter::sthx, {"sthx", OPTYPE_STORE, FL_IN_A0 | 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}}, {439, Interpreter::sthux, {"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store byte //store byte
{215, Interpreter::stbx, {"stbx", OPTYPE_STORE, FL_IN_A0 | 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}}, {247, Interpreter::stbux, {"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}},
//store bytereverse //store bytereverse
{662, Interpreter::stwbrx, {"stwbrx", OPTYPE_STORE, FL_IN_A0 | 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}}, {918, Interpreter::sthbrx, {"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B | FL_LOADSTORE}},
{661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL}}, {661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}},
{725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL}}, {725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}},
// fp load/store // fp load/store
{535, Interpreter::lfsx, {"lfsx", OPTYPE_LOADFP, FL_IN_A0 | 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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {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}}, {19, Interpreter::mfcr, {"mfcr", OPTYPE_SYSTEM, FL_OUT_D}},
{83, Interpreter::mfmsr, {"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, {83, Interpreter::mfmsr, {"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}},

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 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 fps with this option enabled. If you suspect that this option cause problems you can also disable it from the
debugging window. */ debugging window. */
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) if (Core::g_CoreStartupParameter.bEnableDebugging)
{ {
jo.enableBlocklink = false; jo.enableBlocklink = false;
SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = false; Core::g_CoreStartupParameter.bSkipIdle = false;
} }
else else
{ {
jo.enableBlocklink = true; if (!Core::g_CoreStartupParameter.bJITBlockLinking)
{
jo.enableBlocklink = false;
}
else
jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU;
} }
#ifdef _M_X64 #ifdef _M_X64
jo.enableFastMem = SConfig::GetInstance().m_LocalCoreStartupParameter.bUseFastMem; jo.enableFastMem = Core::g_CoreStartupParameter.bUseFastMem;
#else #else
jo.enableFastMem = false; jo.enableFastMem = false;
#endif #endif
@ -194,16 +199,11 @@ void Jit64::Init()
jo.optimizeGatherPipe = true; jo.optimizeGatherPipe = true;
jo.fastInterrupts = false; jo.fastInterrupts = false;
jo.accurateSinglePrecision = true; jo.accurateSinglePrecision = true;
js.memcheck = Core::g_CoreStartupParameter.bMMU;
gpr.SetEmitter(this); gpr.SetEmitter(this);
fpr.SetEmitter(this); fpr.SetEmitter(this);
if (Core::g_CoreStartupParameter.bJITBlockLinking)
{
jo.enableBlocklink = false;
SuccessAlert("Your game was started without JIT Block Linking");
}
trampolines.Init(); trampolines.Init();
AllocCodeSpace(CODE_SIZE); AllocCodeSpace(CODE_SIZE);
@ -218,7 +218,6 @@ void Jit64::ClearCache()
ClearCodeSpace(); ClearCodeSpace();
} }
void Jit64::Shutdown() void Jit64::Shutdown()
{ {
FreeCodeSpace(); FreeCodeSpace();
@ -349,11 +348,10 @@ void Jit64::WriteRfiExitDestInEAX()
JMP(asm_routines.testExceptions, true); JMP(asm_routines.testExceptions, true);
} }
void Jit64::WriteExceptionExit(u32 exception) void Jit64::WriteExceptionExit()
{ {
Cleanup(); Cleanup();
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception)); SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount));
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
JMP(asm_routines.testExceptions, true); JMP(asm_routines.testExceptions, true);
} }
@ -361,7 +359,6 @@ void STACKALIGN Jit64::Run()
{ {
CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode;
pExecAddr(); pExecAddr();
//Will return when PowerPC::state changes
} }
void Jit64::SingleStep() void Jit64::SingleStep()
@ -370,7 +367,7 @@ void Jit64::SingleStep()
pExecAddr(); pExecAddr();
} }
void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) void Jit64::Trace()
{ {
char regs[500] = ""; char regs[500] = "";
char fregs[750] = ""; char fregs[750] = "";
@ -392,11 +389,11 @@ void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address)
strncat(fregs, reg, 750); strncat(fregs, reg, 750);
} }
#endif #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) 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)); 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) const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b)
{ {
int blockSize = code_buf->GetSize(); 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) // Comment out the following to disable breakpoints (speed-up)
blockSize = 1; blockSize = 1;
Trace(code_buf, em_address); broken_block = true;
Trace();
} }
if (em_address == 0) if (em_address == 0)
PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); 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; int size = 0;
js.isLastInstruction = false; js.isLastInstruction = false;
js.blockStart = em_address; 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, //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. //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; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
@ -465,16 +482,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
SetJumpTarget(b1); 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. // 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));
@ -498,18 +505,22 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
gpr.Start(js.gpa); gpr.Start(js.gpa);
fpr.Start(js.fpa); fpr.Start(js.fpa);
js.downcountAmount = js.st.numCycles; js.downcountAmount = 0;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) if (!Core::g_CoreStartupParameter.bEnableDebugging)
js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address); js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address);
js.skipnext = false; js.skipnext = false;
js.blockSize = size; js.blockSize = size;
js.compilerPC = nextPC;
// Translate instructions // Translate instructions
for (int i = 0; i < (int)size; i++) for (int i = 0; i < (int)size; i++)
{ {
js.compilerPC = ops[i].address; js.compilerPC = ops[i].address;
js.op = &ops[i]; js.op = &ops[i];
js.instructionNumber = i; js.instructionNumber = i;
const GekkoOPInfo *opinfo = GetOpInfo(ops[i].inst);
js.downcountAmount += (opinfo->numCyclesMinusOne + 1);
if (i == (int)size - 1) if (i == (int)size - 1)
{ {
// WARNING - cmp->branch merging will screw this up. // 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 (!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]); 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 defined(_DEBUG) || defined(DEBUGFAST)
if (gpr.SanityCheck() || fpr.SanityCheck()) if (gpr.SanityCheck() || fpr.SanityCheck())
{ {
@ -558,7 +601,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (js.cancel) if (js.cancel)
break; 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); gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL);

View File

@ -52,6 +52,16 @@
Core::g_CoreStartupParameter.bJIT##type##Off) \ Core::g_CoreStartupParameter.bJIT##type##Off) \
{Default(inst); return;} {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 class Jit64 : public JitBase
{ {
private: private:
@ -69,6 +79,8 @@ private:
int block_flags; int block_flags;
bool isLastInstruction; bool isLastInstruction;
bool memcheck;
bool broken_block;
int fifoBytesThisBlock; int fifoBytesThisBlock;
@ -105,12 +117,12 @@ public:
JitBlockCache *GetBlockCache() { return &blocks; } JitBlockCache *GetBlockCache() { return &blocks; }
void NotifyBreakpoint(u32 em_address, bool set); void NotifyBreakpoint(u32 em_address, bool set);
void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address); void Trace();
void ClearCache(); void ClearCache();
const u8 *GetDispatcher() { const u8 *GetDispatcher() {
return asm_routines.dispatcher; // asm_routines.dispatcher return asm_routines.dispatcher;
} }
const CommonAsmRoutines *GetAsmRoutines() { const CommonAsmRoutines *GetAsmRoutines() {
return &asm_routines; return &asm_routines;
@ -132,7 +144,7 @@ public:
void WriteExit(u32 destination, int exit_num); void WriteExit(u32 destination, int exit_num);
void WriteExitDestInEAX(int exit_num); void WriteExitDestInEAX(int exit_num);
void WriteExceptionExit(u32 exception); void WriteExceptionExit();
void WriteRfiExitDestInEAX(); void WriteRfiExitDestInEAX();
void WriteCallInterpreter(UGeckoInstruction _inst); void WriteCallInterpreter(UGeckoInstruction _inst);
void Cleanup(); void Cleanup();

View File

@ -389,8 +389,6 @@ void CompileInstruction(PPCAnalyst::CodeOp & op)
#endif #endif
info->compileCount++; info->compileCount++;
info->lastUse = jit->js.compilerPC; info->lastUse = jit->js.compilerPC;
} else {
PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC);
} }
} }

View File

@ -129,8 +129,6 @@ void Jit64AsmRoutineManager::Generate()
//FP blocks test for FPU available, jump here if false //FP blocks test for FPU available, jump here if false
fpException = AlignCode4(); fpException = AlignCode4();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC)); MOV(32, R(EAX), M(&NPC));

View File

@ -47,7 +47,9 @@ void Jit64::sc(UGeckoInstruction inst)
gpr.Flush(FLUSH_ALL); gpr.Flush(FLUSH_ALL);
fpr.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) void Jit64::rfi(UGeckoInstruction inst)

View File

@ -238,7 +238,8 @@ void Jit64::cmpXX(UGeckoInstruction inst)
} }
} }
if (!merge_branch) { if (!merge_branch)
{
// Keep the normal code separate for clarity. // Keep the normal code separate for clarity.
CMP(32, gpr.R(a), comparand); 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 // 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 // http://maws.mameworld.info/maws/mamesrc/src/emu/cpu/powerpc/drc_ops.c : bt, adc
} else { } else {
js.downcountAmount++;
int test_bit = 8 >> (js.next_inst.BI & 3); int test_bit = 8 >> (js.next_inst.BI & 3);
bool condition = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? false : true; bool condition = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? false : true;
CMP(32, gpr.R(a), comparand); CMP(32, gpr.R(a), comparand);

View File

@ -357,13 +357,13 @@ void JitIL::SingleStep()
pExecAddr(); pExecAddr();
} }
void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) void JitIL::Trace()
{ {
char regs[500] = ""; char regs[500] = "";
char fregs[750] = ""; char fregs[750] = "";
#ifdef JIT_LOG_GPR #ifdef JIT_LOG_GPR
for (unsigned int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
char reg[50]; char reg[50];
sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); 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 #endif
#ifdef JIT_LOG_FPR #ifdef JIT_LOG_FPR
for (unsigned int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
char reg[50]; char reg[50];
sprintf(reg, "f%02d: %016x ", i, riPS0(i)); sprintf(reg, "f%02d: %016x ", i, riPS0(i));
strncat(fregs, reg, 750); strncat(fregs, reg, 750);
} }
#endif #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) 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(); 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) if (Core::g_CoreStartupParameter.bEnableDebugging)
{ {
// Comment out the following to disable breakpoints (speed-up) // Comment out the following to disable breakpoints (speed-up)
blockSize = 1; blockSize = 1;
Trace(code_buf, em_address); Trace();
} }
if (em_address == 0) 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, //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. //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; PPCAnalyst::CodeOp *ops = code_buf->codebuffer;
const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr

View File

@ -85,7 +85,7 @@ public:
const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b); const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b);
void NotifyBreakpoint(u32 em_address, bool set); void NotifyBreakpoint(u32 em_address, bool set);
void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address); void Trace();
void ClearCache(); void ClearCache();
const u8 *GetDispatcher() { const u8 *GetDispatcher() {

View File

@ -64,6 +64,8 @@ protected:
bool isLastInstruction; bool isLastInstruction;
bool forceUnsafeLoad; bool forceUnsafeLoad;
bool memcheck;
bool broken_block;
int fifoBytesThisBlock; int fifoBytesThisBlock;

View File

@ -360,7 +360,7 @@ bool JitBlock::ContainsAddress(u32 em_address)
} }
b.invalid = true; b.invalid = true;
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode); Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD);
#else #else
if (Memory::ReadFast32(b.originalAddress) == block_num) if (Memory::ReadFast32(b.originalAddress) == block_num)
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
@ -399,7 +399,7 @@ bool JitBlock::ContainsAddress(u32 em_address)
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
// invalidate iCache. // invalidate iCache.
// icbi can be called with any address, so we sholud check // icbi can be called with any address, so we should check
if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000 && if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000 &&
(address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area (address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000) (address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000)

View File

@ -91,7 +91,10 @@ class JitBlockCache
public: public:
JitBlockCache() : JitBlockCache() :
blockCodePointers(0), blocks(0), num_blocks(0), blockCodePointers(0), blocks(0), num_blocks(0),
iCache(0), iCacheEx(0), iCacheVMEM(0), MAX_NUM_BLOCKS(0) { } #ifdef JIT_UNLIMITED_ICACHE
iCache(0), iCacheEx(0), iCacheVMEM(0),
#endif
MAX_NUM_BLOCKS(0) { }
int AllocateBlock(u32 em_address); int AllocateBlock(u32 em_address);
void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr); void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr);

View File

@ -285,7 +285,7 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
// Does not yet perform inlining - although there are plans for that. // Does not yet perform inlining - although there are plans for that.
// Returns the exit address of the next PC // Returns the exit address of the next PC
u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer, int blockSize) u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, bool &broken_block, CodeBuffer *buffer, int blockSize)
{ {
memset(st, 0, sizeof(st)); memset(st, 0, sizeof(st));
@ -296,6 +296,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Bloc
gpa->any = true; gpa->any = true;
fpa->any = false; fpa->any = false;
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
gpa->firstRead[i] = -1; gpa->firstRead[i] = -1;
@ -324,154 +325,159 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Bloc
UGeckoInstruction inst = Memory::Read_Opcode_JIT(code[i].address); UGeckoInstruction inst = Memory::Read_Opcode_JIT(code[i].address);
_assert_msg_(POWERPC, inst.hex != 0, "Zero Op - Error flattening %08x op %08x", address + i*4, inst.hex); if (inst.hex != 0)
code[i].inst = inst;
code[i].branchTo = -1;
code[i].branchToIndex = -1;
code[i].skip = false;
GekkoOPInfo *opinfo = GetOpInfo(inst);
code[i].opinfo = opinfo;
if (opinfo)
numCycles += opinfo->numCyclesMinusOne + 1;
_assert_msg_(POWERPC, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst.hex);
code[i].wantsCR0 = false;
code[i].wantsCR1 = false;
code[i].wantsPS1 = false;
int flags = opinfo->flags;
if (flags & FL_USE_FPU)
fpa->any = true;
if (flags & FL_TIMER)
gpa->anyTimer = true;
// Does the instruction output CR0?
if (flags & FL_RC_BIT)
code[i].outputCR0 = inst.hex & 1; //todo fix
else if ((flags & FL_SET_CRn) && inst.CRFD == 0)
code[i].outputCR0 = true;
else
code[i].outputCR0 = (flags & FL_SET_CR0) ? true : false;
// Does the instruction output CR1?
if (flags & FL_RC_BIT_F)
code[i].outputCR1 = inst.hex & 1; //todo fix
else if ((flags & FL_SET_CRn) && inst.CRFD == 1)
code[i].outputCR1 = true;
else
code[i].outputCR1 = (flags & FL_SET_CR1) ? true : false;
int numOut = 0;
int numIn = 0;
if (flags & FL_OUT_A)
{ {
code[i].regsOut[numOut++] = inst.RA; code[i].inst = inst;
gpa->SetOutputRegister(inst.RA, i); code[i].branchTo = -1;
} code[i].branchToIndex = -1;
if (flags & FL_OUT_D) code[i].skip = false;
{ GekkoOPInfo *opinfo = GetOpInfo(inst);
code[i].regsOut[numOut++] = inst.RD; code[i].opinfo = opinfo;
gpa->SetOutputRegister(inst.RD, i); if (opinfo)
} numCycles += opinfo->numCyclesMinusOne + 1;
if (flags & FL_OUT_S) _assert_msg_(POWERPC, opinfo != 0, "Invalid Op - Error flattening %08x op %08x", address + i*4, inst.hex);
{
code[i].regsOut[numOut++] = inst.RS;
gpa->SetOutputRegister(inst.RS, i);
}
if ((flags & FL_IN_A) || ((flags & FL_IN_A0) && inst.RA != 0))
{
code[i].regsIn[numIn++] = inst.RA;
gpa->SetInputRegister(inst.RA, i);
}
if (flags & FL_IN_B)
{
code[i].regsIn[numIn++] = inst.RB;
gpa->SetInputRegister(inst.RB, i);
}
if (flags & FL_IN_C)
{
code[i].regsIn[numIn++] = inst.RC;
gpa->SetInputRegister(inst.RC, i);
}
if (flags & FL_IN_S)
{
code[i].regsIn[numIn++] = inst.RS;
gpa->SetInputRegister(inst.RS, i);
}
// Set remaining register slots as unused (-1) code[i].wantsCR0 = false;
for (int j = numIn; j < 3; j++) code[i].wantsCR1 = false;
code[i].regsIn[j] = -1; code[i].wantsPS1 = false;
for (int j = numOut; j < 2; j++)
code[i].regsOut[j] = -1;
for (int j = 0; j < 3; j++)
code[i].fregsIn[j] = -1;
code[i].fregOut = -1;
switch (opinfo->type) int flags = opinfo->flags;
{
case OPTYPE_INTEGER: if (flags & FL_USE_FPU)
case OPTYPE_LOAD: fpa->any = true;
case OPTYPE_STORE:
break; if (flags & FL_TIMER)
case OPTYPE_FPU: gpa->anyTimer = true;
break;
case OPTYPE_LOADFP: // Does the instruction output CR0?
break; if (flags & FL_RC_BIT)
case OPTYPE_BRANCH: code[i].outputCR0 = inst.hex & 1; //todo fix
if (code[i].inst.hex == 0x4e800020) else if ((flags & FL_SET_CRn) && inst.CRFD == 0)
{
// For analysis purposes, we can assume that blr eats flags.
code[i].outputCR0 = true; code[i].outputCR0 = true;
code[i].outputCR1 = true;
}
break;
case OPTYPE_SYSTEM:
case OPTYPE_SYSTEMFP:
numSystemInstructions++;
break;
}
bool follow = false;
u32 destination;
if (inst.OPCD == 18 && blockSize > 1)
{
//Is bx - should we inline? yes!
if (inst.AA)
destination = SignExt26(inst.LI << 2);
else else
destination = address + SignExt26(inst.LI << 2); code[i].outputCR0 = (flags & FL_SET_CR0) ? true : false;
if (destination != blockstart)
follow = true; // Does the instruction output CR1?
} if (flags & FL_RC_BIT_F)
if (follow) code[i].outputCR1 = inst.hex & 1; //todo fix
numFollows++; else if ((flags & FL_SET_CRn) && inst.CRFD == 1)
if (numFollows > 1) code[i].outputCR1 = true;
follow = false; else
follow = false; code[i].outputCR1 = (flags & FL_SET_CR1) ? true : false;
if (!follow)
{ int numOut = 0;
if (opinfo->flags & FL_ENDBLOCK) //right now we stop early int numIn = 0;
if (flags & FL_OUT_A)
{ {
foundExit = true; code[i].regsOut[numOut++] = inst.RA;
gpa->SetOutputRegister(inst.RA, i);
}
if (flags & FL_OUT_D)
{
code[i].regsOut[numOut++] = inst.RD;
gpa->SetOutputRegister(inst.RD, i);
}
if (flags & FL_OUT_S)
{
code[i].regsOut[numOut++] = inst.RS;
gpa->SetOutputRegister(inst.RS, i);
}
if ((flags & FL_IN_A) || ((flags & FL_IN_A0) && inst.RA != 0))
{
code[i].regsIn[numIn++] = inst.RA;
gpa->SetInputRegister(inst.RA, i);
}
if (flags & FL_IN_B)
{
code[i].regsIn[numIn++] = inst.RB;
gpa->SetInputRegister(inst.RB, i);
}
if (flags & FL_IN_C)
{
code[i].regsIn[numIn++] = inst.RC;
gpa->SetInputRegister(inst.RC, i);
}
if (flags & FL_IN_S)
{
code[i].regsIn[numIn++] = inst.RS;
gpa->SetInputRegister(inst.RS, i);
}
// Set remaining register slots as unused (-1)
for (int j = numIn; j < 3; j++)
code[i].regsIn[j] = -1;
for (int j = numOut; j < 2; j++)
code[i].regsOut[j] = -1;
for (int j = 0; j < 3; j++)
code[i].fregsIn[j] = -1;
code[i].fregOut = -1;
switch (opinfo->type)
{
case OPTYPE_INTEGER:
case OPTYPE_LOAD:
case OPTYPE_STORE:
case OPTYPE_LOADFP:
case OPTYPE_STOREFP:
break;
case OPTYPE_FPU:
break;
case OPTYPE_BRANCH:
if (code[i].inst.hex == 0x4e800020)
{
// For analysis purposes, we can assume that blr eats flags.
code[i].outputCR0 = true;
code[i].outputCR1 = true;
}
break;
case OPTYPE_SYSTEM:
case OPTYPE_SYSTEMFP:
numSystemInstructions++;
break; break;
} }
address += 4;
bool follow = false;
u32 destination;
if (inst.OPCD == 18 && blockSize > 1)
{
//Is bx - should we inline? yes!
if (inst.AA)
destination = SignExt26(inst.LI << 2);
else
destination = address + SignExt26(inst.LI << 2);
if (destination != blockstart)
follow = true;
}
if (follow)
numFollows++;
if (numFollows > 1)
follow = false;
follow = false;
if (!follow)
{
if (opinfo->flags & FL_ENDBLOCK) //right now we stop early
{
foundExit = true;
break;
}
address += 4;
}
else
{
code[i].skip = true;
address = destination;
}
} }
else else
{ {
code[i].skip = true; // Memory exception occurred
address = destination; break;
} }
} }
if (!foundExit && blockSize > 1)
NOTICE_LOG(POWERPC, "Analyzer ERROR - Function %08x too big, size is 0x%08x", blockstart, address-blockstart);
st->numCycles = numCycles; st->numCycles = numCycles;
// Instruction Reordering Pass // Instruction Reordering Pass
if (blockSize > 1) if (num_inst > 2)
{ {
// Bubble down compares towards branches, so that they can be merged. // Bubble down compares towards branches, so that they can be merged.
// -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch. // -2: -1 for the pair, -1 for not swapping with the final instruction which is probably the branch.
@ -493,6 +499,13 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Bloc
} }
} }
} }
if (!foundExit && num_inst > 1)
{
// A broken block is a block that does not end in a branch
broken_block = true;
}
// Scan for CR0 dependency // Scan for CR0 dependency
// assume next block wants CR0 to be safe // assume next block wants CR0 to be safe
bool wantsCR0 = true; bool wantsCR0 = true;

View File

@ -108,7 +108,7 @@ public:
}; };
u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer, int blockSize); u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, bool &broken_block, CodeBuffer *buffer, int blockSize);
void LogFunctionCall(u32 addr); void LogFunctionCall(u32 addr);
void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db); void FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db);
bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0); bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0);

View File

@ -99,7 +99,7 @@ namespace PowerPC
u32 InstructionCache::ReadInstruction(u32 addr) u32 InstructionCache::ReadInstruction(u32 addr)
{ {
if (!HID0.ICE) // instuction cache is disabled if (!HID0.ICE) // instruction cache is disabled
return Memory::ReadUnchecked_U32(addr); return Memory::ReadUnchecked_U32(addr);
u32 set = (addr >> 5) & 0x7f; u32 set = (addr >> 5) & 0x7f;
u32 tag = addr >> 12; u32 tag = addr >> 12;

View File

@ -49,6 +49,7 @@ enum
FL_CHECKEXCEPTIONS = (1<<16), FL_CHECKEXCEPTIONS = (1<<16),
FL_EVIL = (1<<17), FL_EVIL = (1<<17),
FL_USE_FPU = (1<<18), FL_USE_FPU = (1<<18),
FL_LOADSTORE = (1<<19),
}; };
enum enum

View File

@ -267,7 +267,6 @@ void CheckExceptions()
{ {
SRR0 = NPC; SRR0 = NPC;
//GenerateISIException() sets up SRR1 //GenerateISIException() sets up SRR1
SRR1 |= MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 17) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000400; NPC = 0x80000400;
@ -306,6 +305,10 @@ void CheckExceptions()
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 17) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
// TODO: Verify whether the code below is correct
//SRR1 = MSR & 0x0000FFFF;
//MSR |= (MSR >> 16) & 1;
//MSR &= ~0x04EF32;
NPC = 0x80000800; NPC = 0x80000800;
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");

View File

@ -66,10 +66,13 @@ struct GC_ALIGNED64(PowerPCState)
// also for power management, but we don't care about that. // also for power management, but we don't care about that.
u32 spr[1024]; u32 spr[1024];
u32 tlb_last; u32 dtlb_last;
u32 tlb_va[16]; u32 dtlb_va[128];
u32 tlb_pa[16]; u32 dtlb_pa[128];
u32 itlb_last;
u32 itlb_va[128];
u32 itlb_pa[128];
InstructionCache iCache; InstructionCache iCache;
}; };

View File

@ -176,7 +176,8 @@ void CJitWindow::Compare(u32 em_address)
PPCAnalyst::BlockStats st; PPCAnalyst::BlockStats st;
PPCAnalyst::BlockRegStats gpa; PPCAnalyst::BlockRegStats gpa;
PPCAnalyst::BlockRegStats fpa; PPCAnalyst::BlockRegStats fpa;
if (PPCAnalyst::Flatten(ppc_addr, &size, &st, &gpa, &fpa, &code_buffer, size) != 0xffffffff) bool broken_block = false;
if (PPCAnalyst::Flatten(ppc_addr, &size, &st, &gpa, &fpa, broken_block, &code_buffer, size) != 0xffffffff)
{ {
sptr = (char*)xDis; sptr = (char*)xDis;
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)

View File

@ -107,6 +107,7 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF); game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack); game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
// Wii settings // Wii settings
if (StartUp.bWii) if (StartUp.bWii)
{ {

View File

@ -290,7 +290,8 @@ void CISOProperties::CreateGUIControls(bool IsWad)
sbCoreOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core")); sbCoreOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core"));
CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator); CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator); SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
TLBHack = new wxCheckBox(m_GameConfig, ID_TLBHACK, _("TLB Hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator); MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
TLBHack = new wxCheckBox(m_GameConfig, ID_TLBHACK, _("MMU Speed Hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
// Wii Console // Wii Console
sbWiiOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console")); sbWiiOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
EnableProgressiveScan = new wxCheckBox(m_GameConfig, ID_ENABLEPROGRESSIVESCAN, _("Enable Progressive Scan"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator); EnableProgressiveScan = new wxCheckBox(m_GameConfig, ID_ENABLEPROGRESSIVESCAN, _("Enable Progressive Scan"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
@ -346,6 +347,7 @@ void CISOProperties::CreateGUIControls(bool IsWad)
sbGameConfig->Add(OverrideText, 0, wxEXPAND|wxALL, 5); sbGameConfig->Add(OverrideText, 0, wxEXPAND|wxALL, 5);
sbCoreOverrides->Add(CPUThread, 0, wxEXPAND|wxLEFT, 5); sbCoreOverrides->Add(CPUThread, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(SkipIdle, 0, wxEXPAND|wxLEFT, 5); sbCoreOverrides->Add(SkipIdle, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(MMU, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(TLBHack, 0, wxEXPAND|wxLEFT, 5); sbCoreOverrides->Add(TLBHack, 0, wxEXPAND|wxLEFT, 5);
sbWiiOverrides->Add(EnableProgressiveScan, 0, wxEXPAND|wxLEFT, 5); sbWiiOverrides->Add(EnableProgressiveScan, 0, wxEXPAND|wxLEFT, 5);
sbWiiOverrides->Add(EnableWideScreen, 0, wxEXPAND|wxLEFT, 5); sbWiiOverrides->Add(EnableWideScreen, 0, wxEXPAND|wxLEFT, 5);
@ -809,6 +811,11 @@ void CISOProperties::LoadGameConfig()
else else
SkipIdle->Set3StateValue(wxCHK_UNDETERMINED); SkipIdle->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "MMU", &bTemp))
MMU->Set3StateValue((wxCheckBoxState)bTemp);
else
MMU->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "TLBHack", &bTemp)) if (GameIni.Get("Core", "TLBHack", &bTemp))
TLBHack->Set3StateValue((wxCheckBoxState)bTemp); TLBHack->Set3StateValue((wxCheckBoxState)bTemp);
else else
@ -890,6 +897,11 @@ bool CISOProperties::SaveGameConfig()
else else
GameIni.Set("Core", "SkipIdle", SkipIdle->Get3StateValue()); GameIni.Set("Core", "SkipIdle", SkipIdle->Get3StateValue());
if (MMU->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "MMU");
else
GameIni.Set("Core", "MMU", MMU->Get3StateValue());
if (TLBHack->Get3StateValue() == wxCHK_UNDETERMINED) if (TLBHack->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "TLBHack"); GameIni.DeleteKey("Core", "TLBHack");
else else

View File

@ -84,7 +84,7 @@ class CISOProperties : public wxDialog
wxStaticText *OverrideText; wxStaticText *OverrideText;
// Core // Core
wxCheckBox *CPUThread, *SkipIdle, *TLBHack; wxCheckBox *CPUThread, *SkipIdle, *MMU, *TLBHack;
// Wii // Wii
wxCheckBox *EnableProgressiveScan, *EnableWideScreen; wxCheckBox *EnableProgressiveScan, *EnableWideScreen;
// Video // Video
@ -164,6 +164,7 @@ class CISOProperties : public wxDialog
ID_OVERRIDE_TEXT, ID_OVERRIDE_TEXT,
ID_USEDUALCORE, ID_USEDUALCORE,
ID_IDLESKIP, ID_IDLESKIP,
ID_MMU,
ID_TLBHACK, ID_TLBHACK,
ID_FORCEFILTERING, ID_FORCEFILTERING,
ID_EFBCOPYDISABLE, ID_EFBCOPYDISABLE,