diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index 7b90c582ee..6fe8de6e68 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -537,22 +537,32 @@ u32 Read_Instruction(const u32 em_address) u32 Read_Opcode_JIT(const u32 _Address) { -#ifdef JIT_UNLIMITED_ICACHE - //return Memory::ReadUnchecked_U32(_Address); - if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000) +#ifdef JIT_UNLIMITED_ICACHE + if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && + (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) { PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); return 0; } - u8* iCache = jit.GetBlockCache()->GetICache(); - u32 addr = _Address & JIT_ICACHE_MASK; - jit.GetBlockCache()->GetICache(); + u8* iCache; + u32 addr; + if (_Address & JIT_ICACHE_EXRAM_BIT) + { + iCache = jit.GetBlockCache()->GetICacheEx(); + addr = _Address & JIT_ICACHEEX_MASK; + } + else + { + iCache = jit.GetBlockCache()->GetICache(); + addr = _Address & JIT_ICACHE_MASK; + } u32 inst = *(u32*)(iCache + addr); if (inst == JIT_ICACHE_INVALID_WORD) { - u32 block_start = addr & ~0x1f; - u8 *pMem = Memory::GetPointer(block_start); - memcpy(iCache + block_start, pMem, 32); + u32 cache_block_start = addr & ~0x1f; + u32 mem_block_start = _Address & ~0x1f; + u8 *pMem = Memory::GetPointer(mem_block_start); + memcpy(iCache + cache_block_start, pMem, 32); inst = *(u32*)(iCache + addr); } inst = Common::swap32(inst); @@ -563,22 +573,37 @@ u32 Read_Opcode_JIT(const u32 _Address) { inst = jit.GetBlockCache()->GetOriginalFirstOp(inst); } - //PanicAlert("Read from %x. res = %x. mem=%x", _Address, inst, Memory::Read_U32(_Address)); + + // if a crash occured after that message + // that means that we've compiled outdated code from the cache instead of memory + // this could happen if a game forgot to icbi the new code + 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); return inst; } u32 Read_Opcode_JIT_LC(const u32 _Address) { -#ifdef JIT_UNLIMITED_ICACHE - //return Memory::ReadUnchecked_U32(_Address); - if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000) +#ifdef JIT_UNLIMITED_ICACHE + if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 && + (_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000) { PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address); return 0; } - u8* iCache = jit.GetBlockCache()->GetICache(); - u32 addr = _Address & JIT_ICACHE_MASK; - jit.GetBlockCache()->GetICache(); + u8* iCache; + u32 addr; + if (_Address & JIT_ICACHE_EXRAM_BIT) + { + iCache = jit.GetBlockCache()->GetICacheEx(); + addr = _Address & JIT_ICACHEEX_MASK; + } + else + { + iCache = jit.GetBlockCache()->GetICache(); + addr = _Address & JIT_ICACHE_MASK; + } u32 inst = *(u32*)(iCache + addr); if (inst == JIT_ICACHE_INVALID_WORD) inst = Memory::ReadUnchecked_U32(_Address); @@ -590,7 +615,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) if ((inst & 0xfc000000) == 0) { inst = jit.GetBlockCache()->GetOriginalFirstOp(inst); - } + } return inst; } @@ -599,7 +624,12 @@ u32 Read_Opcode_JIT_LC(const u32 _Address) void Write_Opcode_JIT(const u32 _Address, const u32 _Value) { #ifdef JIT_UNLIMITED_ICACHE - *(u32*)(jit.GetBlockCache()->GetICache() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value); + if (_Address & JIT_ICACHE_EXRAM_BIT) + { + *(u32*)(jit.GetBlockCache()->GetICacheEx() + (_Address & JIT_ICACHEEX_MASK)) = Common::swap32(_Value); + } + else + *(u32*)(jit.GetBlockCache()->GetICache() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value); #else Memory::WriteUnchecked_U32(_Value, _Address); #endif diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp index aac2095122..9520d653d0 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp @@ -87,23 +87,9 @@ void AsmRoutineManager::Generate() MOV(32, R(EAX), M(&PowerPC::ppcState.pc)); dispatcherPcInEAX = GetCodePtr(); -#ifdef JIT_UNLIMITED_ICACHE - AND(32, R(EAX), Imm32(JIT_ICACHE_MASK)); -#ifdef _M_IX86 - MOV(32, R(EAX), MDisp(EAX, (u32)jit.GetBlockCache()->GetICache())); -#else - MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICache())); - MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); -#endif -#else -#ifdef _M_IX86 - AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); - MOV(32, R(EBX), Imm32((u32)Memory::base)); - MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0)); -#else - MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0)); -#endif -#endif + FixupBranch needinst = J(true); + const u8* haveinst = GetCodePtr(); + TEST(32, R(EAX), Imm32(0xFC)); FixupBranch notfound = J_CC(CC_NZ); BSWAP(32, EAX); @@ -169,6 +155,45 @@ void AsmRoutineManager::Generate() ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); + + SetJumpTarget(needinst); +#ifdef JIT_UNLIMITED_ICACHE + + TEST(32, R(EAX), Imm32(JIT_ICACHE_EXRAM_BIT)); + FixupBranch exram = J_CC(CC_NZ); + + AND(32, R(EAX), Imm32(JIT_ICACHE_MASK)); +#ifdef _M_IX86 + MOV(32, R(EAX), MDisp(EAX, (u32)jit.GetBlockCache()->GetICache())); +#else + MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICache())); + MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); +#endif + + FixupBranch getinst = J(); + SetJumpTarget(exram); + + AND(32, R(EAX), Imm32(JIT_ICACHEEX_MASK)); +#ifdef _M_IX86 + MOV(32, R(EAX), MDisp(EAX, (u32)jit.GetBlockCache()->GetICacheEx())); +#else + MOV(64, R(RSI), Imm64((u64)jit.GetBlockCache()->GetICacheEx())); + MOV(32, R(EAX), MComplex(RSI, EAX, SCALE_1, 0)); +#endif + + SetJumpTarget(getinst); +#else +#ifdef _M_IX86 + AND(32, R(EAX), Imm32(Memory::MEMVIEW32_MASK)); + MOV(32, R(EBX), Imm32((u32)Memory::base)); + MOV(32, R(EAX), MComplex(EBX, EAX, SCALE_1, 0)); +#else + MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0)); +#endif +#endif + JMP(haveinst, true); + + breakpointBailout = GetCodePtr(); //Landing pad for drec space ABI_PopAllCalleeSavedRegsAndAdjustStack(); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 13f0307fc2..ce1988bb7d 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -86,19 +86,21 @@ bool JitBlock::ContainsAddress(u32 em_address) blocks = new JitBlock[MAX_NUM_BLOCKS]; blockCodePointers = new const u8*[MAX_NUM_BLOCKS]; #ifdef JIT_UNLIMITED_ICACHE - if (iCache == 0) + if (iCache == 0 && iCacheEx == 0) { iCache = new u8[JIT_ICACHE_SIZE]; + iCacheEx = new u8[JIT_ICACHEEX_SIZE]; } else { PanicAlert("JitBlockCache::Init() - iCache is already initialized"); } - if (iCache == 0) + if (iCache == 0 || iCacheEx == 0) { PanicAlert("JitBlockCache::Init() - unable to allocate iCache"); } memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); + memset(iCacheEx, JIT_ICACHE_INVALID_BYTE, JIT_ICACHEEX_SIZE); #endif Clear(); } @@ -111,6 +113,9 @@ bool JitBlock::ContainsAddress(u32 em_address) if (iCache != 0) delete [] iCache; iCache = 0; + if (iCacheEx != 0) + delete [] iCacheEx; + iCacheEx = 0; #endif blocks = 0; blockCodePointers = 0; @@ -224,10 +229,15 @@ bool JitBlock::ContainsAddress(u32 em_address) } #ifdef JIT_UNLIMITED_ICACHE - u8 *JitBlockCache::GetICache() + u8* JitBlockCache::GetICache() { return iCache; } + + u8* JitBlockCache::GetICacheEx() + { + return iCacheEx; + } #endif int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) @@ -235,7 +245,15 @@ bool JitBlock::ContainsAddress(u32 em_address) if (!blocks) return -1; #ifdef JIT_UNLIMITED_ICACHE - u32 inst = *(u32*)(iCache + (addr & JIT_ICACHE_MASK)); + u32 inst; + if (addr & JIT_ICACHE_EXRAM_BIT) + { + inst = *(u32*)(iCacheEx + (addr & JIT_ICACHEEX_MASK)); + } + else + { + inst = *(u32*)(iCache + (addr & JIT_ICACHE_MASK)); + } inst = Common::swap32(inst); #else u32 inst = Memory::ReadFast32(addr); @@ -369,16 +387,29 @@ bool JitBlock::ContainsAddress(u32 em_address) } if (it1 != it2) { - block_map.erase(it1, it2); + if (address & JIT_ICACHE_EXRAM_BIT) + PanicAlert("icbi deleted blocks. addr=%x", address); + block_map.erase(it1, it2); } #ifdef JIT_UNLIMITED_ICACHE - // invalidate iCache - if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000) + // invalidate iCache. + // icbi can be called with any address, so we sholud check + if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000 && + (address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000) { return; } - u32 cacheaddr = address & JIT_ICACHE_MASK; - memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + if (address & JIT_ICACHE_EXRAM_BIT) + { + ERROR_LOG(POWERPC, "icbi clearing exram icache. addr=%x", address); + u32 cacheaddr = address & JIT_ICACHEEX_MASK; + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + } + else + { + u32 cacheaddr = address & JIT_ICACHE_MASK; + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + } #endif } diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index db2f9c8f49..a402eae75d 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -34,6 +34,9 @@ #define JIT_ICACHE_SIZE 0x2000000 #define JIT_ICACHE_MASK 0x1ffffff +#define JIT_ICACHEEX_SIZE 0x4000000 +#define JIT_ICACHEEX_MASK 0x3ffffff +#define JIT_ICACHE_EXRAM_BIT 0x10000000 // this corresponds to opcode 5 which is invalid in PowerPC #define JIT_ICACHE_INVALID_BYTE 0x14 #define JIT_ICACHE_INVALID_WORD 0x14141414 @@ -85,6 +88,7 @@ class JitBlockCache std::map, u32> block_map; // (end_addr, start_addr) -> number #ifdef JIT_UNLIMITED_ICACHE u8 *iCache; + u8 *iCacheEx; #endif int MAX_NUM_BLOCKS; @@ -111,6 +115,7 @@ public: const u8 **GetCodePointers(); #ifdef JIT_UNLIMITED_ICACHE u8 *GetICache(); + u8 *GetICacheEx(); #endif // Fast way to get a block. Only works on the first ppc instruction of a block. diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp index e0382c1081..0494e5f45a 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp @@ -71,6 +71,7 @@ namespace PowerPC memset(plru, 0, sizeof(plru)); #ifdef FAST_ICACHE memset(lookup_table, 0xff, sizeof(lookup_table)); + memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex)); #endif } @@ -84,20 +85,31 @@ namespace PowerPC for (int i = 0; i < 8; i++) if (valid[set] & (1<> 12)) + lookup_table_ex[((tags[set][i] << 7) | set) & 0x1fffff] = 0xff; + else + lookup_table[((tags[set][i] << 7) | set) & 0xfffff] = 0xff; } #endif valid[set] = 0; } u32 InstructionCache::ReadInstruction(u32 addr) - { + { if (!HID0.ICE) // instuction cache is disabled return Memory::ReadUnchecked_U32(addr); u32 set = (addr >> 5) & 0x7f; u32 tag = addr >> 12; #ifdef FAST_ICACHE - u32 t = lookup_table[(addr>>5) & 0xfffff]; + u32 t; + if (addr & ICACHE_EXRAM_BIT) + { + t = lookup_table_ex[(addr>>5) & 0x1fffff]; + } + else + { + t = lookup_table[(addr>>5) & 0xfffff]; + } #else u32 t = 0xff; for (u32 i = 0; i < 8; i++) @@ -121,15 +133,24 @@ namespace PowerPC memcpy(data[set][t], p, 32); #ifdef FAST_ICACHE if (valid[set] & (1<>5) & 0xfffff] = t; + { + if (tags[set][t] & (ICACHE_EXRAM_BIT >> 12)) + lookup_table_ex[((tags[set][t] << 7) | set) & 0x1fffff] = 0xff; + else + lookup_table[((tags[set][t] << 7) | set) & 0xfffff] = 0xff; + } + if (addr & ICACHE_EXRAM_BIT) + lookup_table_ex[(addr>>5) & 0x1fffff] = t; + else + lookup_table[(addr>>5) & 0xfffff] = t; #endif tags[set][t] = tag; valid[set] |= 1<>2)&7]); + u32 res = Common::swap32(data[set][t][(addr>>2)&7]); + return res; } } \ No newline at end of file diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.h b/Source/Core/Core/Src/PowerPC/PPCCache.h index 5732643efa..559afc0c6c 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.h +++ b/Source/Core/Core/Src/PowerPC/PPCCache.h @@ -25,11 +25,13 @@ namespace PowerPC { - const u32 ICACHE_SETS = 128; + const u32 ICACHE_SETS = 128; const u32 ICACHE_WAYS = 8; // size of an instruction cache block in words const u32 ICACHE_BLOCK_SIZE = 8; + const u32 ICACHE_EXRAM_BIT = 0x10000000; + struct InstructionCache { u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE]; @@ -42,6 +44,7 @@ namespace PowerPC #ifdef FAST_ICACHE u8 lookup_table[1<<20]; + u8 lookup_table_ex[1<<21]; #endif InstructionCache(); diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index 44f0b966a5..b7020f9598 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -67,7 +67,6 @@ struct GC_ALIGNED64(PowerPCState) u32 spr[1024]; InstructionCache iCache; - // JIT-mode instruction cache. Managed by JitCache }; enum CPUState diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index dd2816b1e8..13bd4a90ad 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -96,7 +96,8 @@ void DoState(PointerWrap &p) HW::DoState(p); CoreTiming::DoState(p); #ifdef JIT_UNLIMITED_ICACHE - p.DoVoid(jit.GetBlockCache()->GetICache(), JIT_ICACHE_SIZE); + p.DoVoid(jit.GetBlockCache()->GetICache(), JIT_ICACHE_SIZE); + p.DoVoid(jit.GetBlockCache()->GetICacheEx(), JIT_ICACHEEX_SIZE); #endif }