Added code to invalidate the JIT cache on dcbi and writes to memory.

This commit is contained in:
skidau 2011-10-27 21:08:35 +11:00
parent 9a627e89fb
commit e03fd9a942
7 changed files with 31 additions and 51 deletions

View File

@ -265,6 +265,7 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
((em_address & 0xF0000000) == 0xC0000000) ||
((em_address & 0xF0000000) == 0x00000000))
{
PowerPC::ppcState.iCache.InvalidateBlock(em_address);
*(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data);
return;
}
@ -272,6 +273,8 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
((em_address & 0xF0000000) == 0xD0000000) ||
((em_address & 0xF0000000) == 0x10000000))
{
// Should we invalidate jit blocks in exram?
//PowerPC::ppcState.iCache.InvalidateBlock(em_address);
*(T*)&m_pEXRAM[em_address & EXRAM_MASK] = bswap(data);
return;
}

View File

@ -369,6 +369,9 @@ void Interpreter::dcbi(UGeckoInstruction _inst)
{
// Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything.
// Seen used during initialization.
u32 address = Helper_Get_EA_X(_inst);
if (jit)
jit->GetBlockCache()->InvalidateICache(address & ~0x1f);
}
void Interpreter::dcbst(UGeckoInstruction _inst)

View File

@ -393,6 +393,7 @@ void STACKALIGN Jit64::Jit(u32 em_address)
{
ClearCache();
}
int block_num = blocks.AllocateBlock(em_address);
JitBlock *b = blocks.GetBlock(block_num);
blocks.FinalizeBlock(block_num, jo.enableBlocklink, DoJit(em_address, &code_buffer, b));
@ -612,14 +613,14 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
#ifdef _M_IX86
if (js.compilerPC & JIT_ICACHE_VMEM_BIT)
MOV(32, M((jit->GetBlockCache()->GetICacheVMEM() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
else if (js.blockStart & JIT_ICACHE_EXRAM_BIT)
else if (js.compilerPC & JIT_ICACHE_EXRAM_BIT)
MOV(32, M((jit->GetBlockCache()->GetICacheEx() + (js.compilerPC & JIT_ICACHEEX_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
else
MOV(32, M((jit->GetBlockCache()->GetICache() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD));
#else
if (js.compilerPC & JIT_ICACHE_VMEM_BIT)
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICacheVMEM() + (js.compilerPC & JIT_ICACHE_MASK)));
else if (js.blockStart & JIT_ICACHE_EXRAM_BIT)
else if (js.compilerPC & JIT_ICACHE_EXRAM_BIT)
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICacheEx() + (js.compilerPC & JIT_ICACHEEX_MASK)));
else
MOV(64, R(RAX), ImmPtr(jit->GetBlockCache()->GetICache() + (js.compilerPC & JIT_ICACHE_MASK)));

View File

@ -126,16 +126,16 @@ 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("Clearing code cache.", 3000);
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);
ClearSafe();
}
void JitBlockCache::ClearSafe()
@ -207,8 +207,9 @@ bool JitBlock::ContainsAddress(u32 em_address)
blockCodePointers[block_num] = code_ptr;
JitBlock &b = blocks[block_num];
b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress);
if ((b.originalAddress + b.originalSize) > code_high)
code_high = b.originalAddress + b.originalSize;
Memory::Write_Opcode_JIT(b.originalAddress, (JIT_OPCODE << 26) | block_num);
block_map[std::make_pair(b.originalAddress + 4 * b.originalSize - 1, b.originalAddress)] = block_num;
if (block_link)
{
for (int i = 0; i < 2; i++)
@ -355,79 +356,44 @@ bool JitBlock::ContainsAddress(u32 em_address)
void JitBlockCache::DestroyBlock(int block_num, bool invalidate)
{
if (block_num < 0 || block_num >= num_blocks)
{
PanicAlert("DestroyBlock: Invalid block number %d", block_num);
return;
}
JitBlock &b = blocks[block_num];
if (b.invalid)
{
if (invalidate)
PanicAlert("Invalidating invalid block %d", block_num);
return;
}
b.invalid = true;
#ifdef JIT_UNLIMITED_ICACHE
Memory::Write_Opcode_JIT(b.originalAddress, b.originalFirstOpcode?b.originalFirstOpcode:JIT_ICACHE_INVALID_WORD);
Memory::Write_Opcode_JIT(b.originalAddress, JIT_ICACHE_INVALID_WORD);
#else
if (Memory::ReadFast32(b.originalAddress) == block_num)
Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.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.
// 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(jit->GetAsmRoutines()->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::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<pair<u32,u32>, 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)
{
DestroyBlock(it2->second, true);
it2++;
}
if (it1 != it2)
{
block_map.erase(it1, it2);
}
#ifdef JIT_UNLIMITED_ICACHE
// invalidate iCache.
// icbi can be called with any address, so we should check
if ((address & ~JIT_ICACHE_MASK) != 0x80000000 && (address & ~JIT_ICACHE_MASK) != 0x00000000 &&
(address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{
return;
}
if (address & JIT_ICACHE_VMEM_BIT)
{
u32 cacheaddr = address & JIT_ICACHE_MASK;
if (cacheaddr > (code_high & JIT_ICACHE_MASK))
return;
memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
}
else if (address & JIT_ICACHE_EXRAM_BIT)
{
u32 cacheaddr = address & JIT_ICACHEEX_MASK;
if (cacheaddr > (code_high & JIT_ICACHEEX_MASK))
return;
memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
}
else
{
u32 cacheaddr = address & JIT_ICACHE_MASK;
if (cacheaddr > (code_high & JIT_ICACHE_MASK))
return;
memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32);
}
#endif

View File

@ -76,7 +76,6 @@ class JitBlockCache
JitBlock *blocks;
int num_blocks;
std::multimap<u32, int> links_to;
std::map<std::pair<u32,u32>, u32> block_map; // (end_addr, start_addr) -> number
#ifdef JIT_UNLIMITED_ICACHE
u8 *iCache;
u8 *iCacheEx;
@ -105,6 +104,7 @@ public:
void Reset();
bool IsFull() const;
u32 code_high;
// Code Cache
JitBlock *GetBlock(int block_num);

View File

@ -82,8 +82,6 @@ namespace PowerPC
void InstructionCache::Invalidate(u32 addr)
{
if (jit)
jit->GetBlockCache()->InvalidateICache(addr);
if (!HID0.ICE)
return;
// invalidates the whole set
@ -101,6 +99,14 @@ namespace PowerPC
}
#endif
valid[set] = 0;
if (jit)
jit->GetBlockCache()->InvalidateICache(addr);
}
void InstructionCache::InvalidateBlock(u32 addr)
{
if (jit)
jit->GetBlockCache()->InvalidateICache(addr);
}
u32 InstructionCache::ReadInstruction(u32 addr)

View File

@ -53,6 +53,7 @@ namespace PowerPC
void Reset();
u32 ReadInstruction(u32 addr);
void Invalidate(u32 addr);
void InvalidateBlock(u32 addr);
};
}