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:
LinesPrower 2009-10-04 05:13:56 +00:00
parent b843378636
commit 26a60eb9bf
8 changed files with 168 additions and 53 deletions

View File

@ -537,22 +537,32 @@ u32 Read_Instruction(const u32 em_address)
u32 Read_Opcode_JIT(const u32 _Address) u32 Read_Opcode_JIT(const u32 _Address)
{ {
#ifdef JIT_UNLIMITED_ICACHE #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); PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0; return 0;
} }
u8* iCache = jit.GetBlockCache()->GetICache(); u8* iCache;
u32 addr = _Address & JIT_ICACHE_MASK; u32 addr;
jit.GetBlockCache()->GetICache(); 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); u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD) if (inst == JIT_ICACHE_INVALID_WORD)
{ {
u32 block_start = addr & ~0x1f; u32 cache_block_start = addr & ~0x1f;
u8 *pMem = Memory::GetPointer(block_start); u32 mem_block_start = _Address & ~0x1f;
memcpy(iCache + block_start, pMem, 32); u8 *pMem = Memory::GetPointer(mem_block_start);
memcpy(iCache + cache_block_start, pMem, 32);
inst = *(u32*)(iCache + addr); inst = *(u32*)(iCache + addr);
} }
inst = Common::swap32(inst); inst = Common::swap32(inst);
@ -563,22 +573,37 @@ u32 Read_Opcode_JIT(const u32 _Address)
{ {
inst = jit.GetBlockCache()->GetOriginalFirstOp(inst); 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; return inst;
} }
u32 Read_Opcode_JIT_LC(const u32 _Address) u32 Read_Opcode_JIT_LC(const u32 _Address)
{ {
#ifdef JIT_UNLIMITED_ICACHE #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); PanicAlert("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0; return 0;
} }
u8* iCache = jit.GetBlockCache()->GetICache(); u8* iCache;
u32 addr = _Address & JIT_ICACHE_MASK; u32 addr;
jit.GetBlockCache()->GetICache(); 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); u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD) if (inst == JIT_ICACHE_INVALID_WORD)
inst = Memory::ReadUnchecked_U32(_Address); inst = Memory::ReadUnchecked_U32(_Address);
@ -590,7 +615,7 @@ u32 Read_Opcode_JIT_LC(const u32 _Address)
if ((inst & 0xfc000000) == 0) if ((inst & 0xfc000000) == 0)
{ {
inst = jit.GetBlockCache()->GetOriginalFirstOp(inst); inst = jit.GetBlockCache()->GetOriginalFirstOp(inst);
} }
return 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) void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
{ {
#ifdef JIT_UNLIMITED_ICACHE #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 #else
Memory::WriteUnchecked_U32(_Value, _Address); Memory::WriteUnchecked_U32(_Value, _Address);
#endif #endif

View File

@ -87,23 +87,9 @@ void AsmRoutineManager::Generate()
MOV(32, R(EAX), M(&PowerPC::ppcState.pc)); MOV(32, R(EAX), M(&PowerPC::ppcState.pc));
dispatcherPcInEAX = GetCodePtr(); dispatcherPcInEAX = GetCodePtr();
#ifdef JIT_UNLIMITED_ICACHE FixupBranch needinst = J(true);
AND(32, R(EAX), Imm32(JIT_ICACHE_MASK)); const u8* haveinst = GetCodePtr();
#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)); TEST(32, R(EAX), Imm32(0xFC));
FixupBranch notfound = J_CC(CC_NZ); FixupBranch notfound = J_CC(CC_NZ);
BSWAP(32, EAX); BSWAP(32, EAX);
@ -169,6 +155,45 @@ void AsmRoutineManager::Generate()
ABI_PopAllCalleeSavedRegsAndAdjustStack(); ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET(); 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(); breakpointBailout = GetCodePtr();
//Landing pad for drec space //Landing pad for drec space
ABI_PopAllCalleeSavedRegsAndAdjustStack(); ABI_PopAllCalleeSavedRegsAndAdjustStack();

View File

@ -86,19 +86,21 @@ bool JitBlock::ContainsAddress(u32 em_address)
blocks = new JitBlock[MAX_NUM_BLOCKS]; blocks = new JitBlock[MAX_NUM_BLOCKS];
blockCodePointers = new const u8*[MAX_NUM_BLOCKS]; blockCodePointers = new const u8*[MAX_NUM_BLOCKS];
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
if (iCache == 0) if (iCache == 0 && iCacheEx == 0)
{ {
iCache = new u8[JIT_ICACHE_SIZE]; iCache = new u8[JIT_ICACHE_SIZE];
iCacheEx = new u8[JIT_ICACHEEX_SIZE];
} }
else else
{ {
PanicAlert("JitBlockCache::Init() - iCache is already initialized"); PanicAlert("JitBlockCache::Init() - iCache is already initialized");
} }
if (iCache == 0) if (iCache == 0 || iCacheEx == 0)
{ {
PanicAlert("JitBlockCache::Init() - unable to allocate iCache"); PanicAlert("JitBlockCache::Init() - unable to allocate iCache");
} }
memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE); memset(iCache, JIT_ICACHE_INVALID_BYTE, JIT_ICACHE_SIZE);
memset(iCacheEx, JIT_ICACHE_INVALID_BYTE, JIT_ICACHEEX_SIZE);
#endif #endif
Clear(); Clear();
} }
@ -111,6 +113,9 @@ bool JitBlock::ContainsAddress(u32 em_address)
if (iCache != 0) if (iCache != 0)
delete [] iCache; delete [] iCache;
iCache = 0; iCache = 0;
if (iCacheEx != 0)
delete [] iCacheEx;
iCacheEx = 0;
#endif #endif
blocks = 0; blocks = 0;
blockCodePointers = 0; blockCodePointers = 0;
@ -224,10 +229,15 @@ bool JitBlock::ContainsAddress(u32 em_address)
} }
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
u8 *JitBlockCache::GetICache() u8* JitBlockCache::GetICache()
{ {
return iCache; return iCache;
} }
u8* JitBlockCache::GetICacheEx()
{
return iCacheEx;
}
#endif #endif
int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr) int JitBlockCache::GetBlockNumberFromStartAddress(u32 addr)
@ -235,7 +245,15 @@ bool JitBlock::ContainsAddress(u32 em_address)
if (!blocks) if (!blocks)
return -1; return -1;
#ifdef JIT_UNLIMITED_ICACHE #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); inst = Common::swap32(inst);
#else #else
u32 inst = Memory::ReadFast32(addr); u32 inst = Memory::ReadFast32(addr);
@ -369,16 +387,29 @@ bool JitBlock::ContainsAddress(u32 em_address)
} }
if (it1 != it2) 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 #ifdef JIT_UNLIMITED_ICACHE
// invalidate iCache // invalidate iCache.
if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000) // 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; return;
} }
u32 cacheaddr = address & JIT_ICACHE_MASK; if (address & JIT_ICACHE_EXRAM_BIT)
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); {
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 #endif
} }

View File

@ -34,6 +34,9 @@
#define JIT_ICACHE_SIZE 0x2000000 #define JIT_ICACHE_SIZE 0x2000000
#define JIT_ICACHE_MASK 0x1ffffff #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 // this corresponds to opcode 5 which is invalid in PowerPC
#define JIT_ICACHE_INVALID_BYTE 0x14 #define JIT_ICACHE_INVALID_BYTE 0x14
#define JIT_ICACHE_INVALID_WORD 0x14141414 #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 std::map<std::pair<u32,u32>, u32> block_map; // (end_addr, start_addr) -> number
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
u8 *iCache; u8 *iCache;
u8 *iCacheEx;
#endif #endif
int MAX_NUM_BLOCKS; int MAX_NUM_BLOCKS;
@ -111,6 +115,7 @@ public:
const u8 **GetCodePointers(); const u8 **GetCodePointers();
#ifdef JIT_UNLIMITED_ICACHE #ifdef JIT_UNLIMITED_ICACHE
u8 *GetICache(); u8 *GetICache();
u8 *GetICacheEx();
#endif #endif
// Fast way to get a block. Only works on the first ppc instruction of a block. // Fast way to get a block. Only works on the first ppc instruction of a block.

View File

@ -71,6 +71,7 @@ namespace PowerPC
memset(plru, 0, sizeof(plru)); memset(plru, 0, sizeof(plru));
#ifdef FAST_ICACHE #ifdef FAST_ICACHE
memset(lookup_table, 0xff, sizeof(lookup_table)); memset(lookup_table, 0xff, sizeof(lookup_table));
memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex));
#endif #endif
} }
@ -84,20 +85,31 @@ namespace PowerPC
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
if (valid[set] & (1<<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 #endif
valid[set] = 0; valid[set] = 0;
} }
u32 InstructionCache::ReadInstruction(u32 addr) u32 InstructionCache::ReadInstruction(u32 addr)
{ {
if (!HID0.ICE) // instuction cache is disabled if (!HID0.ICE) // instuction cache is disabled
return Memory::ReadUnchecked_U32(addr); return Memory::ReadUnchecked_U32(addr);
u32 set = (addr >> 5) & 0x7f; u32 set = (addr >> 5) & 0x7f;
u32 tag = addr >> 12; u32 tag = addr >> 12;
#ifdef FAST_ICACHE #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 #else
u32 t = 0xff; u32 t = 0xff;
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
@ -121,15 +133,24 @@ namespace PowerPC
memcpy(data[set][t], p, 32); memcpy(data[set][t], p, 32);
#ifdef FAST_ICACHE #ifdef FAST_ICACHE
if (valid[set] & (1<<t)) 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 #endif
tags[set][t] = tag; tags[set][t] = tag;
valid[set] |= 1<<t; valid[set] |= 1<<t;
} }
// update plru // update plru
plru[set] = (plru[set] & ~plru_mask[t]) | plru_value[t]; 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;
} }
} }

View File

@ -25,11 +25,13 @@
namespace PowerPC namespace PowerPC
{ {
const u32 ICACHE_SETS = 128; const u32 ICACHE_SETS = 128;
const u32 ICACHE_WAYS = 8; const u32 ICACHE_WAYS = 8;
// size of an instruction cache block in words // size of an instruction cache block in words
const u32 ICACHE_BLOCK_SIZE = 8; const u32 ICACHE_BLOCK_SIZE = 8;
const u32 ICACHE_EXRAM_BIT = 0x10000000;
struct InstructionCache struct InstructionCache
{ {
u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE]; u32 data[ICACHE_SETS][ICACHE_WAYS][ICACHE_BLOCK_SIZE];
@ -42,6 +44,7 @@ namespace PowerPC
#ifdef FAST_ICACHE #ifdef FAST_ICACHE
u8 lookup_table[1<<20]; u8 lookup_table[1<<20];
u8 lookup_table_ex[1<<21];
#endif #endif
InstructionCache(); InstructionCache();

View File

@ -67,7 +67,6 @@ struct GC_ALIGNED64(PowerPCState)
u32 spr[1024]; u32 spr[1024];
InstructionCache iCache; InstructionCache iCache;
// JIT-mode instruction cache. Managed by JitCache
}; };
enum CPUState enum CPUState

View File

@ -96,7 +96,8 @@ void DoState(PointerWrap &p)
HW::DoState(p); HW::DoState(p);
CoreTiming::DoState(p); CoreTiming::DoState(p);
#ifdef JIT_UNLIMITED_ICACHE #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 #endif
} }