Added the ExRAM support to the iCache (only JIT and Interpreter for now, JIT IL fix will be a bit later)
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4358 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
b843378636
commit
26a60eb9bf
|
@ -538,21 +538,31 @@ 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)
|
||||
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)
|
||||
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);
|
||||
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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<std::pair<u32,u32>, 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.
|
||||
|
|
|
@ -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,7 +85,10 @@ namespace PowerPC
|
|||
for (int i = 0; i < 8; i++)
|
||||
if (valid[set] & (1<<i))
|
||||
{
|
||||
lookup_table[((tags[set][i] << 7) | set) & 0xfffff] = 0xff;
|
||||
if (tags[set][i] & (ICACHE_EXRAM_BIT >> 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;
|
||||
|
@ -97,7 +101,15 @@ namespace PowerPC
|
|||
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<<t))
|
||||
lookup_table[((tags[set][t] << 7) | set) & 0xfffff] = 0xff;
|
||||
lookup_table[(addr>>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<<t;
|
||||
}
|
||||
// update plru
|
||||
plru[set] = (plru[set] & ~plru_mask[t]) | plru_value[t];
|
||||
return Common::swap32(data[set][t][(addr>>2)&7]);
|
||||
u32 res = Common::swap32(data[set][t][(addr>>2)&7]);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -30,6 +30,8 @@ namespace PowerPC
|
|||
// 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();
|
||||
|
|
|
@ -67,7 +67,6 @@ struct GC_ALIGNED64(PowerPCState)
|
|||
u32 spr[1024];
|
||||
|
||||
InstructionCache iCache;
|
||||
// JIT-mode instruction cache. Managed by JitCache
|
||||
};
|
||||
|
||||
enum CPUState
|
||||
|
|
|
@ -97,6 +97,7 @@ void DoState(PointerWrap &p)
|
|||
CoreTiming::DoState(p);
|
||||
#ifdef JIT_UNLIMITED_ICACHE
|
||||
p.DoVoid(jit.GetBlockCache()->GetICache(), JIT_ICACHE_SIZE);
|
||||
p.DoVoid(jit.GetBlockCache()->GetICacheEx(), JIT_ICACHEEX_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue