Implement PPC write-back data cache

This commit is contained in:
TheLordScruffy committed 2022-12-08 18:18:32 -05:00
1 parent abf08b5869
commit e97d380437
22 files changed
+559 -132

No files matched your search

@@ -438,14 +438,17 @@ void Interpreter::dcba(UGeckoInstruction inst)
void Interpreter::dcbf(UGeckoInstruction inst)
{
// TODO: Implement some sort of L2 emulation.
// TODO: Raise DSI if translation fails (except for direct-store segments).
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
JitInterface::InvalidateICacheLine(address);
if (!PowerPC::ppcState.m_enable_dcache)
{
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address);
return;
}
PowerPC::FlushCacheLine(address);
}
void Interpreter::dcbi(UGeckoInstruction inst)
@@ -456,42 +459,44 @@ void Interpreter::dcbi(UGeckoInstruction inst)
return;
}
// TODO: Implement some sort of L2 emulation.
// TODO: Raise DSI if translation fails (except for direct-store segments).
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
JitInterface::InvalidateICacheLine(address);
if (!PowerPC::ppcState.m_enable_dcache)
{
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address);
return;
}
PowerPC::InvalidateCacheLine(address);
}
void Interpreter::dcbst(UGeckoInstruction inst)
{
// TODO: Implement some sort of L2 emulation.
// TODO: Raise DSI if translation fails (except for direct-store segments).
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
JitInterface::InvalidateICacheLine(address);
if (!PowerPC::ppcState.m_enable_dcache)
{
// Invalidate the JIT cache here as a heuristic to compensate for
// the lack of precise L1 icache emulation in the JIT. (Portable software
// should use icbi consistently, but games aren't portable.)
JitInterface::InvalidateICacheLine(address);
return;
}
PowerPC::StoreCacheLine(address);
}
// These instructions hint that it might be optimal to prefetch the specified cache line into the
// data cache. But the CPU is never guaranteed to do this fetch, and in practice it's not more
// performant to emulate it.
void Interpreter::dcbt(UGeckoInstruction inst)
{
if (HID0.NOOPTI)
return;
// TODO: Implement some sort of L2 emulation.
}
void Interpreter::dcbtst(UGeckoInstruction inst)
{
if (HID0.NOOPTI)
return;
// TODO: Implement some sort of L2 emulation.
}
void Interpreter::dcbz(UGeckoInstruction inst)
@@ -504,14 +509,17 @@ void Interpreter::dcbz(UGeckoInstruction inst)
return;
}
// Hack to stop dcbz/dcbi over low MEM1 trashing memory.
if ((dcbz_addr < 0x80008000) && (dcbz_addr >= 0x80000000) &&
Config::Get(Config::MAIN_LOW_DCBZ_HACK))
if (!PowerPC::ppcState.m_enable_dcache)
{
return;
// Hack to stop dcbz/dcbi over low MEM1 trashing memory. This is not needed if data cache
// emulation is enabled.
if ((dcbz_addr < 0x80008000) && (dcbz_addr >= 0x80000000) &&
Config::Get(Config::MAIN_LOW_DCBZ_HACK))
{
return;
}
}
// TODO: Implement some sort of L2 emulation.
PowerPC::ClearCacheLine(dcbz_addr & (~31));
}
@@ -531,7 +539,6 @@ void Interpreter::dcbz_l(UGeckoInstruction inst)
return;
}
// FAKE: clear memory instead of clearing the cache block
PowerPC::ClearCacheLine(address & (~31));
}
@@ -587,6 +594,7 @@ void Interpreter::icbi(UGeckoInstruction inst)
{
// TODO: Raise DSI if translation fails (except for direct-store segments).
const u32 address = Helper_Get_EA_X(PowerPC::ppcState, inst);
JitInterface::InvalidateICacheLine(address);
PowerPC::ppcState.iCache.Invalidate(address);
}
@@ -250,9 +250,32 @@ void Interpreter::mfspr(UGeckoInstruction inst)
rSPR(index) &= ~1;
}
break;
case SPR_XER:
rSPR(index) = PowerPC::GetXER().Hex;
break;
case SPR_UPMC1:
rSPR(index) = rSPR(SPR_PMC1);
break;
case SPR_UPMC2:
rSPR(index) = rSPR(SPR_PMC2);
break;
case SPR_UPMC3:
rSPR(index) = rSPR(SPR_PMC3);
break;
case SPR_UPMC4:
rSPR(index) = rSPR(SPR_PMC4);
break;
case SPR_IABR:
// A strange quirk: reading back this register on hardware will always have this bit set to 0
// (despite the bit appearing to function normally when set). This does not apply to the DABR.
rGPR[inst.RD] = rSPR(index) & ~1;
return;
}
rGPR[inst.RD] = rSPR(index);
}