dolphin/Source/Core/Core/PowerPC/PPCCache.cpp
Silent 6c21811090
Make DolphinAnalytics a true singleton - static local variables are initialized in a thread safe manner since C++11
Also works around a Visual Studio 2017 bug where static inline class fields are destructed multiple times
2019-06-23 21:43:47 +02:00

174 lines
4.2 KiB
C++

// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/PowerPC/PPCCache.h"
#include <cstring>
#include "Common/ChunkFile.h"
#include "Common/Swap.h"
#include "Core/Analytics.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PowerPC.h"
namespace PowerPC
{
static const u32 s_plru_mask[8] = {11, 11, 19, 19, 37, 37, 69, 69};
static const u32 s_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 << w))
w++;
way_from_valid[m] = w;
}
for (u32 m = 0; m < 128; m++)
{
u32 b[7];
for (int i = 0; i < 7; i++)
b[i] = m & (1 << i);
u32 w;
if (b[0])
if (b[2])
if (b[6])
w = 7;
else
w = 6;
else if (b[5])
w = 5;
else
w = 4;
else if (b[1])
if (b[4])
w = 3;
else
w = 2;
else if (b[3])
w = 1;
else
w = 0;
way_from_plru[m] = w;
}
}
void InstructionCache::Reset()
{
memset(valid, 0, sizeof(valid));
memset(plru, 0, sizeof(plru));
memset(lookup_table, 0xff, sizeof(lookup_table));
memset(lookup_table_ex, 0xff, sizeof(lookup_table_ex));
memset(lookup_table_vmem, 0xff, sizeof(lookup_table_vmem));
JitInterface::ClearSafe();
}
void InstructionCache::Init()
{
memset(data, 0, sizeof(data));
memset(tags, 0, sizeof(tags));
Reset();
}
void InstructionCache::Invalidate(u32 addr)
{
if (!HID0.ICE)
return;
// invalidates the whole set
u32 set = (addr >> 5) & 0x7f;
for (int i = 0; i < 8; i++)
if (valid[set] & (1 << i))
{
if (tags[set][i] & (ICACHE_VMEM_BIT >> 12))
lookup_table_vmem[((tags[set][i] << 7) | set) & 0xfffff] = 0xff;
else 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;
}
valid[set] = 0;
JitInterface::InvalidateICache(addr & ~0x1f, 32, false);
}
u32 InstructionCache::ReadInstruction(u32 addr)
{
if (!HID0.ICE) // instruction cache is disabled
return Memory::Read_U32(addr);
u32 set = (addr >> 5) & 0x7f;
u32 tag = addr >> 12;
u32 t;
if (addr & ICACHE_VMEM_BIT)
{
t = lookup_table_vmem[(addr >> 5) & 0xfffff];
}
else if (addr & ICACHE_EXRAM_BIT)
{
t = lookup_table_ex[(addr >> 5) & 0x1fffff];
}
else
{
t = lookup_table[(addr >> 5) & 0xfffff];
}
if (t == 0xff) // load to the cache
{
if (HID0.ILOCK) // instruction cache is locked
return Memory::Read_U32(addr);
// select a way
if (valid[set] != 0xff)
t = way_from_valid[valid[set]];
else
t = way_from_plru[plru[set]];
// load
Memory::CopyFromEmu((u8*)data[set][t], (addr & ~0x1f), 32);
if (valid[set] & (1 << t))
{
if (tags[set][t] & (ICACHE_VMEM_BIT >> 12))
lookup_table_vmem[((tags[set][t] << 7) | set) & 0xfffff] = 0xff;
else 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_VMEM_BIT)
lookup_table_vmem[(addr >> 5) & 0xfffff] = t;
else if (addr & ICACHE_EXRAM_BIT)
lookup_table_ex[(addr >> 5) & 0x1fffff] = t;
else
lookup_table[(addr >> 5) & 0xfffff] = t;
tags[set][t] = tag;
valid[set] |= (1 << t);
}
// update plru
plru[set] = (plru[set] & ~s_plru_mask[t]) | s_plru_value[t];
u32 res = Common::swap32(data[set][t][(addr >> 2) & 7]);
u32 inmem = Memory::Read_U32(addr);
if (res != inmem)
{
INFO_LOG(POWERPC, "ICache read at %08x returned stale data: CACHED: %08x vs. RAM: %08x", addr,
res, inmem);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::ICACHE_MATTERS);
}
return res;
}
void InstructionCache::DoState(PointerWrap& p)
{
p.DoArray(data);
p.DoArray(tags);
p.DoArray(plru);
p.DoArray(valid);
p.DoArray(way_from_valid);
p.DoArray(way_from_plru);
p.DoArray(lookup_table);
p.DoArray(lookup_table_ex);
p.DoArray(lookup_table_vmem);
}
} // namespace PowerPC