diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj
index 874a69ad8a..f43cf7ecfd 100644
--- a/Source/Core/Core/Core.vcproj
+++ b/Source/Core/Core/Core.vcproj
@@ -963,6 +963,14 @@
RelativePath=".\Src\PowerPC\PPCAnalyst.h"
>
+
+
+
+
diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp
index ff223726d8..7b90c582ee 100644
--- a/Source/Core/Core/Src/HW/Memmap.cpp
+++ b/Source/Core/Core/Src/HW/Memmap.cpp
@@ -528,17 +528,82 @@ bool AreMemoryBreakpointsActivated()
u32 Read_Instruction(const u32 em_address)
{
- UGeckoInstruction inst = ReadUnchecked_U32(em_address);
- if (inst.OPCD == 0)
- inst.hex = jit.GetBlockCache()->GetOriginalCode(em_address);
+ UGeckoInstruction inst = ReadUnchecked_U32(em_address);
if (inst.OPCD == 1)
return HLE::GetOrigInstruction(em_address);
else
return inst.hex;
}
+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)
+ {
+ 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();
+ 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);
+ inst = *(u32*)(iCache + addr);
+ }
+ inst = Common::swap32(inst);
+#else
+ u32 inst = Memory::ReadUnchecked_U32(_Address);
+#endif
+ if ((inst & 0xfc000000) == 0)
+ {
+ inst = jit.GetBlockCache()->GetOriginalFirstOp(inst);
+ }
+ //PanicAlert("Read from %x. res = %x. mem=%x", _Address, inst, Memory::Read_U32(_Address));
+ 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)
+ {
+ 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();
+ u32 inst = *(u32*)(iCache + addr);
+ if (inst == JIT_ICACHE_INVALID_WORD)
+ inst = Memory::ReadUnchecked_U32(_Address);
+ else
+ inst = Common::swap32(inst);
+#else
+ u32 inst = Memory::ReadUnchecked_U32(_Address);
+#endif
+ if ((inst & 0xfc000000) == 0)
+ {
+ inst = jit.GetBlockCache()->GetOriginalFirstOp(inst);
+ }
+ return inst;
+}
+// WARNING! No checks!
+// We assume that _Address is cached
+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);
+#else
+ Memory::WriteUnchecked_U32(_Value, _Address);
+#endif
+}
// =======================================================
diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h
index b3da643916..720e39359b 100644
--- a/Source/Core/Core/Src/HW/Memmap.h
+++ b/Source/Core/Core/Src/HW/Memmap.h
@@ -89,8 +89,7 @@ namespace Memory
void InitHWMemFuncs();
void InitHWMemFuncsWii();
-
- u32 Read_Instruction(const u32 _Address);
+
bool IsRAMAddress(const u32 addr, bool allow_locked_cache = false);
writeFn32 GetHWWriteFun32(const u32 _Address);
@@ -105,7 +104,17 @@ namespace Memory
#endif
}
+ // used by interpreter to read instructions, uses iCache
u32 Read_Opcode(const u32 _Address);
+ // used by JIT to read instructions, uses iCacheJIT
+ u32 Read_Opcode_JIT(const u32 _Address);
+ // used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode
+ u32 Read_Opcode_JIT_LC(const u32 _Address);
+ void Write_Opcode_JIT(const u32 _Address, const u32 _Value);
+ // this is used by Debugger a lot.
+ // For now, just reads from memory!
+ u32 Read_Instruction(const u32 _Address);
+
// For use by emulator
diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp
index 14341522d9..ccbcc3bdcf 100644
--- a/Source/Core/Core/Src/HW/MemmapFunctions.cpp
+++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp
@@ -294,9 +294,10 @@ u32 Read_Opcode(const u32 _Address)
return 0x00000000;
}
- u32 _var = 0;
+ /*u32 _var = 0;
ReadFromHardware(_var, _Address, _Address, FLAG_OPCODE);
- return _var;
+ return _var;*/
+ return PowerPC::ppcState.iCache.ReadInstruction(_Address);
}
u8 Read_U8(const u32 _Address)
diff --git a/Source/Core/Core/Src/PowerPC/Gekko.h b/Source/Core/Core/Src/PowerPC/Gekko.h
index 957c26e208..c1685436ee 100644
--- a/Source/Core/Core/Src/PowerPC/Gekko.h
+++ b/Source/Core/Core/Src/PowerPC/Gekko.h
@@ -391,6 +391,45 @@ union UReg_FPSCR
UReg_FPSCR() { Hex = 0;}
};
+// Hardware Implementation-Dependent Register 0
+union UReg_HID0
+{
+ struct
+ {
+ unsigned NOOPTI : 1;
+ unsigned : 1;
+ unsigned BHT : 1;
+ unsigned ABE : 1;
+ unsigned : 1;
+ unsigned BTIC : 1;
+ unsigned DCFA : 1;
+ unsigned SGE : 1;
+ unsigned IFEM : 1;
+ unsigned SPD : 1;
+ unsigned DCFI : 1;
+ unsigned ICFI : 1;
+ unsigned DLOCK : 1;
+ unsigned ILOCK : 1;
+ unsigned DCE : 1;
+ unsigned ICE : 1;
+ unsigned NHR : 1;
+ unsigned : 3;
+ unsigned DPM : 1;
+ unsigned SLEEP : 1;
+ unsigned NAP : 1;
+ unsigned DOZE : 1;
+ unsigned PAR : 1;
+ unsigned ECLK : 1;
+ unsigned : 1;
+ unsigned BCLK : 1;
+ unsigned EBD : 1;
+ unsigned EBA : 1;
+ unsigned DBP : 1;
+ unsigned EMCP : 1;
+ };
+ u32 Hex;
+};
+
// Hardware Implementation-Dependent Register 2
union UReg_HID2
{
@@ -590,6 +629,8 @@ enum
SPR_DBAT3L = 542,
SPR_DBAT3U = 543,
SPR_GQR0 = 912,
+ SPR_HID0 = 1008,
+ SPR_HID1 = 1009,
SPR_HID2 = 920,
SPR_WPAR = 921,
SPR_DMAU = 922,
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
index dc608f14bf..17b03721c4 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp
@@ -316,15 +316,7 @@ void dcbtst(UGeckoInstruction _inst)
}
void dcbz(UGeckoInstruction _inst)
-{
- // hack to prevent clearing of memory cached in the CPU instruction cache
- // needed to run WiiWare games
- // 0x81330c2c
- u32 NextOpcode = Memory::Read_U32(PC+4);
- if (NextOpcode == 0x7C0400AC)
- {
- return;
- }
+{
// HACK but works... we think
Memory::Memset(Helper_Get_EA_X(_inst) & (~31), 0, 32);
}
@@ -345,19 +337,10 @@ void eieio(UGeckoInstruction _inst)
}
void icbi(UGeckoInstruction _inst)
-{
- u32 address = Helper_Get_EA_X(_inst);
- // block size seems to be 0x20
- address &= ~0x1f;
-
- // this comment is slightly outdated but still relevant:
- // Inform the JIT to kill off this area of code NOW
- // VERY IMPORTANT when we start linking blocks
- // There are a TON of these so hopefully we can make this mechanism
- // fast in the JIT
- // ector said that this isn't needed anymore, and that making
- // a jit version of this instruction would be easy anyway
- //jit.GetBlockCache()->InvalidateCodeRange(address, 0x20);
+{
+ u32 address = Helper_Get_EA_X(_inst);
+ PowerPC::ppcState.iCache.Invalidate(address);
+ jit.GetBlockCache()->InvalidateICache(address);
}
void lbzux(UGeckoInstruction _inst)
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
index a439b28270..272da1bf3e 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
@@ -318,6 +318,28 @@ void mtspr(UGeckoInstruction _inst)
TU = m_GPR[_inst.RD];
break;
+ case SPR_HID0: // HID0
+ {
+ UReg_HID0 old_hid0;
+ old_hid0.Hex = oldValue;
+ if (HID0.ICE != old_hid0.ICE)
+ {
+ NOTICE_LOG(POWERPC, "Instruction Cache Enable (HID0.ICE) = %d", (int)HID0.ICE);
+ }
+ if (HID0.ILOCK != old_hid0.ILOCK)
+ {
+ NOTICE_LOG(POWERPC, "Instruction Cache Lock (HID0.ILOCK) = %d", (int)HID0.ILOCK);
+ }
+ if (HID0.ICFI)
+ {
+ HID0.ICFI = 0;
+ NOTICE_LOG(POWERPC, "Flush Instruction Cache! ICE=%d", (int)HID0.ICE);
+ // this is rather slow
+ // most games do it only once during initialization
+ PowerPC::ppcState.iCache.Reset();
+ }
+ }
+ break;
case SPR_HID2: // HID2
{
UReg_HID2 old_hid2;
diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
index 3a6a9b04e3..b465984239 100644
--- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
+++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp
@@ -280,7 +280,7 @@ static GekkoOPTemplate table31[] =
{4, Interpreter::tw, {"tw", OPTYPE_SYSTEM, 0, 1}},
{598, Interpreter::sync, {"sync", OPTYPE_SYSTEM, 0, 2}},
- {982, Interpreter::icbi, {"icbi", OPTYPE_SYSTEM, 0, 3}},
+ {982, Interpreter::icbi, {"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}},
// Unused instructions on GC
{310, Interpreter::eciwx, {"eciwx", OPTYPE_INTEGER, FL_RC_BIT}},
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
index 084fb780bf..017332014f 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h
@@ -27,15 +27,10 @@
// * A flush simply does a conditional write to the appropriate CRx.
// * If flag available, branch code can become absolutely trivial.
-
-
// Settings
// ----------
#define JIT_OFF_OPTIONS // Compile with JIT off options
-
-
-
// Include
// ----------
#if JITTEST
@@ -55,9 +50,6 @@
#include
#endif
-
-
-
// Declarations and definitions
// ----------
@@ -308,9 +300,11 @@ public:
void lmw(UGeckoInstruction inst);
void stmw(UGeckoInstruction inst);
+
+ void icbi(UGeckoInstruction inst);
};
extern Jit64 jit;
#endif // _JIT_H
-#endif // JITTEST
+#endif // JITTEST
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
index 00b5225dde..aac2095122 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp
@@ -86,12 +86,23 @@ void AsmRoutineManager::Generate()
dispatcherNoCheck = GetCodePtr();
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
TEST(32, R(EAX), Imm32(0xFC));
FixupBranch notfound = J_CC(CC_NZ);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp
index 958fddf1eb..43a3bbe96a 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp
@@ -509,3 +509,9 @@ void Jit64::stmw(UGeckoInstruction inst)
gpr.UnlockAllX();
#endif
}
+
+void Jit64::icbi(UGeckoInstruction inst)
+{
+ Default(inst);
+ WriteExit(js.compilerPC + 4, 0);
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64IL/Jit.h
index fbe6e38f7c..e0838321a0 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/Jit.h
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/Jit.h
@@ -294,6 +294,8 @@ public:
void lmw(UGeckoInstruction inst);
void stmw(UGeckoInstruction inst);
+
+ void icbi(UGeckoInstruction inst);
};
extern Jit64 jit;
@@ -303,4 +305,3 @@ void Jit(u32 em_address);
void ProfiledReJit();
#endif
-
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp
index f63d4f5af5..cccd2c2707 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitAsm.cpp
@@ -88,6 +88,16 @@ void AsmRoutineManager::Generate()
dispatcherNoCheck = GetCodePtr();
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));
@@ -95,6 +105,8 @@ void AsmRoutineManager::Generate()
#else
MOV(32, R(EAX), MComplex(RBX, RAX, SCALE_1, 0));
#endif
+#endif
+
TEST(32, R(EAX), Imm32(0xFC));
FixupBranch notfound = J_CC(CC_NZ);
BSWAP(32, EAX);
diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/Jit_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/Jit_LoadStore.cpp
index 877f2aa450..aac8516327 100644
--- a/Source/Core/Core/Src/PowerPC/Jit64IL/Jit_LoadStore.cpp
+++ b/Source/Core/Core/Src/PowerPC/Jit64IL/Jit_LoadStore.cpp
@@ -196,3 +196,9 @@ void Jit64::stmw(UGeckoInstruction inst)
addr = ibuild.EmitAdd(addr, ibuild.EmitIntConst(4));
}
}
+
+void Jit64::icbi(UGeckoInstruction inst)
+{
+ Default(inst);
+ ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4));
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
index cb67441921..13f0307fc2 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp
@@ -60,7 +60,6 @@ using namespace Gen;
#define INVALID_EXIT 0xFFFFFFFF
-
bool JitBlock::ContainsAddress(u32 em_address)
{
// WARNING - THIS DOES NOT WORK WITH INLINING ENABLED.
@@ -86,7 +85,21 @@ bool JitBlock::ContainsAddress(u32 em_address)
#endif
blocks = new JitBlock[MAX_NUM_BLOCKS];
blockCodePointers = new const u8*[MAX_NUM_BLOCKS];
-
+#ifdef JIT_UNLIMITED_ICACHE
+ if (iCache == 0)
+ {
+ iCache = new u8[JIT_ICACHE_SIZE];
+ }
+ else
+ {
+ PanicAlert("JitBlockCache::Init() - iCache is already initialized");
+ }
+ if (iCache == 0)
+ {
+ PanicAlert("JitBlockCache::Init() - unable to allocate iCache");
+ }
+ memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE);
+#endif
Clear();
}
@@ -94,6 +107,11 @@ bool JitBlock::ContainsAddress(u32 em_address)
{
delete [] blocks;
delete [] blockCodePointers;
+#ifdef JIT_UNLIMITED_ICACHE
+ if (iCache != 0)
+ delete [] iCache;
+ iCache = 0;
+#endif
blocks = 0;
blockCodePointers = 0;
num_blocks = 0;
@@ -105,19 +123,19 @@ bool JitBlock::ContainsAddress(u32 em_address)
// This clears the JIT cache. It's called from JitCache.cpp when the JIT cache
// is full and when saving and loading states.
void JitBlockCache::Clear()
- {
+ {
Core::DisplayMessage("Cleared code cache.", 3000);
- // Is destroying the blocks really necessary?
for (int i = 0; i < num_blocks; i++)
{
DestroyBlock(i, false);
}
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)
+ /*void JitBlockCache::DestroyBlocksWithFlag(BlockFlag death_flag)
{
for (int i = 0; i < num_blocks; i++)
{
@@ -126,7 +144,7 @@ bool JitBlock::ContainsAddress(u32 em_address)
DestroyBlock(i, false);
}
}
- }
+ }*/
void JitBlockCache::Reset()
{
@@ -161,7 +179,6 @@ bool JitBlock::ContainsAddress(u32 em_address)
JitBlock &b = blocks[num_blocks];
b.invalid = false;
b.originalAddress = em_address;
- b.originalFirstOpcode = Memory::ReadFast32(em_address);
b.exitAddress[0] = INVALID_EXIT;
b.exitAddress[1] = INVALID_EXIT;
b.exitPtrs[0] = 0;
@@ -177,7 +194,9 @@ bool JitBlock::ContainsAddress(u32 em_address)
{
blockCodePointers[block_num] = code_ptr;
JitBlock &b = blocks[block_num];
- Memory::WriteUnchecked_U32((JIT_OPCODE << 26) | block_num, blocks[block_num].originalAddress);
+ b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress);
+ Memory::Write_Opcode_JIT(b.originalAddress, (JIT_OPCODE << 26) | block_num);
+ block_map[std::make_pair(b.originalAddress + b.originalSize - 1, b.originalAddress)] = block_num;
if (block_link)
{
for (int i = 0; i < 2; i++)
@@ -204,51 +223,52 @@ bool JitBlock::ContainsAddress(u32 em_address)
return blockCodePointers;
}
+#ifdef JIT_UNLIMITED_ICACHE
+ u8 *JitBlockCache::GetICache()
+ {
+ return iCache;
+ }
+#endif
+
int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr)
{
if (!blocks)
+ return -1;
+#ifdef JIT_UNLIMITED_ICACHE
+ u32 inst = *(u32*)(iCache + (addr & JIT_ICACHE_MASK));
+ inst = Common::swap32(inst);
+#else
+ u32 inst = Memory::ReadFast32(addr);
+#endif
+ if (inst & 0xfc000000) // definitely not a JIT block
return -1;
- u32 code = Memory::ReadFast32(addr);
- if ((code >> 26) == JIT_OPCODE)
- {
- // Jitted code.
- unsigned int block = code & 0x03FFFFFF;
- if (block >= (unsigned int)num_blocks) {
- return -1;
- }
-
- if (blocks[block].originalAddress != addr)
- {
- //_assert_msg_(DYNA_REC, 0, "GetBlockFromAddress %08x - No match - This is BAD", addr);
- return -1;
- }
- return block;
- }
- else
- {
+ if (inst >= num_blocks)
return -1;
- }
+ if (blocks[inst].originalAddress != addr)
+ return -1;
+ return inst;
}
-void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers)
-{
- for (int i = 0; i < num_blocks; i++)
- if (blocks[i].ContainsAddress(em_address))
- block_numbers->push_back(i);
-}
-
- u32 JitBlockCache::GetOriginalCode(u32 address)
+ void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers)
{
- int num = GetBlockNumberFromStartAddress(address);
- if (num == -1)
- return Memory::ReadUnchecked_U32(address);
- else
- return blocks[num].originalFirstOpcode;
- }
+ for (int i = 0; i < num_blocks; i++)
+ if (blocks[i].ContainsAddress(em_address))
+ block_numbers->push_back(i);
+ }
+
+ u32 JitBlockCache::GetOriginalFirstOp(u32 block_num)
+ {
+ if (block_num >= num_blocks)
+ {
+ //PanicAlert("JitBlockCache::GetOriginalFirstOp - block_num = %u is out of range", block_num);
+ return block_num;
+ }
+ return blocks[block_num].originalFirstOpcode;
+ }
CompiledCode JitBlockCache::GetCompiledCodeFromBlock(int blockNumber)
- {
- return (CompiledCode)blockCodePointers[blockNumber];
+ {
+ return (CompiledCode)blocks[blockNumber].normalEntry;
}
//Block linker
@@ -301,52 +321,64 @@ void JitBlockCache::GetBlockNumbersFromAddress(u32 em_address, std::vector
void JitBlockCache::DestroyBlock(int blocknum, bool invalidate)
{
- u32 codebytes = (JIT_OPCODE << 26) | blocknum; //generate from i
+ if (blocknum < 0 || blocknum >= num_blocks)
+ {
+ PanicAlert("DestroyBlock: Invalid block number %d", blocknum);
+ return;
+ }
JitBlock &b = blocks[blocknum];
- b.invalid = 1;
- if (codebytes == Memory::ReadFast32(b.originalAddress))
+ if (b.invalid)
{
- //nobody has changed it, good
+ if (invalidate)
+ PanicAlert("Invalidating invalid block %d", blocknum);
+ return;
+ }
+ b.invalid = true;
+#ifdef JIT_UNLIMITED_ICACHE
+ Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode);
+#else
+ if (Memory::ReadFast32(b.originalAddress) == blocknum)
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress);
- }
- else if (!invalidate)
- {
- //PanicAlert("Detected code overwrite");
- //else, we may be in trouble, since we apparently know of this block but it's been
- //overwritten. We should have thrown it out before, on instruction cache invalidate or something.
- //Not ne cessarily bad though , if a game has simply thrown away a lot of code and is now using the space
- //for something else, then it's fine.
- DEBUG_LOG(MASTER_LOG, "WARNING - ClearCache detected code overwrite @ %08x", blocks[blocknum].originalAddress);
- }
+#endif
// We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher.
- // Not entirely ideal, but .. pretty good.
-
- // TODO - make sure that the below stuff really is safe.
-
+ // Not entirely ideal, but .. pretty good.
// Spurious entrances from previously linked blocks can only come through checkedEntry
XEmitter emit((u8 *)b.checkedEntry);
emit.MOV(32, M(&PC), Imm32(b.originalAddress));
emit.JMP(asm_routines.dispatcher, true);
-
+ // this is not needed really
+ /*
emit.SetCodePtr((u8 *)blockCodePointers[blocknum]);
emit.MOV(32, M(&PC), Imm32(b.originalAddress));
emit.JMP(asm_routines.dispatcher, true);
+ */
}
- void JitBlockCache::InvalidateCodeRange(u32 address, u32 length)
- {
- if (!jit.jo.enableBlocklink)
- return;
- return;
- //This is slow but should be safe (zelda needs it for block linking)
- for (int i = 0; i < num_blocks; i++)
+ void JitBlockCache::InvalidateICache(u32 address)
+ {
+ address &= ~0x1f;
+ // destroy JIT blocks
+ // !! this works correctly under assumption that any two overlapping blocks end at the same address
+ std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it;
+ while (it2 != block_map.end() && it2->first.second < address + 0x20)
{
- if (RangeIntersect(blocks[i].originalAddress, blocks[i].originalAddress + blocks[i].originalSize,
- address, address + length))
- {
- DestroyBlock(i, true);
- }
+ DestroyBlock(it2->second, true);
+ it2++;
}
+ if (it1 != it2)
+ {
+ block_map.erase(it1, it2);
+ }
+
+#ifdef JIT_UNLIMITED_ICACHE
+ // invalidate iCache
+ if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000)
+ {
+ return;
+ }
+ 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 4f36025078..db2f9c8f49 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h
@@ -28,6 +28,17 @@
#include
#endif
+// emulate CPU with unlimited instruction cache
+// the only way to invalidate a region is the "icbi" instruction
+#define JIT_UNLIMITED_ICACHE
+
+#define JIT_ICACHE_SIZE 0x2000000
+#define JIT_ICACHE_MASK 0x1ffffff
+// this corresponds to opcode 5 which is invalid in PowerPC
+#define JIT_ICACHE_INVALID_BYTE 0x14
+#define JIT_ICACHE_INVALID_WORD 0x14141414
+
+
enum BlockFlag
{
BLOCK_USE_GQR0 = 0x1, BLOCK_USE_GQR1 = 0x2, BLOCK_USE_GQR2 = 0x4, BLOCK_USE_GQR3 = 0x8,
@@ -71,6 +82,10 @@ class JitBlockCache
JitBlock *blocks;
int num_blocks;
std::multimap links_to;
+ std::map, u32> block_map; // (end_addr, start_addr) -> number
+#ifdef JIT_UNLIMITED_ICACHE
+ u8 *iCache;
+#endif
int MAX_NUM_BLOCKS;
bool RangeIntersect(int s1, int e1, int s2, int e2) const;
@@ -94,6 +109,9 @@ public:
JitBlock *GetBlock(int block_num);
int GetNumBlocks() const;
const u8 **GetCodePointers();
+#ifdef JIT_UNLIMITED_ICACHE
+ u8 *GetICache();
+#endif
// Fast way to get a block. Only works on the first ppc instruction of a block.
int GetBlockNumberFromStartAddress(u32 em_address);
@@ -104,15 +122,15 @@ public:
// This one is slow so should only be used for one-shots from the debugger UI, not for anything during runtime.
void GetBlockNumbersFromAddress(u32 em_address, std::vector *block_numbers);
- u32 GetOriginalCode(u32 address);
+ u32 GetOriginalFirstOp(u32 block_num);
CompiledCode GetCompiledCodeFromBlock(int blockNumber);
// DOES NOT WORK CORRECTLY WITH INLINING
- void InvalidateCodeRange(u32 em_address, u32 length);
+ void InvalidateICache(u32 em_address);
void DestroyBlock(int blocknum, bool invalidate);
// Not currently used
- void DestroyBlocksWithFlag(BlockFlag death_flag);
+ //void DestroyBlocksWithFlag(BlockFlag death_flag);
};
#endif
diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Tables.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Tables.cpp
index bcdd8bdbf9..d5fa033081 100644
--- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Tables.cpp
+++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Tables.cpp
@@ -319,7 +319,7 @@ static GekkoOPTemplate table31[] =
{4, &Jit64::Default}, //"tw", OPTYPE_SYSTEM, 0, 1}},
{598, &Jit64::DoNothing}, //"sync", OPTYPE_SYSTEM, 0, 2}},
- {982, &Jit64::Default}, //"icbi", OPTYPE_SYSTEM, 0, 3}},
+ {982, &Jit64::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}},
// Unused instructions on GC
{310, &Jit64::Default}, //"eciwx", OPTYPE_INTEGER, FL_RC_BIT}},
diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
index 436a0e2bd0..4c27a1820a 100644
--- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
+++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp
@@ -287,8 +287,7 @@ bool CanSwapAdjacentOps(const CodeOp &a, const CodeOp &b)
bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, BlockRegStats *fpa, CodeBuffer *buffer)
{
memset(st, 0, sizeof(st));
-
- UGeckoInstruction previnst = Memory::Read_Instruction(address - 4);
+ UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4);
if (previnst.hex == 0x4e800020)
st->isFirstBlockOfFunction = true;
@@ -309,10 +308,9 @@ bool Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, Blo
{
memset(&code[i], 0, sizeof(CodeOp));
code[i].address = address;
- UGeckoInstruction inst = Memory::Read_Instruction(code[i].address);
- UGeckoInstruction untouched_op = Memory::ReadUnchecked_U32(code[i].address);
- if (untouched_op.OPCD == 1) // Do handle HLE instructions.
- inst = untouched_op;
+
+ 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;
diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp
new file mode 100644
index 0000000000..e0382c1081
--- /dev/null
+++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp
@@ -0,0 +1,135 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "PPCCache.h"
+#include "../HW/Memmap.h"
+#include "PowerPC.h"
+
+namespace PowerPC
+{
+
+ u32 plru_mask[8] = {11,11,19,19,37,37,69,69};
+ u32 plru_value[8] = {11,3,17,1,36,4,64,0};
+
+ InstructionCache::InstructionCache()
+ {
+ for (u32 m = 0; m < 0xff; m++)
+ {
+ u32 w = 0;
+ while (m & (1<> 5) & 0x7f;
+#ifdef FAST_ICACHE
+ for (int i = 0; i < 8; i++)
+ if (valid[set] & (1<> 5) & 0x7f;
+ u32 tag = addr >> 12;
+#ifdef FAST_ICACHE
+ u32 t = lookup_table[(addr>>5) & 0xfffff];
+#else
+ u32 t = 0xff;
+ for (u32 i = 0; i < 8; i++)
+ if (tags[set][i] == tag && (valid[set] & (1<>5) & 0xfffff] = t;
+#endif
+ tags[set][t] = tag;
+ valid[set] |= 1<>2)&7]);
+ }
+
+}
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.h b/Source/Core/Core/Src/PowerPC/PPCCache.h
new file mode 100644
index 0000000000..5732643efa
--- /dev/null
+++ b/Source/Core/Core/Src/PowerPC/PPCCache.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _PPCCACHE_H
+#define _PPCCACHE_H
+
+#include "Common.h"
+
+#define FAST_ICACHE
+
+namespace PowerPC
+{
+
+ const u32 ICACHE_SETS = 128;
+ const u32 ICACHE_WAYS = 8;
+ // size of an instruction cache block in words
+ const u32 ICACHE_BLOCK_SIZE = 8;
+
+ struct InstructionCache
+ {
+ u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE];
+ u32 tags[ICACHE_SETS][ICACHE_WAYS];
+ u32 plru[ICACHE_SETS];
+ u32 valid[ICACHE_SETS];
+
+ u32 way_from_valid[255];
+ u32 way_from_plru[128];
+
+#ifdef FAST_ICACHE
+ u8 lookup_table[1<<20];
+#endif
+
+ InstructionCache();
+ void Reset();
+ u32 ReadInstruction(u32 addr);
+ void Invalidate(u32 addr);
+ };
+
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
index 1706f68e97..cdcb680b9b 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp
@@ -127,6 +127,8 @@ void Init()
// ... but start as interpreter by default.
mode = MODE_INTERPRETER;
state = CPU_STEPPING;
+
+ ppcState.iCache.Reset();
}
void Shutdown()
diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h
index 1b579b0fb1..44f0b966a5 100644
--- a/Source/Core/Core/Src/PowerPC/PowerPC.h
+++ b/Source/Core/Core/Src/PowerPC/PowerPC.h
@@ -22,6 +22,7 @@
#include "Gekko.h"
#include "BreakPoints.h"
#include "../Debugger/PPCDebugInterface.h"
+#include "PPCCache.h"
class PointerWrap;
@@ -64,6 +65,9 @@ struct GC_ALIGNED64(PowerPCState)
// special purpose registers - controlls quantizers, DMA, and lots of other misc extensions.
// also for power management, but we don't care about that.
u32 spr[1024];
+
+ InstructionCache iCache;
+ // JIT-mode instruction cache. Managed by JitCache
};
enum CPUState
@@ -101,6 +105,7 @@ void OnIdle(u32 _uThreadAddr);
void OnIdleIL();
// Easy register access macros.
+#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0])
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2])
#define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
@@ -194,4 +199,4 @@ inline void SetXER_SO(int value) {
void UpdateFPRF(double dvalue);
-#endif
+#endif
\ No newline at end of file
diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript
index 13dd14dc3e..3a677bd3c7 100644
--- a/Source/Core/Core/Src/SConscript
+++ b/Source/Core/Core/Src/SConscript
@@ -72,6 +72,7 @@ files = ["ActionReplay.cpp",
"PowerPC/PowerPC.cpp",
"PowerPC/PPCAnalyst.cpp",
"PowerPC/PPCTables.cpp",
+ "PowerPC/PPCCache.cpp",
"PowerPC/Profiler.cpp",
"PowerPC/SignatureDB.cpp",
"PowerPC/PPCSymbolDB.cpp",
diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp
index 917dc40282..dd2816b1e8 100644
--- a/Source/Core/Core/Src/State.cpp
+++ b/Source/Core/Core/Src/State.cpp
@@ -24,7 +24,11 @@
#include "CoreTiming.h"
#include "HW/HW.h"
#include "PowerPC/PowerPC.h"
+#ifdef JITTEST
+#include "PowerPC/Jit64IL/Jit.h"
+#else
#include "PowerPC/Jit64/Jit.h"
+#endif
#include "PluginManager.h"
@@ -91,6 +95,9 @@ void DoState(PointerWrap &p)
PowerPC::DoState(p);
HW::DoState(p);
CoreTiming::DoState(p);
+#ifdef JIT_UNLIMITED_ICACHE
+ p.DoVoid(jit.GetBlockCache()->GetICache(), JIT_ICACHE_SIZE);
+#endif
}
void LoadBufferStateCallback(u64 userdata, int cyclesLate)