diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 343d5d84d1..00b0d08112 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -290,6 +290,7 @@ void SConfig::LoadSettings() ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false); ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false); ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false); + ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false); ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0); ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default diff --git a/Source/Core/Core/Src/Console.cpp b/Source/Core/Core/Src/Console.cpp index d2114d0198..e07773af78 100644 --- a/Source/Core/Core/Src/Console.cpp +++ b/Source/Core/Core/Src/Console.cpp @@ -55,7 +55,7 @@ void Console_Submit(const char *cmd) { #if MAX_LOGLEVEL >= INFO_LEVEL u32 EA = - Memory::TranslatePageAddress(addr, Memory::FLAG_NO_EXCEPTION); + Memory::TranslateAddress(addr, Memory::FLAG_NO_EXCEPTION); INFO_LOG(CONSOLE, "EA 0x%08x to 0x%08x", addr, EA); #endif } diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index d46d2bf443..7eb420a584 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -183,6 +183,15 @@ bool Init() SCoreStartupParameter &_CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; g_CoreStartupParameter = _CoreParameter; + + // TODO: Reenable JIT instructions + if (g_CoreStartupParameter.bMMU) + { + g_CoreStartupParameter.bJITLoadStoreOff = true; + g_CoreStartupParameter.bJITLoadStorePairedOff = true; + g_CoreStartupParameter.bJITLoadStoreFloatingOff = true; + } + // FIXME DEBUG_LOG(BOOT, dump_params()); Host_SetWaitCursor(true); diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index 70634a6259..ad2303dcac 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -32,7 +32,7 @@ SCoreStartupParameter::SCoreStartupParameter() : hInstance(0), hMainWindow(0), - bJITNoBlockCache(false), bJITBlockLinking(false), + bJITNoBlockCache(false), bJITBlockLinking(true), bJITOff(false), bJITLoadStoreOff(false), bJITLoadStorelXzOff(false), bJITLoadStorelwzOff(false), bJITLoadStorelbzxOff(false), @@ -48,7 +48,7 @@ SCoreStartupParameter::SCoreStartupParameter() bEnableCheats(false), bRunCompareServer(false), bRunCompareClient(false), iTLBHack(0), SelectedLanguage(0), - bWii(false), + bWii(false), bMMU(false), bConfirmStop(false), bHideCursor(false), bAutoHideCursor(false), bUsePanicHandlers(true), iRenderWindowXPos(0), iRenderWindowYPos(0), @@ -72,6 +72,7 @@ void SCoreStartupParameter::LoadDefaults() bEnableFPRF = false; bWii = false; SelectedLanguage = 0; + bMMU = false; iTLBHack = 0; iPosX = 100; diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index 2c330a7513..4b45ee63cc 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -77,6 +77,7 @@ struct SCoreStartupParameter bool bRunCompareServer; bool bRunCompareClient; + bool bMMU; int iTLBHack; int SelectedLanguage; diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index dcbe3ab6d5..d512e0fe5a 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -58,6 +58,7 @@ namespace Memory /* Enable the Translation Lookaside Buffer functions. TLBHack = 1 in Dolphin.ini or a .ini file will set this to true */ bool bFakeVMEM = false; +bool bMMU = false; // ============== @@ -348,6 +349,7 @@ bool Init() { bool wii = SConfig::GetInstance().m_LocalCoreStartupParameter.bWii; bFakeVMEM = SConfig::GetInstance().m_LocalCoreStartupParameter.iTLBHack == 1; + bMMU = SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU; u32 flags = 0; if (wii) flags |= MV_WII_ONLY; @@ -416,28 +418,37 @@ u32 Read_Instruction(const u32 em_address) return inst.hex; } -u32 Read_Opcode_JIT(const u32 _Address) +u32 Read_Opcode_JIT(u32 _Address) { #ifdef FAST_ICACHE - if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && - (_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area - (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) + if (bMMU && !bFakeVMEM && (_Address >> 28) == 0x7) { - PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); - return 0; + _Address = Memory::TranslateAddress(_Address, Memory::XCheckTLBFlag::FLAG_OPCODE); + if (_Address == 0) + { + return 0; + } } - - u32 inst = Read_Opcode(_Address); + + u32 inst = PowerPC::ppcState.iCache.ReadInstruction(_Address); #else u32 inst = Memory::ReadUnchecked_U32(_Address); #endif // if a crash occured after that message - // that means that we've compiled outdated code from the cache instead of memory + // that means that we have compiled outdated code from the cache instead of memory // this could happen if a game forgot to icbi the new code #if defined(_DEBUG) || defined(DEBUGFAST) u32 inst_mem = Memory::ReadUnchecked_U32(_Address); if (inst_mem != inst) ERROR_LOG(POWERPC, "JIT: compiling outdated code. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst); + + inst = Read_Opcode_JIT_LC(_Address); + if (inst_mem != inst) + { + ERROR_LOG(POWERPC, "JIT: self-modifying code detected. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst); + PanicAlert("JIT: self-modifying code detected. addr=%x, mem=%x, cache=%x", _Address, inst_mem, inst); + Write_Opcode_JIT(_Address, inst_mem); + } #endif return inst; } @@ -451,6 +462,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) { PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); + ERROR_LOG(MEMMAP, "iCacheJIT: Reading Opcode from %x. Please report.", _Address); return 0; } u8* iCache; @@ -505,132 +517,14 @@ void Write_Opcode_JIT(const u32 _Address, const u32 _Value) #endif } - -// ======================================================= -/* Functions to detect and trace memory read/write errors. Turn of JIT LoadStore to - make it work, and add a return 0 at the beginning of CheckDTLB to avoid closing - Dolphin just as it starts to get interesting. You can also try to change - the TitleID write in IOCTL_ES_GETTITLEID to 0x00000000, otherwise it will never even - get to making the bad dev/di request. - - I'm currently at (---, 8021347c) : Write32: Program wrote [0x7fd5d340] to [0x933e00f8], - 0x8021347c seems to write the out buffer to a 0x933e.... address before it is copies - to the 0x133e.... address for the Ioctlv. But why does it generate this bad address - when it made a good one 120 milliseconds earlier? - */ -// ------------- -bool ValidMemory(const u32 _Address) +void GenerateISIException_JIT(u32 _EffectiveAddress) { - switch (_Address >> 24) - { - case 0x00: - case 0x01: - case 0x80: - case 0x81: - case 0xC0: - case 0xC1: - return true; + GenerateISIException(_EffectiveAddress); - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) - return true; - else - return false; - case 0x7e: - case 0x7f: - if (bFakeVMEM) - return true; - else - return false; - - case 0xE0: - if (_Address < (0xE0000000 + L1_CACHE_SIZE)) - return true; - else - return false; - case 0xCC: - case 0xCD: - case 0xC8: - return true; - } - return false; + // Remove the invalid instruction from the icache, forcing a recompile + Write_Opcode_JIT(_EffectiveAddress, JIT_ICACHE_INVALID_WORD); } -void CheckForBadAddresses(u32 Address, u32 Data, bool Read, int Bits) -{ - if (!ValidMemory(Address)) - { - if(Read) - { - WARN_LOG(CONSOLE, "Read%i: Program tried to read [%08x] from [%08x]", Bits, Address); - } - else - { - ERROR_LOG(CONSOLE, "Write%i: Program tried to write [%08x] to [%08x]", Bits, Data, Address); - } - } - - if (Address == 0) - { - if(Read) - { - WARN_LOG(CONSOLE, "Read%i: Program read [0x%08x] from [0x%08x] * * * 0 * * *", Bits, Data, Address); - } - else - { - WARN_LOG(CONSOLE, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * 0 * * *", Bits, Data, Address); - } - } - // Try to figure out where the dev/di Ioctl arguments are stored (including buffer out), so we can - // find the bad one - if( - Data == 0x1090f4c0 // good out buffer right before it, for sound/smashbros_sound.brsar - || Data == 0x10913b00 // second one - || Data == 0x7fd5d340 // first bad out buffer - || Data == 0x133e00f8 // the address that store the bad 0x7fd5d340, this changes every time - || Data == 0x2a24aa // menu2\sc_title_en.pac byte size - || ( - (PC == 0x8021347c || PC == 0x801f6a20 || PC == 0x800202d0 || PC == 0x80229964 - || PC == 0x801d88bc) /* this could be interesting, because the bad out buffer 0x7fd5d340 - is 0x80000000 - size = 0x7fd5d340 perhaps some function read 0x80000000, I dunno */ - && Data == 0x80000000) - ) - { - if(Read) - { - ERROR_LOG(CONSOLE, "Read%i: Program read [0x%08x] from [0x%08x] * * * * * * * * * * * *", Bits, Data, Address); - } - else - { - ERROR_LOG(CONSOLE, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * * * * * * * * * *", Bits,Data, Address); - } - } -} - - -void CheckForBadAddresses8(u32 Address, u8 Data, bool Read) -{CheckForBadAddresses(Address, (u32)Data, Read, 8);} - -void CheckForBadAddresses16(u32 Address, u16 Data, bool Read) -{CheckForBadAddresses(Address, (u32)Data, Read, 16);} - -void CheckForBadAddresses32(u32 Address, u32 Data, bool Read) -{CheckForBadAddresses(Address, (u32)Data, Read, 32);} - -void CheckForBadAddresses64(u32 Address, u64 Data, bool Read) -{CheckForBadAddresses(Address, (u32)Data, Read, 64);} - void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize) { memcpy(GetPointer(_Address), _pData, _iSize); @@ -709,7 +603,6 @@ void GetString(std::string& _string, const u32 em_address) _string = stringBuffer; } - // GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit // programs don't have problems directly addressing any part of memory. u8 *GetPointer(const u32 _Address) @@ -743,7 +636,10 @@ u8 *GetPointer(const u32 _Address) case 0x7E: case 0x7F: - return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK)); + if (bFakeVMEM) + return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK)); + else + return 0; case 0xE0: if (_Address < (0xE0000000 + L1_CACHE_SIZE)) diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h index be1212f8be..1b326f742c 100644 --- a/Source/Core/Core/Src/HW/Memmap.h +++ b/Source/Core/Core/Src/HW/Memmap.h @@ -51,7 +51,7 @@ namespace Memory // so be sure to load it into a 64-bit register. extern u8 *base; -// These are guarenteed to point to "low memory" addresses (sub-32-bit). +// These are guaranteed to point to "low memory" addresses (sub-32-bit). extern u8 *m_pRAM; extern u8 *m_pEXRAM; extern u8 *m_pL1Cache; @@ -75,7 +75,7 @@ enum #ifdef _M_IX86 MEMVIEW32_MASK = 0x3FFFFFFF, #endif -}; +}; // Init and Shutdown bool IsInitialized(); @@ -169,11 +169,15 @@ enum XCheckTLBFlag FLAG_WRITE, FLAG_OPCODE, }; -u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag); -u32 TranslateBlockAddress(u32 _Address); +u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag); +void InvalidateTLBEntry(u32 _Address); +void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite); +void GenerateISIException(u32 _EffectiveAdress); +void GenerateISIException_JIT(u32 _EffectiveAdress); extern u32 pagetable_base; extern u32 pagetable_hashmask; }; #endif + diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp index ea0d0a0869..6d91f35a93 100644 --- a/Source/Core/Core/Src/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp @@ -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])); } - else if (em_address >= 0xE0000000) - { - PanicAlert("READ: Invalid address: %08x", em_address); - } else if (bFakeVMEM && ((em_address &0xF0000000) == 0x70000000)) { // fake VMEM @@ -197,30 +193,29 @@ inline void ReadFromHardware(T &_var, u32 em_address, u32 effective_address, Mem else { // MMU - u32 tlb_addr = TranslateBlockAddress(em_address); + u32 tlb_addr = TranslateAddress(em_address, flag); if (tlb_addr == 0) { - tlb_addr = TranslatePageAddress(em_address, flag); - if (tlb_addr != 0) - _var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK])); - else - PanicAlert("READ: Invalid address: %08x", em_address); + if (flag == FLAG_READ) + { + GenerateDSIException(em_address, false); + } } else + { _var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK])); + } } - - // Debugging: CheckForBadAddresses##_type(em_address, _var, true); } template 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 // reason we end up in this function: - if (em_address == 0xCC008000) { + if (em_address == 0xCC008000) + { switch (sizeof(T)) { case 1: GPFifo::Write8((u8)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; } - else if (em_address <= 0xcc009000) { + else if (em_address <= 0xcc009000) + { hwWrite(data, em_address); return; } /* WIIMODE */ else if (((em_address & 0xFF000000) == 0xCD000000) && - (em_address <= 0xcd009000)) { + (em_address <= 0xcd009000)) + { hwWriteWii(data,em_address); return; } else if (((em_address & 0xFFF00000) == 0xCD800000) && - (em_address <= 0xCD809000)) { + (em_address <= 0xCD809000)) + { hwWriteIOBridge(data,em_address); return; } - else { + else + { ERROR_LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", em_address, data, PC); _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)) { *(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; } 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); 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)) { // fake VMEM @@ -295,18 +294,18 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address, else { // MMU - u32 tlb_addr = TranslateBlockAddress(em_address); + u32 tlb_addr = TranslateAddress(em_address, flag); if (tlb_addr == 0) { - tlb_addr = TranslatePageAddress(em_address, flag); - if (tlb_addr != 0) - *(T*)&m_pRAM[tlb_addr & RAM_MASK] = bswap(data); - else - PanicAlert("WRITE: Invalid address: %08x", em_address); + if (flag == FLAG_WRITE) + { + GenerateDSIException(em_address, true); + } } else + { *(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 location through ReadFromHardware and WriteToHardware */ // ---------------- -u32 Read_Opcode(const u32 _Address) +u32 Read_Opcode(u32 _Address) { if (_Address == 0x00000000) { @@ -325,9 +324,19 @@ u32 Read_Opcode(const u32 _Address) return 0x00000000; } - /*u32 _var = 0; - ReadFromHardware(_var, _Address, _Address, FLAG_OPCODE); - return _var;*/ + if (Core::g_CoreStartupParameter.bMMU && (_Address >> 28) == 0x7) + { + // 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); } @@ -587,40 +596,25 @@ union UPTE2 u32 pagetable_base = 0; u32 pagetable_hashmask = 0; -void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite) +void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite) { if (_bWrite) PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; else 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; } -void GenerateISIException() +void GenerateISIException(u32 _EffectiveAddress) { - // shuffle2: ISI exception doesn't modify DSISR at all, to my knowledge... - //PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000; // maybe this was a typo for PPC_EXC_DSISR_PAGE? + // Address of instruction could not be translated + 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; } @@ -650,17 +644,166 @@ void SDRUpdated() 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 - for (int i = 0; i < 16; i++) { - if ((_Address & ~0xfff) == (PowerPC::ppcState.tlb_va[(PowerPC::ppcState.tlb_last + i) & 15])) { - u32 result = PowerPC::ppcState.tlb_pa[(PowerPC::ppcState.tlb_last + i) & 15] | (_Address & 0xfff); - PowerPC::ppcState.tlb_last = i; - return result; + u32 tag; + u32 paddr; + u8 flags; +} tlb_entry; + +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)]; @@ -673,7 +816,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) // hash function no 1 "xor" .360 u32 hash1 = (VSID ^ page_index); - u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base; + u32 pteg_addr = ((hash1 & pagetable_hashmask) << 6) | pagetable_base; // hash1 for (int i = 0; i < 8; i++) @@ -688,11 +831,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) UPTE2 PTE2; PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); - // TLB cache - 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; + UpdateTLBEntry(_Flag, PTE2, _Address); // set the access bits switch (_Flag) @@ -712,7 +851,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) // hash function no 2 "not" .360 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++) { u32 pte = bswap(*(u32*)&pRAM[pteg_addr]); @@ -723,11 +862,7 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) UPTE2 PTE2; PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); - // TLB cache - 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; + UpdateTLBEntry(_Flag, PTE2, _Address); switch (_Flag) { @@ -743,27 +878,6 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) } 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; } @@ -778,53 +892,78 @@ u32 TranslatePageAddress(u32 _Address, XCheckTLBFlag _Flag) #define BAT_EA_4(v) ((v)&0xf0000000) // Block Address Translation -u32 TranslateBlockAddress(u32 addr) +u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag) { u32 result = 0; 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; for (int i = 0; i < bats; i++) { - 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 (_Flag != FLAG_OPCODE) + { + 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])) { - // bat applies to this address - if (PowerPC::ppcState.spr[SPR_DBAT0U + i * 2] & batu) { - // bat entry valid - u32 offset = BAT_EA_OFFSET(addr); - u32 page = BAT_EA_11(addr); - page &= ~bl17; - page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_DBAT0L + i * 2]); - // fixme: check access rights - result = page | offset; - return result; + 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 entry valid + u32 offset = BAT_EA_OFFSET(addr); + u32 page = BAT_EA_11(addr); + page &= ~bl17; + page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_DBAT0L + i * 2]); + // 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); - addr2 = addr & (bl17 | 0xf001ffff); - batu = (m_MSR.PR ? BATU_Vp : BATU_Vs); - - if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2])) { - // bat applies to this address - if (PowerPC::ppcState.spr[SPR_IBAT0U + i * 2] & batu) { - // bat entry valid - u32 offset = BAT_EA_OFFSET(addr); - u32 page = BAT_EA_11(addr); - page &= ~bl17; - page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_IBAT0L + i * 2]); - // fixme: check access rights - result = page | offset; - return result; + if (BATU_BEPI(addr2) == BATU_BEPI(PowerPC::ppcState.spr[SPR_IBAT0U + i * 2])) + { + // bat applies to this address + if (PowerPC::ppcState.spr[SPR_IBAT0U + i * 2] & batu) + { + // bat entry valid + u32 offset = BAT_EA_OFFSET(addr); + u32 page = BAT_EA_11(addr); + page &= ~bl17; + page |= BATL_BRPN(PowerPC::ppcState.spr[SPR_IBAT0L + i * 2]); + // fixme: check access rights + result = page | offset; + return result; + } } } } 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 diff --git a/Source/Core/Core/Src/LuaInterface.cpp b/Source/Core/Core/Src/LuaInterface.cpp index d70436ffa0..6352f3ffb7 100644 --- a/Source/Core/Core/Src/LuaInterface.cpp +++ b/Source/Core/Core/Src/LuaInterface.cpp @@ -2797,6 +2797,7 @@ DEFINE_LUA_FUNCTION(emulua_loadrom, "filename") game_ini.Get("Core", "CPUOnThread", &StartUp.bCPUThread, StartUp.bCPUThread); game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF); + game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU); game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack); // Wii settings if (StartUp.bWii) diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp index bfae2475ba..b5815d4e8a 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter.cpp @@ -82,32 +82,54 @@ void SingleStepInner(void) static UGeckoInstruction instCode; NPC = PC + sizeof(UGeckoInstruction); - instCode.hex = Memory::Read_Opcode(PC); + instCode.hex = Memory::Read_Opcode(PC); - UReg_MSR& msr = (UReg_MSR&)MSR; - if (msr.FP) //If FPU is enabled, just execute - m_opTable[instCode.OPCD](instCode); - else + if (instCode.hex != 0) { - // check if we have to generate a FPU unavailable exception - if (!PPCTables::UsesFPU(instCode)) + UReg_MSR& msr = (UReg_MSR&)MSR; + if (msr.FP) //If FPU is enabled, just execute + { m_opTable[instCode.OPCD](instCode); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } else { - PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; - PowerPC::CheckExceptions(); - m_EndBlock = true; + // check if we have to generate a FPU unavailable exception + if (!PPCTables::UsesFPU(instCode)) + { + m_opTable[instCode.OPCD](instCode); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PowerPC::CheckExceptions(); + m_EndBlock = true; + } + } + else + { + PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE; + PowerPC::CheckExceptions(); + m_EndBlock = true; + } } - + } + else + { + // Memory exception on instruction fetch + PowerPC::CheckExceptions(); + m_EndBlock = true; } last_pc = PC; PC = NPC; +#if defined(_DEBUG) || defined(DEBUGFAST) if (PowerPC::ppcState.gpr[1] == 0) { printf("%i Corrupt stack", PowerPC::ppcState.DebugCount); } -#if defined(_DEBUG) || defined(DEBUGFAST) PowerPC::ppcState.DebugCount++; #endif patches(); @@ -224,11 +246,15 @@ void Run() void unknown_instruction(UGeckoInstruction _inst) { - char disasm[256]; - DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256); - printf("Last PC = %08x : %s\n", last_pc, disasm); - Dolphin_Debugger::PrintCallstack(); - _dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); + if (_inst.hex != 0) + { + char disasm[256]; + DisassembleGekko(Memory::ReadUnchecked_U32(last_pc), last_pc, disasm, 256); + printf("Last PC = %08x : %s\n", last_pc, disasm); + Dolphin_Debugger::PrintCallstack(); + _dbg_assert_msg_(POWERPC, 0, "\nIntCPU: Unknown instr %08x at PC = %08x last_PC = %08x LR = %08x\n", _inst.hex, PC, last_pc, LR); + } + } } // namespace diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp index 30aa7c464d..d62c5ae5a6 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -58,100 +58,148 @@ u32 Helper_Get_EA_UX(const 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) { u32 uAddress = Helper_Get_EA_U(_inst); - m_GPR[_inst.RD] = (u32)Memory::Read_U8(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = (u32)Memory::Read_U8(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) { u32 uAddress = Helper_Get_EA_U(_inst); - riPS0(_inst.FD) = Memory::Read_U64(uAddress); - m_GPR[_inst.RA] = uAddress; + u64 temp = Memory::Read_U64(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + riPS0(_inst.FD) = temp; + m_GPR[_inst.RA] = uAddress; + } } void lfdux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); - riPS0(_inst.FD) = Memory::Read_U64(uAddress); - m_GPR[_inst.RA] = uAddress; + u64 temp = Memory::Read_U64(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + riPS0(_inst.FD) = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) { u32 uTemp = Memory::Read_U32(Helper_Get_EA(_inst)); - double value = *(float*)&uTemp; - rPS0(_inst.FD) = value; - rPS1(_inst.FD) = value; + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + double value = *(float*)&uTemp; + rPS0(_inst.FD) = value; + rPS1(_inst.FD) = value; + } } void lfsu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); u32 uTemp = Memory::Read_U32(uAddress); - double value = *(float*)&uTemp; - rPS0(_inst.FD) = value; - rPS1(_inst.FD) = value; - m_GPR[_inst.RA] = uAddress; + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + double value = *(float*)&uTemp; + rPS0(_inst.FD) = value; + rPS1(_inst.FD) = value; + m_GPR[_inst.RA] = uAddress; + } + } void lfsux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); u32 uTemp = Memory::Read_U32(uAddress); - double value = *(float*)&uTemp; - rPS0(_inst.FD) = value; - rPS1(_inst.FD) = value; - m_GPR[_inst.RA] = uAddress; + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + double value = *(float*)&uTemp; + rPS0(_inst.FD) = value; + rPS1(_inst.FD) = value; + m_GPR[_inst.RA] = uAddress; + } } void lfsx(UGeckoInstruction _inst) { u32 uTemp = Memory::Read_U32(Helper_Get_EA_X(_inst)); - double value = *(float*)&uTemp; - rPS0(_inst.FD) = value; - rPS1(_inst.FD) = value; + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + double value = *(float*)&uTemp; + rPS0(_inst.FD) = value; + rPS1(_inst.FD) = value; + } } 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) { u32 uAddress = Helper_Get_EA_U(_inst); - m_GPR[_inst.RD] = (u32)(s32)(s16)Memory::Read_U16(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = (u32)(s32)(s16)Memory::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) { u32 uAddress = Helper_Get_EA_U(_inst); - m_GPR[_inst.RD] = (u32)(u16)Memory::Read_U16(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = (u32)(u16)Memory::Read_U16(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) { u32 uAddress = Helper_Get_EA(_inst); @@ -160,14 +208,18 @@ void lmw(UGeckoInstruction _inst) u32 TempReg = Memory::Read_U32(uAddress); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) { - PanicAlert("DSI exception in lmv."); + PanicAlert("DSI exception in lmw"); + NOTICE_LOG(POWERPC, "DSI exception in lmw"); return; } - - m_GPR[iReg] = TempReg; + else + { + m_GPR[iReg] = TempReg; + } } } +// FIXME: stmw should do a total rollback if a DSI occurs void stmw(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA(_inst); @@ -175,14 +227,22 @@ void stmw(UGeckoInstruction _inst) { Memory::Write_U32(m_GPR[iReg], uAddress); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + PanicAlert("DSI exception in stmw"); + NOTICE_LOG(POWERPC, "DSI exception in stmw"); return; + } } } void lwz(UGeckoInstruction _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 // should probably run a pass through memory instead before execution @@ -204,8 +264,12 @@ void lwz(UGeckoInstruction _inst) void lwzu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); - m_GPR[_inst.RD] = Memory::Read_U32(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = Memory::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } void stb(UGeckoInstruction _inst) @@ -217,7 +281,10 @@ void stbu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); 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) @@ -229,7 +296,10 @@ void stfdu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); 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) @@ -244,7 +314,10 @@ void stfsu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); 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) @@ -256,7 +329,10 @@ void sthu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); 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) @@ -268,7 +344,10 @@ void stwu(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_U(_inst); 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) @@ -315,7 +394,8 @@ void dcbtst(UGeckoInstruction _inst) void dcbz(UGeckoInstruction _inst) { // 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 @@ -330,7 +410,9 @@ void eciwx(UGeckoInstruction _inst) EA = b + m_GPR[_inst.RB]; if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) + { PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; + } if (EA & 3) PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; @@ -350,7 +432,9 @@ void ecowx(UGeckoInstruction _inst) EA = b + m_GPR[_inst.RB]; if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) + { PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; + } if (EA & 3) PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; @@ -378,42 +462,70 @@ void icbi(UGeckoInstruction _inst) void lbzux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); - m_GPR[_inst.RD] = (u32)Memory::Read_U8(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = (u32)Memory::Read_U8(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) { u32 uAddress = Helper_Get_EA_UX(_inst); - m_GPR[_inst.RD] = (s32)(s16)Memory::Read_U16(uAddress); - m_GPR[_inst.RA] = uAddress; + s32 temp = (s32)(s16)Memory::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) { - 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) { u32 uAddress = Helper_Get_EA_UX(_inst); - m_GPR[_inst.RD] = (u32)Memory::Read_U16(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = (u32)Memory::Read_U16(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } 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) @@ -426,27 +538,42 @@ void lswx(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) { u32 uAddress = Helper_Get_EA_UX(_inst); - m_GPR[_inst.RD] = Memory::Read_U32(uAddress); - m_GPR[_inst.RA] = uAddress; + u32 temp = Memory::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + m_GPR[_inst.RA] = uAddress; + } } void lwzx(UGeckoInstruction _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) { u32 uAddress = Helper_Get_EA_UX(_inst); 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) @@ -458,7 +585,10 @@ void stfdux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); 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) @@ -482,7 +612,10 @@ void stfsux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); 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) @@ -499,7 +632,10 @@ void sthux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); 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) @@ -509,7 +645,7 @@ void sthx(UGeckoInstruction _inst) // __________________________________________________________________________________________________ // lswi - bizarro string instruction -// +// FIXME: Should rollback if a DSI occurs void lswi(UGeckoInstruction _inst) { u32 EA; @@ -555,7 +691,7 @@ void lswi(UGeckoInstruction _inst) // todo : optimize ? // __________________________________________________________________________________________________ // stswi - bizarro string instruction -// +// FIXME: Should rollback if a DSI occurs void stswi(UGeckoInstruction _inst) { u32 EA; @@ -581,7 +717,9 @@ void stswi(UGeckoInstruction _inst) } Memory::Write_U8((m_GPR[r] >> (24 - i)) & 0xFF, EA); if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { return; + } i += 8; if (i == 32) @@ -612,10 +750,13 @@ void stwbrx(UGeckoInstruction _inst) void lwarx(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_X(_inst); - m_GPR[_inst.RD] = Memory::Read_U32(uAddress); - - g_bReserve = true; - g_reserveAddr = uAddress; + u32 temp = Memory::Read_U32(uAddress); + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + m_GPR[_inst.RD] = temp; + g_bReserve = true; + g_reserveAddr = uAddress; + } } void stwcxd(UGeckoInstruction _inst) @@ -626,9 +767,12 @@ void stwcxd(UGeckoInstruction _inst) uAddress = Helper_Get_EA_X(_inst); if (uAddress == g_reserveAddr) { Memory::Write_U32(m_GPR[_inst.RS], uAddress); - g_bReserve = false; - SetCRField(0, 2 | GetXER_SO()); - return; + if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) + { + g_bReserve = false; + SetCRField(0, 2 | GetXER_SO()); + return; + } } } @@ -639,7 +783,10 @@ void stwux(UGeckoInstruction _inst) { u32 uAddress = Helper_Get_EA_UX(_inst); 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) @@ -665,14 +812,7 @@ void tlbie(UGeckoInstruction _inst) { // Invalidate TLB entry u32 _Address = m_GPR[_inst.RB]; - for (int i = 0; i < 16; i++) - { - 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; - } - } + Memory::InvalidateTLBEntry(_Address); } void tlbsync(UGeckoInstruction _inst) diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp index 9b4918d014..3b5ebadb3b 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp @@ -153,7 +153,6 @@ float Helper_Dequantize(const u32 _Addr, const EQuantizeType _quantizeType, fResult = 0; break; } - return fResult; } @@ -170,12 +169,23 @@ void psq_l(UGeckoInstruction _inst) if (_inst.W == 0) { - rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale); - rPS1(_inst.RS) = Helper_Dequantize(EA+c, ldType, ldScale); + float ps0 = Helper_Dequantize(EA, ldType, ldScale); + float ps1 = Helper_Dequantize(EA+c, ldType, ldScale); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; + rPS1(_inst.RS) = ps1; } else { - rPS0(_inst.RS) = Helper_Dequantize(EA, ldType, ldScale); + float ps0 = Helper_Dequantize(EA, ldType, ldScale); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; rPS1(_inst.RS) = 1.0f; } } @@ -193,12 +203,23 @@ void psq_lu(UGeckoInstruction _inst) if (_inst.W == 0) { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); - rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale ); + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + float ps1 = Helper_Dequantize( EA+c, ldType, ldScale ); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; + rPS1(_inst.RS) = ps1; } else { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; rPS1(_inst.RS) = 1.0f; } m_GPR[_inst.RA] = EA; @@ -246,6 +267,10 @@ void psq_stu(UGeckoInstruction _inst) { Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale); } + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } m_GPR[_inst.RA] = EA; } @@ -262,13 +287,29 @@ void psq_lx(UGeckoInstruction _inst) if (_inst.Wx == 0) { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); - rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale ); + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + float ps1 = Helper_Dequantize( EA+c, ldType, ldScale ); + + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + + rPS0(_inst.RS) = ps0; + rPS1(_inst.RS) = ps1; } else { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); - rPS1(_inst.RS) = 1.0f; + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + float ps1 = 1.0f; + + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + + rPS0(_inst.RS) = ps0; + rPS1(_inst.RS) = ps1; } } @@ -307,12 +348,23 @@ void psq_lux(UGeckoInstruction _inst) if (_inst.Wx == 0) { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); - rPS1(_inst.RS) = Helper_Dequantize( EA+c, ldType, ldScale ); + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + float ps1 = Helper_Dequantize( EA+c, ldType, ldScale ); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; + rPS1(_inst.RS) = ps1; } else { - rPS0(_inst.RS) = Helper_Dequantize( EA, ldType, ldScale ); + float ps0 = Helper_Dequantize( EA, ldType, ldScale ); + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } + rPS0(_inst.RS) = ps0; rPS1(_inst.RS) = 1.0f; } m_GPR[_inst.RA] = EA; @@ -338,6 +390,10 @@ void psq_stux(UGeckoInstruction _inst) { Helper_Quantize(EA, rPS0(_inst.RS), stType, stScale); } + if (PowerPC::ppcState.Exceptions & EXCEPTION_DSI) + { + return; + } m_GPR[_inst.RA] = EA; } // namespace======= diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp index 198a55bb45..291232b381 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -63,40 +63,40 @@ static GekkoOPTemplate primarytable[] = {28, Interpreter::andi_rc, {"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {29, Interpreter::andis_rc, {"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {32, Interpreter::lwz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {33, Interpreter::lwzu, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {34, Interpreter::lbz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {35, Interpreter::lbzu, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {40, Interpreter::lhz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {41, Interpreter::lhzu, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {32, Interpreter::lwz, {"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}}, + {33, Interpreter::lwzu, {"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}}, + {34, Interpreter::lbz, {"lbz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}}, + {35, Interpreter::lbzu, {"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}}, + {40, Interpreter::lhz, {"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}}, + {41, Interpreter::lhzu, {"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}}, - {42, Interpreter::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, - {43, Interpreter::lhau, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, + {42, Interpreter::lha, {"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A | FL_LOADSTORE}}, + {43, Interpreter::lhau, {"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}}, - {44, Interpreter::sth, {"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {45, Interpreter::sthu, {"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, - {36, Interpreter::stw, {"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {37, Interpreter::stwu, {"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, - {38, Interpreter::stb, {"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, - {39, Interpreter::stbu, {"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S}}, + {44, Interpreter::sth, {"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}}, + {45, Interpreter::sthu, {"sthu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}}, + {36, Interpreter::stw, {"stw", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}}, + {37, Interpreter::stwu, {"stwu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}}, + {38, Interpreter::stb, {"stb", OPTYPE_STORE, FL_IN_A | FL_IN_S | FL_LOADSTORE}}, + {39, Interpreter::stbu, {"stbu", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}}, - {46, Interpreter::lmw, {"lmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, - {47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL, 10}}, + {46, Interpreter::lmw, {"lmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}}, + {47, Interpreter::stmw, {"stmw", OPTYPE_SYSTEM, FL_EVIL | FL_LOADSTORE, 10}}, - {48, Interpreter::lfs, {"lfs", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU}}, - {49, Interpreter::lfsu, {"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, - {50, Interpreter::lfd, {"lfd", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU}}, - {51, Interpreter::lfdu, {"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, + {48, Interpreter::lfs, {"lfs", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {49, Interpreter::lfsu, {"lfsu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {50, Interpreter::lfd, {"lfd", OPTYPE_LOADFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {51, Interpreter::lfdu, {"lfdu", OPTYPE_LOADFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, - {52, Interpreter::stfs, {"stfs", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU}}, - {53, Interpreter::stfsu, {"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, - {54, Interpreter::stfd, {"stfd", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU}}, - {55, Interpreter::stfdu, {"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, + {52, Interpreter::stfs, {"stfs", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {53, Interpreter::stfsu, {"stfsu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {54, Interpreter::stfd, {"stfd", OPTYPE_STOREFP, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {55, Interpreter::stfdu, {"stfdu", OPTYPE_STOREFP, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, - {56, Interpreter::psq_l, {"psq_l", OPTYPE_PS, FL_IN_A | FL_USE_FPU}}, - {57, Interpreter::psq_lu, {"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, - {60, Interpreter::psq_st, {"psq_st", OPTYPE_PS, FL_IN_A | FL_USE_FPU}}, - {61, Interpreter::psq_stu, {"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU}}, + {56, Interpreter::psq_l, {"psq_l", OPTYPE_PS, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {57, Interpreter::psq_lu, {"psq_lu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {60, Interpreter::psq_st, {"psq_st", OPTYPE_PS, FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, + {61, Interpreter::psq_stu, {"psq_stu", OPTYPE_PS, FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}}, //missing: 0, 5, 6, 9, 22, 30, 62, 58 {0, Interpreter::unknown_instruction, {"unknown_instruction", OPTYPE_UNKNOWN, 0}}, @@ -151,10 +151,10 @@ static GekkoOPTemplate table4_2[] = static GekkoOPTemplate table4_3[] = { - {6, Interpreter::psq_lx, {"psq_lx", OPTYPE_PS, FL_USE_FPU}}, - {7, Interpreter::psq_stx, {"psq_stx", OPTYPE_PS, FL_USE_FPU}}, - {38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU}}, - {39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU}}, + {6, Interpreter::psq_lx, {"psq_lx", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}}, + {7, Interpreter::psq_stx, {"psq_stx", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}}, + {38, Interpreter::psq_lux, {"psq_lux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}}, + {39, Interpreter::psq_stux, {"psq_stux", OPTYPE_PS, FL_USE_FPU | FL_LOADSTORE}}, }; static GekkoOPTemplate table19[] = @@ -207,63 +207,63 @@ static GekkoOPTemplate table31[] = {1014, Interpreter::dcbz, {"dcbz", OPTYPE_DCACHE, 0, 4}}, //load word - {23, Interpreter::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {55, Interpreter::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {23, Interpreter::lwzx, {"lwzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {55, Interpreter::lwzux, {"lwzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //load halfword - {279, Interpreter::lhzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {311, Interpreter::lhzux, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {279, Interpreter::lhzx, {"lhzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {311, Interpreter::lhzux, {"lhzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //load halfword signextend - {343, Interpreter::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {375, Interpreter::lhaux, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {343, Interpreter::lhax, {"lhax", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {375, Interpreter::lhaux, {"lhaux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //load byte - {87, Interpreter::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {119, Interpreter::lbzux, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B}}, + {87, Interpreter::lbzx, {"lbzx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {119, Interpreter::lbzux, {"lbzux", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //load byte reverse - {534, Interpreter::lwbrx, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, - {790, Interpreter::lhbrx, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B}}, + {534, Interpreter::lwbrx, {"lwbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {790, Interpreter::lhbrx, {"lhbrx", OPTYPE_LOAD, FL_OUT_D | FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, // Conditional load/store (Wii SMP) - {150, Interpreter::stwcxd, {"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0}}, - {20, Interpreter::lwarx, {"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0}}, + {150, Interpreter::stwcxd, {"stwcxd", OPTYPE_STORE, FL_EVIL | FL_SET_CR0 | FL_LOADSTORE}}, + {20, Interpreter::lwarx, {"lwarx", OPTYPE_LOAD, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE}}, //load string (Inst these) - {533, Interpreter::lswx, {"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D}}, - {597, Interpreter::lswi, {"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D}}, + {533, Interpreter::lswx, {"lswx", OPTYPE_LOAD, FL_EVIL | FL_IN_A | FL_OUT_D | FL_LOADSTORE}}, + {597, Interpreter::lswi, {"lswi", OPTYPE_LOAD, FL_EVIL | FL_IN_AB | FL_OUT_D | FL_LOADSTORE}}, //store word - {151, Interpreter::stwx, {"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {183, Interpreter::stwux, {"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {151, Interpreter::stwx, {"stwx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {183, Interpreter::stwux, {"stwux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //store halfword - {407, Interpreter::sthx, {"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {439, Interpreter::sthux, {"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {407, Interpreter::sthx, {"sthx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {439, Interpreter::sthux, {"sthux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //store byte - {215, Interpreter::stbx, {"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {247, Interpreter::stbux, {"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B}}, + {215, Interpreter::stbx, {"stbx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {247, Interpreter::stbux, {"stbux", OPTYPE_STORE, FL_OUT_A | FL_IN_A | FL_IN_B | FL_LOADSTORE}}, //store bytereverse - {662, Interpreter::stwbrx, {"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B}}, - {918, Interpreter::sthbrx, {"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B}}, + {662, Interpreter::stwbrx, {"stwbrx", OPTYPE_STORE, FL_IN_A0 | FL_IN_B | FL_LOADSTORE}}, + {918, Interpreter::sthbrx, {"sthbrx", OPTYPE_STORE, FL_IN_A | FL_IN_B | FL_LOADSTORE}}, - {661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL}}, - {725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL}}, + {661, Interpreter::stswx, {"stswx", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}}, + {725, Interpreter::stswi, {"stswi", OPTYPE_STORE, FL_EVIL | FL_LOADSTORE}}, // fp load/store - {535, Interpreter::lfsx, {"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}}, - {567, Interpreter::lfsux, {"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU}}, - {599, Interpreter::lfdx, {"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}}, - {631, Interpreter::lfdux, {"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU}}, + {535, Interpreter::lfsx, {"lfsx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {567, Interpreter::lfsux, {"lfsux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {599, Interpreter::lfdx, {"lfdx", OPTYPE_LOADFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {631, Interpreter::lfdux, {"lfdux", OPTYPE_LOADFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, - {663, Interpreter::stfsx, {"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}}, - {695, Interpreter::stfsux, {"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU}}, - {727, Interpreter::stfdx, {"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}}, - {759, Interpreter::stfdux, {"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU}}, - {983, Interpreter::stfiwx, {"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU}}, + {663, Interpreter::stfsx, {"stfsx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {695, Interpreter::stfsux, {"stfsux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {727, Interpreter::stfdx, {"stfdx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {759, Interpreter::stfdux, {"stfdux", OPTYPE_STOREFP, FL_IN_A | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, + {983, Interpreter::stfiwx, {"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B | FL_USE_FPU | FL_LOADSTORE}}, {19, Interpreter::mfcr, {"mfcr", OPTYPE_SYSTEM, FL_OUT_D}}, {83, Interpreter::mfmsr, {"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 9023ce3c18..81dd8c642d 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -175,17 +175,22 @@ void Jit64::Init() where this cause problems, so I'm enabling this by default, since I seem to get perhaps as much as 20% more fps with this option enabled. If you suspect that this option cause problems you can also disable it from the debugging window. */ - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) + if (Core::g_CoreStartupParameter.bEnableDebugging) { jo.enableBlocklink = false; - SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle = false; + Core::g_CoreStartupParameter.bSkipIdle = false; } else { - jo.enableBlocklink = true; + if (!Core::g_CoreStartupParameter.bJITBlockLinking) + { + jo.enableBlocklink = false; + } + else + jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU; } #ifdef _M_X64 - jo.enableFastMem = SConfig::GetInstance().m_LocalCoreStartupParameter.bUseFastMem; + jo.enableFastMem = Core::g_CoreStartupParameter.bUseFastMem; #else jo.enableFastMem = false; #endif @@ -194,16 +199,11 @@ void Jit64::Init() jo.optimizeGatherPipe = true; jo.fastInterrupts = false; jo.accurateSinglePrecision = true; + js.memcheck = Core::g_CoreStartupParameter.bMMU; gpr.SetEmitter(this); fpr.SetEmitter(this); - if (Core::g_CoreStartupParameter.bJITBlockLinking) - { - jo.enableBlocklink = false; - SuccessAlert("Your game was started without JIT Block Linking"); - } - trampolines.Init(); AllocCodeSpace(CODE_SIZE); @@ -218,7 +218,6 @@ void Jit64::ClearCache() ClearCodeSpace(); } - void Jit64::Shutdown() { FreeCodeSpace(); @@ -349,11 +348,10 @@ void Jit64::WriteRfiExitDestInEAX() JMP(asm_routines.testExceptions, true); } -void Jit64::WriteExceptionExit(u32 exception) +void Jit64::WriteExceptionExit() { Cleanup(); - OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(exception)); - MOV(32, M(&PC), Imm32(js.compilerPC + 4)); + SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); JMP(asm_routines.testExceptions, true); } @@ -361,7 +359,6 @@ void STACKALIGN Jit64::Run() { CompiledCode pExecAddr = (CompiledCode)asm_routines.enterCode; pExecAddr(); - //Will return when PowerPC::state changes } void Jit64::SingleStep() @@ -370,7 +367,7 @@ void Jit64::SingleStep() pExecAddr(); } -void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) +void Jit64::Trace() { char regs[500] = ""; char fregs[750] = ""; @@ -392,11 +389,11 @@ void Jit64::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) strncat(fregs, reg, 750); } #endif - const PPCAnalyst::CodeOp &op = code_buf->codebuffer[0]; - char ppcInst[256]; - DisassembleGekko(op.inst.hex, em_address, ppcInst, 256); - NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, op.inst.hex, ppcInst); + NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s", + PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], + PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, + PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs); } void STACKALIGN Jit64::Jit(u32 em_address) @@ -410,21 +407,36 @@ void STACKALIGN Jit64::Jit(u32 em_address) blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b)); } - const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b) { int blockSize = code_buf->GetSize(); - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) + // Memory exception on instruction fetch + bool memory_exception = false; + + // A broken block is a block that does not end in a branch + bool broken_block = false; + + if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) blockSize = 1; - Trace(code_buf, em_address); + broken_block = true; + Trace(); } if (em_address == 0) PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); + if (Core::g_CoreStartupParameter.bMMU && (em_address >> 28) == 0x7) + { + if (!Memory::TranslateAddress(em_address, Memory::XCheckTLBFlag::FLAG_OPCODE)) + { + // Memory exception occurred during instruction fetch + memory_exception = true; + } + } + int size = 0; js.isLastInstruction = false; js.blockStart = em_address; @@ -435,7 +447,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc //Analyze the block, collect all instructions it is made of (including inlining, //if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - u32 nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buf, blockSize); + u32 nextPC = em_address; + if (!memory_exception) + { + // If there is a memory exception inside a block (broken_block==true), compile up to that instruction. + nextPC = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize); + } PPCAnalyst::CodeOp *ops = code_buf->codebuffer; @@ -465,16 +482,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc SetJumpTarget(b1); } - if (false && jo.fastInterrupts) - { - // This does NOT yet work. - TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF)); - FixupBranch b1 = J_CC(CC_Z); - MOV(32, M(&PC), Imm32(js.blockStart)); - JMP(asm_routines.testExceptions, true); - SetJumpTarget(b1); - } - // Conditionally add profiling code. if (Profiler::g_ProfileBlocks) { ADD(32, M(&b->runCount), Imm8(1)); @@ -498,18 +505,22 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc gpr.Start(js.gpa); fpr.Start(js.fpa); - js.downcountAmount = js.st.numCycles; - if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) - js.downcountAmount = js.st.numCycles + PatchEngine::GetSpeedhackCycles(em_address); + js.downcountAmount = 0; + if (!Core::g_CoreStartupParameter.bEnableDebugging) + js.downcountAmount += PatchEngine::GetSpeedhackCycles(em_address); js.skipnext = false; js.blockSize = size; + js.compilerPC = nextPC; // Translate instructions for (int i = 0; i < (int)size; i++) { js.compilerPC = ops[i].address; js.op = &ops[i]; js.instructionNumber = i; + const GekkoOPInfo *opinfo = GetOpInfo(ops[i].inst); + js.downcountAmount += (opinfo->numCyclesMinusOne + 1); + if (i == (int)size - 1) { // WARNING - cmp->branch merging will screw this up. @@ -539,8 +550,40 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc } if (!ops[i].skip) + { + if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) + { + // If a memory exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + MOV(32, M(&PC), Imm32(ops[i].address)); + } + + if (js.memcheck && (opinfo->flags & FL_USE_FPU)) + { + //This instruction uses FPU - needs to add FP exception bailout + TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit + FixupBranch b1 = J_CC(CC_NZ); + + // If a FPU exception occurs, the exception handler will read + // from PC. Update PC with the latest value in case that happens. + MOV(32, M(&PC), Imm32(ops[i].address)); + SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); + JMP(asm_routines.fpException, true); + SetJumpTarget(b1); + } + Jit64Tables::CompileInstruction(ops[i]); + if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) + { + TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); + FixupBranch noMemException = J_CC(CC_Z); + + WriteExceptionExit(); + SetJumpTarget(noMemException); + } + } + #if defined(_DEBUG) || defined(DEBUGFAST) if (gpr.SanityCheck() || fpr.SanityCheck()) { @@ -558,7 +601,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (js.cancel) break; } - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableDebugging) + + if (memory_exception) + { + ABI_CallFunctionC(reinterpret_cast(&Memory::GenerateISIException_JIT), js.compilerPC); + WriteExceptionExit(); + } + + if (broken_block) { gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index ec5c9e1ac0..919e92e9fe 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -52,6 +52,16 @@ Core::g_CoreStartupParameter.bJIT##type##Off) \ {Default(inst); return;} +#define MEMCHECK_START \ + FixupBranch memException; \ + if (js.memcheck) \ + { TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); \ + memException = J_CC(CC_NZ); } + +#define MEMCHECK_END \ + if (js.memcheck) \ + SetJumpTarget(memException); + class Jit64 : public JitBase { private: @@ -69,6 +79,8 @@ private: int block_flags; bool isLastInstruction; + bool memcheck; + bool broken_block; int fifoBytesThisBlock; @@ -105,12 +117,12 @@ public: JitBlockCache *GetBlockCache() { return &blocks; } void NotifyBreakpoint(u32 em_address, bool set); - void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address); + void Trace(); void ClearCache(); const u8 *GetDispatcher() { - return asm_routines.dispatcher; // asm_routines.dispatcher + return asm_routines.dispatcher; } const CommonAsmRoutines *GetAsmRoutines() { return &asm_routines; @@ -132,7 +144,7 @@ public: void WriteExit(u32 destination, int exit_num); void WriteExitDestInEAX(int exit_num); - void WriteExceptionExit(u32 exception); + void WriteExceptionExit(); void WriteRfiExitDestInEAX(); void WriteCallInterpreter(UGeckoInstruction _inst); void Cleanup(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp index 13ca90327e..66f40e728f 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp @@ -389,8 +389,6 @@ void CompileInstruction(PPCAnalyst::CodeOp & op) #endif info->compileCount++; info->lastUse = jit->js.compilerPC; - } else { - PanicAlert("Tried to compile illegal (or unknown) instruction %08x, at %08x", op.inst.hex, jit->js.compilerPC); } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp index 67e8145999..841c2a997b 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp @@ -129,8 +129,6 @@ void Jit64AsmRoutineManager::Generate() //FP blocks test for FPU available, jump here if false fpException = AlignCode4(); - MOV(32, R(EAX), M(&PC)); - MOV(32, M(&NPC), R(EAX)); OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); ABI_CallFunction(reinterpret_cast(&PowerPC::CheckExceptions)); MOV(32, R(EAX), M(&NPC)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Branch.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Branch.cpp index 2d73cfe47c..146c1f0513 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Branch.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Branch.cpp @@ -47,7 +47,9 @@ void Jit64::sc(UGeckoInstruction inst) gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); - WriteExceptionExit(EXCEPTION_SYSCALL); + MOV(32, M(&PC), Imm32(js.compilerPC + 4)); + OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL)); + WriteExceptionExit(); } void Jit64::rfi(UGeckoInstruction inst) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index e0f4b592a0..9775a954ed 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -238,7 +238,8 @@ void Jit64::cmpXX(UGeckoInstruction inst) } } - if (!merge_branch) { + if (!merge_branch) + { // Keep the normal code separate for clarity. CMP(32, gpr.R(a), comparand); @@ -256,6 +257,7 @@ void Jit64::cmpXX(UGeckoInstruction inst) // TODO: If we ever care about SO, borrow a trick from // http://maws.mameworld.info/maws/mamesrc/src/emu/cpu/powerpc/drc_ops.c : bt, adc } else { + js.downcountAmount++; int test_bit = 8 >> (js.next_inst.BI & 3); bool condition = (js.next_inst.BO & BO_BRANCH_IF_TRUE) ? false : true; CMP(32, gpr.R(a), comparand); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index 0da62dd74a..c285efc9c3 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -357,13 +357,13 @@ void JitIL::SingleStep() pExecAddr(); } -void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) +void JitIL::Trace() { char regs[500] = ""; char fregs[750] = ""; #ifdef JIT_LOG_GPR - for (unsigned int i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) { char reg[50]; sprintf(reg, "r%02d: %08x ", i, PowerPC::ppcState.gpr[i]); @@ -372,18 +372,18 @@ void JitIL::Trace(PPCAnalyst::CodeBuffer *code_buf, u32 em_address) #endif #ifdef JIT_LOG_FPR - for (unsigned int i = 0; i < 32; i++) + for (int i = 0; i < 32; i++) { char reg[50]; sprintf(reg, "f%02d: %016x ", i, riPS0(i)); strncat(fregs, reg, 750); } #endif - const PPCAnalyst::CodeOp &op = code_buf->codebuffer[0]; - char ppcInst[256]; - DisassembleGekko(op.inst.hex, em_address, ppcInst, 256); - - NOTICE_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, op.inst.hex, ppcInst); + + NOTICE_LOG(DYNA_REC, "JITIL PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s", + PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], + PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, + PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs); } void STACKALIGN JitIL::Jit(u32 em_address) @@ -401,11 +401,14 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { int blockSize = code_buf->GetSize(); + // A broken block is a block that does not end in a branch + bool broken_block = false; + if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) blockSize = 1; - Trace(code_buf, em_address); + Trace(); } if (em_address == 0) @@ -420,7 +423,7 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc //Analyze the block, collect all instructions it is made of (including inlining, //if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, code_buf, blockSize); + b->exitAddress[0] = PPCAnalyst::Flatten(em_address, &size, &js.st, &js.gpa, &js.fpa, broken_block, code_buf, blockSize); PPCAnalyst::CodeOp *ops = code_buf->codebuffer; const u8 *start = AlignCode4(); //TODO: Test if this or AlignCode16 make a difference from GetCodePtr diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h index 465dc389c4..f493bc3214 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.h @@ -85,7 +85,7 @@ public: const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buffer, JitBlock *b); void NotifyBreakpoint(u32 em_address, bool set); - void Trace(PPCAnalyst::CodeBuffer *code_buffer, u32 em_address); + void Trace(); void ClearCache(); const u8 *GetDispatcher() { diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h index d8ca8e689e..2cac4c23a2 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h @@ -64,6 +64,8 @@ protected: bool isLastInstruction; bool forceUnsafeLoad; + bool memcheck; + bool broken_block; int fifoBytesThisBlock; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index e0a1a197e7..c0ac2aaa74 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -135,7 +135,7 @@ bool JitBlock::ContainsAddress(u32 em_address) links_to.clear(); block_map.clear(); num_blocks = 0; - memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); + memset(blockCodePointers, 0, sizeof(u8*)*MAX_NUM_BLOCKS); } /*void JitBlockCache::DestroyBlocksWithFlag(BlockFlag death_flag) @@ -360,7 +360,7 @@ bool JitBlock::ContainsAddress(u32 em_address) } b.invalid = true; #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 if (Memory::ReadFast32(b.originalAddress) == block_num) Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); @@ -399,7 +399,7 @@ bool JitBlock::ContainsAddress(u32 em_address) #ifdef JIT_UNLIMITED_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 && (address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area (address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000) diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index 6029c65d2c..f99d67a9b8 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -91,7 +91,10 @@ class JitBlockCache public: JitBlockCache() : 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); void FinalizeBlock(int block_num, bool block_link, const u8 *code_ptr); diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp index d9fc6f7a0f..3e046155f6 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp @@ -285,7 +285,7 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b) // Does not yet perform inlining - although there are plans for that. // 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)); @@ -296,6 +296,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Bloc gpa->any = true; fpa->any = false; + for (int i = 0; i < 32; i++) { 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); - _assert_msg_(POWERPC, inst.hex != 0, "Zero Op - Error flattening %08x op %08x", address + i*4, inst.hex); - 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) + if (inst.hex != 0) { - 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); - } + 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); - // 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; + code[i].wantsCR0 = false; + code[i].wantsCR1 = false; + code[i].wantsPS1 = false; - switch (opinfo->type) - { - case OPTYPE_INTEGER: - case OPTYPE_LOAD: - case OPTYPE_STORE: - break; - case OPTYPE_FPU: - break; - case OPTYPE_LOADFP: - break; - case OPTYPE_BRANCH: - if (code[i].inst.hex == 0x4e800020) - { - // For analysis purposes, we can assume that blr eats flags. + 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; - 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 - 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 + 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) { - 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; } - 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 { - code[i].skip = true; - address = destination; + // Memory exception occurred + break; } - } - if (!foundExit && blockSize > 1) - NOTICE_LOG(POWERPC, "Analyzer ERROR - Function %08x too big, size is 0x%08x", blockstart, address-blockstart); + } st->numCycles = numCycles; // Instruction Reordering Pass - if (blockSize > 1) + if (num_inst > 2) { // 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. @@ -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 // assume next block wants CR0 to be safe bool wantsCR0 = true; diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.h b/Source/Core/Core/Src/PowerPC/PPCAnalyst.h index d19774e3e8..174b0ec128 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.h @@ -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 FindFunctions(u32 startAddr, u32 endAddr, PPCSymbolDB *func_db); bool AnalyzeFunction(u32 startAddr, Symbol &func, int max_size = 0); diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp index a187d3e293..08d641d740 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp @@ -99,7 +99,7 @@ namespace PowerPC u32 InstructionCache::ReadInstruction(u32 addr) { - if (!HID0.ICE) // instuction cache is disabled + if (!HID0.ICE) // instruction cache is disabled return Memory::ReadUnchecked_U32(addr); u32 set = (addr >> 5) & 0x7f; u32 tag = addr >> 12; diff --git a/Source/Core/Core/Src/PowerPC/PPCTables.h b/Source/Core/Core/Src/PowerPC/PPCTables.h index 42f98d528a..752e0fc351 100644 --- a/Source/Core/Core/Src/PowerPC/PPCTables.h +++ b/Source/Core/Core/Src/PowerPC/PPCTables.h @@ -49,6 +49,7 @@ enum FL_CHECKEXCEPTIONS = (1<<16), FL_EVIL = (1<<17), FL_USE_FPU = (1<<18), + FL_LOADSTORE = (1<<19), }; enum diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 2bc9771638..911fe122fc 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -267,7 +267,6 @@ void CheckExceptions() { SRR0 = NPC; //GenerateISIException() sets up SRR1 - SRR1 |= MSR & 0x87C0FFFF; MSR |= (MSR >> 17) & 1; MSR &= ~0x04EF36; NPC = 0x80000400; @@ -306,6 +305,10 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 17) & 1; MSR &= ~0x04EF36; + // TODO: Verify whether the code below is correct + //SRR1 = MSR & 0x0000FFFF; + //MSR |= (MSR >> 16) & 1; + //MSR &= ~0x04EF32; NPC = 0x80000800; INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index 22c413afd7..b5019ee300 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -66,11 +66,14 @@ struct GC_ALIGNED64(PowerPCState) // also for power management, but we don't care about that. u32 spr[1024]; - u32 tlb_last; - u32 tlb_va[16]; - u32 tlb_pa[16]; + u32 dtlb_last; + u32 dtlb_va[128]; + u32 dtlb_pa[128]; + + u32 itlb_last; + u32 itlb_va[128]; + u32 itlb_pa[128]; - InstructionCache iCache; }; diff --git a/Source/Core/DebuggerWX/Src/JitWindow.cpp b/Source/Core/DebuggerWX/Src/JitWindow.cpp index 795779e669..7c10c50293 100644 --- a/Source/Core/DebuggerWX/Src/JitWindow.cpp +++ b/Source/Core/DebuggerWX/Src/JitWindow.cpp @@ -176,7 +176,8 @@ void CJitWindow::Compare(u32 em_address) PPCAnalyst::BlockStats st; PPCAnalyst::BlockRegStats gpa; 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; for (int i = 0; i < size; i++) diff --git a/Source/Core/DolphinWX/Src/BootManager.cpp b/Source/Core/DolphinWX/Src/BootManager.cpp index cf1c1cfd77..440494447f 100644 --- a/Source/Core/DolphinWX/Src/BootManager.cpp +++ b/Source/Core/DolphinWX/Src/BootManager.cpp @@ -107,6 +107,7 @@ bool BootCore(const std::string& _rFilename) game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle); game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF); game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack); + game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU); // Wii settings if (StartUp.bWii) { diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp index 48f375bc0f..400a0900e4 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.cpp +++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp @@ -290,7 +290,8 @@ void CISOProperties::CreateGUIControls(bool IsWad) 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); 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 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); @@ -346,6 +347,7 @@ void CISOProperties::CreateGUIControls(bool IsWad) sbGameConfig->Add(OverrideText, 0, wxEXPAND|wxALL, 5); sbCoreOverrides->Add(CPUThread, 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); sbWiiOverrides->Add(EnableProgressiveScan, 0, wxEXPAND|wxLEFT, 5); sbWiiOverrides->Add(EnableWideScreen, 0, wxEXPAND|wxLEFT, 5); @@ -809,6 +811,11 @@ void CISOProperties::LoadGameConfig() else 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)) TLBHack->Set3StateValue((wxCheckBoxState)bTemp); else @@ -890,6 +897,11 @@ bool CISOProperties::SaveGameConfig() else 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) GameIni.DeleteKey("Core", "TLBHack"); else diff --git a/Source/Core/DolphinWX/Src/ISOProperties.h b/Source/Core/DolphinWX/Src/ISOProperties.h index 36b4cd2aea..91600e5ba2 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.h +++ b/Source/Core/DolphinWX/Src/ISOProperties.h @@ -84,7 +84,7 @@ class CISOProperties : public wxDialog wxStaticText *OverrideText; // Core - wxCheckBox *CPUThread, *SkipIdle, *TLBHack; + wxCheckBox *CPUThread, *SkipIdle, *MMU, *TLBHack; // Wii wxCheckBox *EnableProgressiveScan, *EnableWideScreen; // Video @@ -164,6 +164,7 @@ class CISOProperties : public wxDialog ID_OVERRIDE_TEXT, ID_USEDUALCORE, ID_IDLESKIP, + ID_MMU, ID_TLBHACK, ID_FORCEFILTERING, ID_EFBCOPYDISABLE,