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

@ -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

View File

@ -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();

View File

@ -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
}

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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();

View File

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

View File

@ -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
}