mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-23 14:25:37 +00:00
CPU: Use partial icache fills for non-line-aligned addresses
This commit is contained in:
parent
3b3ad0c1cb
commit
be63d893cd
|
@ -1006,11 +1006,12 @@ TickCount GetICacheFillTicks(VirtualMemoryAddress address)
|
||||||
|
|
||||||
if (address < RAM_MIRROR_END)
|
if (address < RAM_MIRROR_END)
|
||||||
{
|
{
|
||||||
return 1 * (ICACHE_LINE_SIZE / sizeof(u32));
|
return 1 * ((ICACHE_LINE_SIZE - (address & (ICACHE_LINE_SIZE - 1))) / sizeof(u32));
|
||||||
}
|
}
|
||||||
else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE))
|
else if (address >= BIOS_BASE && address < (BIOS_BASE + BIOS_SIZE))
|
||||||
{
|
{
|
||||||
return m_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] * (ICACHE_LINE_SIZE / sizeof(u32));
|
return m_bios_access_time[static_cast<u32>(MemoryAccessSize::Word)] *
|
||||||
|
((ICACHE_LINE_SIZE - (address & (ICACHE_LINE_SIZE - 1))) / sizeof(u32));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1046,9 +1047,29 @@ void CheckAndUpdateICacheTags(u32 line_count, TickCount uncached_ticks)
|
||||||
u32 FillICache(VirtualMemoryAddress address)
|
u32 FillICache(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
const u32 line = GetICacheLine(address);
|
const u32 line = GetICacheLine(address);
|
||||||
g_state.icache_tags[line] = GetICacheTagForAddress(address);
|
|
||||||
u8* line_data = &g_state.icache_data[line * ICACHE_LINE_SIZE];
|
u8* line_data = &g_state.icache_data[line * ICACHE_LINE_SIZE];
|
||||||
DoInstructionRead<true, true, 4>(address & ~(ICACHE_LINE_SIZE - 1u), line_data);
|
u32 line_tag;
|
||||||
|
switch ((address >> 2) & 0x03u)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
DoInstructionRead<true, true, 4>(address & ~(ICACHE_LINE_SIZE - 1u), line_data);
|
||||||
|
line_tag = GetICacheTagForAddress(address);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
DoInstructionRead<true, true, 3>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x4), line_data + 0x4);
|
||||||
|
line_tag = GetICacheTagForAddress(address) | 0x1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
DoInstructionRead<true, true, 2>(address & (~(ICACHE_LINE_SIZE - 1u) | 0x8), line_data + 0x8);
|
||||||
|
line_tag = GetICacheTagForAddress(address) | 0x3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
DoInstructionRead<true, true, 1>(address & (~(ICACHE_LINE_SIZE - 1u) | 0xC), line_data + 0xC);
|
||||||
|
line_tag = GetICacheTagForAddress(address) | 0x7;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_state.icache_tags[line] = line_tag;
|
||||||
|
|
||||||
const u32 offset = GetICacheLineOffset(address);
|
const u32 offset = GetICacheLineOffset(address);
|
||||||
u32 result;
|
u32 result;
|
||||||
|
@ -1059,7 +1080,7 @@ u32 FillICache(VirtualMemoryAddress address)
|
||||||
void ClearICache()
|
void ClearICache()
|
||||||
{
|
{
|
||||||
std::memset(g_state.icache_data.data(), 0, ICACHE_SIZE);
|
std::memset(g_state.icache_data.data(), 0, ICACHE_SIZE);
|
||||||
g_state.icache_tags.fill(ICACHE_INVALD_BIT | ICACHE_DISABLED_BIT);
|
g_state.icache_tags.fill(ICACHE_INVALID_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE static u32 ReadICache(VirtualMemoryAddress address)
|
ALWAYS_INLINE_RELEASE static u32 ReadICache(VirtualMemoryAddress address)
|
||||||
|
@ -1076,7 +1097,7 @@ ALWAYS_INLINE_RELEASE static void WriteICache(VirtualMemoryAddress address, u32
|
||||||
{
|
{
|
||||||
const u32 line = GetICacheLine(address);
|
const u32 line = GetICacheLine(address);
|
||||||
const u32 offset = GetICacheLineOffset(address);
|
const u32 offset = GetICacheLineOffset(address);
|
||||||
g_state.icache_tags[line] = GetICacheTagForAddress(address) | ICACHE_INVALD_BIT;
|
g_state.icache_tags[line] = GetICacheTagForAddress(address) | ICACHE_INVALID_BITS;
|
||||||
std::memcpy(&g_state.icache_data[line * ICACHE_LINE_SIZE + offset], &value, sizeof(value));
|
std::memcpy(&g_state.icache_data[line * ICACHE_LINE_SIZE + offset], &value, sizeof(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,19 +1107,6 @@ static void WriteCacheControl(u32 value)
|
||||||
|
|
||||||
CacheControl changed_bits{g_state.cache_control.bits ^ value};
|
CacheControl changed_bits{g_state.cache_control.bits ^ value};
|
||||||
g_state.cache_control.bits = value;
|
g_state.cache_control.bits = value;
|
||||||
if (changed_bits.icache_enable)
|
|
||||||
{
|
|
||||||
if (g_state.cache_control.icache_enable)
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < ICACHE_LINES; i++)
|
|
||||||
g_state.icache_tags[i] &= ~ICACHE_DISABLED_BIT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < ICACHE_LINES; i++)
|
|
||||||
g_state.icache_tags[i] |= ICACHE_DISABLED_BIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<MemoryAccessType type, MemoryAccessSize size>
|
template<MemoryAccessType type, MemoryAccessSize size>
|
||||||
|
@ -1323,15 +1331,12 @@ bool FetchInstruction()
|
||||||
case 0x04: // KSEG0 - physical memory cached
|
case 0x04: // KSEG0 - physical memory cached
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
// TODO: icache
|
DoInstructionRead<true, false, 1>(address, &g_state.next_instruction.bits);
|
||||||
TickCount cycles;
|
|
||||||
DoInstructionRead(address, cycles, g_state.next_instruction.bits);
|
|
||||||
#else
|
#else
|
||||||
if (CompareICacheTag(address))
|
if (CompareICacheTag(address))
|
||||||
g_state.next_instruction.bits = ReadICache(address);
|
g_state.next_instruction.bits = ReadICache(address);
|
||||||
else
|
else
|
||||||
g_state.next_instruction.bits = FillICache(address);
|
g_state.next_instruction.bits = FillICache(address);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -490,7 +490,6 @@ bool CompileBlock(CodeBlock* block)
|
||||||
if (icache_line != last_cache_line)
|
if (icache_line != last_cache_line)
|
||||||
{
|
{
|
||||||
block->icache_line_count++;
|
block->icache_line_count++;
|
||||||
block->icache_line_count = GetICacheFillTicks(pc);
|
|
||||||
last_cache_line = icache_line;
|
last_cache_line = icache_line;
|
||||||
}
|
}
|
||||||
block->uncached_fetch_ticks += GetInstructionReadTicks(pc);
|
block->uncached_fetch_ticks += GetInstructionReadTicks(pc);
|
||||||
|
|
|
@ -25,13 +25,8 @@ enum : PhysicalMemoryAddress
|
||||||
ICACHE_LINE_SIZE = 16,
|
ICACHE_LINE_SIZE = 16,
|
||||||
ICACHE_LINES = ICACHE_SIZE / ICACHE_LINE_SIZE,
|
ICACHE_LINES = ICACHE_SIZE / ICACHE_LINE_SIZE,
|
||||||
ICACHE_SLOTS_PER_LINE = ICACHE_SLOTS / ICACHE_LINES,
|
ICACHE_SLOTS_PER_LINE = ICACHE_SLOTS / ICACHE_LINES,
|
||||||
ICACHE_TAG_ADDRESS_MASK = 0xFFFFFFF0u
|
ICACHE_TAG_ADDRESS_MASK = 0xFFFFFFF0u,
|
||||||
};
|
ICACHE_INVALID_BITS = 0x0Fu,
|
||||||
|
|
||||||
enum : u32
|
|
||||||
{
|
|
||||||
ICACHE_DISABLED_BIT = 0x01,
|
|
||||||
ICACHE_INVALD_BIT = 0x02,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
union CacheControl
|
union CacheControl
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "cpu_core.h"
|
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
#include "cpu_core.h"
|
||||||
|
|
||||||
namespace CPU {
|
namespace CPU {
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ void RaiseException(u32 CAUSE_bits, u32 EPC);
|
||||||
ALWAYS_INLINE bool HasPendingInterrupt()
|
ALWAYS_INLINE bool HasPendingInterrupt()
|
||||||
{
|
{
|
||||||
return g_state.cop0_regs.sr.IEc &&
|
return g_state.cop0_regs.sr.IEc &&
|
||||||
(((g_state.cop0_regs.cause.bits & g_state.cop0_regs.sr.bits) & (UINT32_C(0xFF) << 8)) != 0);
|
(((g_state.cop0_regs.cause.bits & g_state.cop0_regs.sr.bits) & (UINT32_C(0xFF) << 8)) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void CheckForPendingInterrupt()
|
ALWAYS_INLINE void CheckForPendingInterrupt()
|
||||||
|
@ -40,10 +40,23 @@ ALWAYS_INLINE u32 GetICacheTagForAddress(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
return (address & ICACHE_TAG_ADDRESS_MASK);
|
return (address & ICACHE_TAG_ADDRESS_MASK);
|
||||||
}
|
}
|
||||||
|
ALWAYS_INLINE u32 GetICacheFillTagForAddress(VirtualMemoryAddress address)
|
||||||
|
{
|
||||||
|
static const u32 invalid_bits[4] = {0, 1, 3, 7};
|
||||||
|
return GetICacheTagForAddress(address) | invalid_bits[(address >> 2) & 0x03u];
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE u32 GetICacheTagMaskForAddress(VirtualMemoryAddress address)
|
||||||
|
{
|
||||||
|
const u32 offset = (address >> 2) & 0x03u;
|
||||||
|
static const u32 mask[4] = {ICACHE_TAG_ADDRESS_MASK | 1, ICACHE_TAG_ADDRESS_MASK | 2, ICACHE_TAG_ADDRESS_MASK | 4,
|
||||||
|
ICACHE_TAG_ADDRESS_MASK | 8};
|
||||||
|
return mask[(address >> 2) & 0x03u];
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool CompareICacheTag(VirtualMemoryAddress address)
|
ALWAYS_INLINE bool CompareICacheTag(VirtualMemoryAddress address)
|
||||||
{
|
{
|
||||||
const u32 line = GetICacheLine(address);
|
const u32 line = GetICacheLine(address);
|
||||||
return (g_state.icache_tags[line] == GetICacheTagForAddress(address));
|
return ((g_state.icache_tags[line] & GetICacheTagMaskForAddress(address)) == GetICacheTagForAddress(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
TickCount GetInstructionReadTicks(VirtualMemoryAddress address);
|
TickCount GetInstructionReadTicks(VirtualMemoryAddress address);
|
||||||
|
|
Loading…
Reference in a new issue