Support fastmem on scratchpad

Disabled due to incorrect access time
This commit is contained in:
Connor McLaughlin 2020-09-06 22:55:00 +10:00
parent 5e45330703
commit dc2840daa2
4 changed files with 64 additions and 22 deletions

View File

@ -70,8 +70,9 @@ union MEMCTRL
}; };
std::bitset<CPU_CODE_CACHE_PAGE_COUNT> m_ram_code_bits{}; std::bitset<CPU_CODE_CACHE_PAGE_COUNT> m_ram_code_bits{};
u8* g_ram = nullptr; // 2MB RAM u8* g_ram = nullptr; // 2MB RAM
u8* g_bios = nullptr; // 512K BIOS ROM u8* g_bios = nullptr; // 512K BIOS ROM
u8* g_scratchpad = nullptr;
static std::array<TickCount, 3> m_exp1_access_time = {}; static std::array<TickCount, 3> m_exp1_access_time = {};
static std::array<TickCount, 3> m_exp2_access_time = {}; static std::array<TickCount, 3> m_exp2_access_time = {};
@ -89,11 +90,15 @@ static std::string m_tty_line_buffer;
static Common::MemoryArena m_memory_arena; static Common::MemoryArena m_memory_arena;
static u8* m_fastmem_base = nullptr; static u8* m_fastmem_base = nullptr;
static std::vector<Common::MemoryArena::View> m_fastmem_ram_views; static std::vector<Common::MemoryArena::View> m_fastmem_ram_views;
static std::vector<Common::MemoryArena::View> m_fastmem_scratchpad_views;
static std::vector<Common::MemoryArena::View> m_fastmem_bios_views;
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay); static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
static void RecalculateMemoryTimings(); static void RecalculateMemoryTimings();
static void SetCodePageFastmemProtection(u32 page_index, bool writable); static void SetCodePageFastmemProtection(u32 page_index, bool writable);
static bool AllocateMemory();
static void UnmapFastmemViews();
#define FIXUP_WORD_READ_OFFSET(offset) ((offset) & ~u32(3)) #define FIXUP_WORD_READ_OFFSET(offset) ((offset) & ~u32(3))
#define FIXUP_WORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8u)) #define FIXUP_WORD_READ_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8u))
@ -124,11 +129,13 @@ bool Initialize()
void Shutdown() void Shutdown()
{ {
m_fastmem_ram_views.clear(); UnmapFastmemViews();
if (g_ram) if (g_ram)
m_memory_arena.ReleaseViewPtr(g_ram, RAM_SIZE); m_memory_arena.ReleaseViewPtr(g_ram, RAM_SIZE);
if (g_bios) if (g_bios)
m_memory_arena.ReleaseViewPtr(g_bios, BIOS_SIZE); m_memory_arena.ReleaseViewPtr(g_bios, BIOS_SIZE);
if (g_scratchpad)
m_memory_arena.ReleaseViewPtr(g_scratchpad, FASTMEM_SCRATCHPAD_SIZE);
CPU::g_state.fastmem_base = nullptr; CPU::g_state.fastmem_base = nullptr;
} }
@ -136,6 +143,7 @@ void Shutdown()
void Reset() void Reset()
{ {
std::memset(g_ram, 0, RAM_SIZE); std::memset(g_ram, 0, RAM_SIZE);
std::memset(g_scratchpad, 0, SCRATCHPAD_SIZE);
m_MEMCTRL.exp1_base = 0x1F000000; m_MEMCTRL.exp1_base = 0x1F000000;
m_MEMCTRL.exp2_base = 0x1F802000; m_MEMCTRL.exp2_base = 0x1F802000;
m_MEMCTRL.exp1_delay_size.bits = 0x0013243F; m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
@ -159,6 +167,7 @@ bool DoState(StateWrapper& sw)
sw.Do(&m_spu_access_time); sw.Do(&m_spu_access_time);
sw.DoBytes(g_ram, RAM_SIZE); sw.DoBytes(g_ram, RAM_SIZE);
sw.DoBytes(g_bios, BIOS_SIZE); sw.DoBytes(g_bios, BIOS_SIZE);
sw.DoBytes(g_scratchpad, SCRATCHPAD_SIZE);
sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs)); sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs));
sw.Do(&m_ram_size_reg); sw.Do(&m_ram_size_reg);
sw.Do(&m_tty_line_buffer); sw.Do(&m_tty_line_buffer);
@ -248,6 +257,8 @@ bool AllocateMemory()
// Create the base views. // Create the base views.
g_ram = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false)); g_ram = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false));
g_bios = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_BIOS_OFFSET, BIOS_SIZE, true, false)); g_bios = static_cast<u8*>(m_memory_arena.CreateViewPtr(MEMORY_ARENA_BIOS_OFFSET, BIOS_SIZE, true, false));
g_scratchpad = static_cast<u8*>(
m_memory_arena.CreateViewPtr(MEMORY_ARENA_SCRATCHPAD_OFFSET, FASTMEM_SCRATCHPAD_SIZE, true, false));
if (!g_ram || !g_bios) if (!g_ram || !g_bios)
{ {
Log_ErrorPrint("Failed to create base views of memory"); Log_ErrorPrint("Failed to create base views of memory");
@ -257,9 +268,16 @@ bool AllocateMemory()
return true; return true;
} }
void UpdateFastmemViews(bool enabled, bool isolate_cache) void UnmapFastmemViews()
{ {
m_fastmem_ram_views.clear(); m_fastmem_ram_views.clear();
m_fastmem_scratchpad_views.clear();
m_fastmem_bios_views.clear();
}
void UpdateFastmemViews(bool enabled, bool isolate_cache)
{
UnmapFastmemViews();
if (!enabled) if (!enabled)
{ {
m_fastmem_base = nullptr; m_fastmem_base = nullptr;
@ -296,15 +314,33 @@ void UpdateFastmemViews(bool enabled, bool isolate_cache)
{ {
u8* page_address = map_address + (i * CPU_CODE_CACHE_PAGE_SIZE); u8* page_address = map_address + (i * CPU_CODE_CACHE_PAGE_SIZE);
if (!m_memory_arena.SetPageProtection(page_address, CPU_CODE_CACHE_PAGE_SIZE, true, false, false)) if (!m_memory_arena.SetPageProtection(page_address, CPU_CODE_CACHE_PAGE_SIZE, true, false, false))
{
Log_ErrorPrintf("Failed to write-protect code page at %p"); Log_ErrorPrintf("Failed to write-protect code page at %p");
return;
}
} }
} }
m_fastmem_ram_views.push_back(std::move(view.value())); m_fastmem_ram_views.push_back(std::move(view.value()));
}; };
auto MapScratchpad = [](u32 base_address) {
u8* map_address = m_fastmem_base + base_address;
auto view =
m_memory_arena.CreateView(MEMORY_ARENA_SCRATCHPAD_OFFSET, FASTMEM_SCRATCHPAD_SIZE, true, false, map_address);
if (!view)
{
Log_ErrorPrintf("Failed to map scratchpad at fastmem area %p (offset 0x%08X)", map_address,
FASTMEM_SCRATCHPAD_SIZE);
return;
}
// mark all pages beyond the first as inaccessible
// we need to do this because of windows's stupidity with its 64K mapping granularity
if (!m_memory_arena.SetPageProtection(map_address + CPU_CODE_CACHE_PAGE_SIZE,
FASTMEM_SCRATCHPAD_SIZE - CPU_CODE_CACHE_PAGE_SIZE, false, false, false))
{
Log_ErrorPrintf("Failed to read/write protect scratchpad");
}
m_fastmem_scratchpad_views.push_back(std::move(view.value()));
};
auto MapBIOS = [](u32 base_address) { auto MapBIOS = [](u32 base_address) {
u8* map_address = m_fastmem_base + base_address; u8* map_address = m_fastmem_base + base_address;
auto view = m_memory_arena.CreateView(MEMORY_ARENA_BIOS_OFFSET, BIOS_SIZE, false, false, map_address); auto view = m_memory_arena.CreateView(MEMORY_ARENA_BIOS_OFFSET, BIOS_SIZE, false, false, map_address);
@ -314,17 +350,19 @@ void UpdateFastmemViews(bool enabled, bool isolate_cache)
return; return;
} }
m_fastmem_ram_views.push_back(std::move(view.value())); m_fastmem_bios_views.push_back(std::move(view.value()));
}; };
if (!isolate_cache) if (!isolate_cache)
{ {
// KUSEG - cached // KUSEG - cached
MapRAM(0x00000000); MapRAM(0x00000000);
// MapScratchpad(0x1F800000);
// MapBIOS(0x1FC00000); // MapBIOS(0x1FC00000);
// KSEG0 - cached // KSEG0 - cached
MapRAM(0x80000000); MapRAM(0x80000000);
// MapScratchpad(0x9F800000);
// MapBIOS(0x9FC00000); // MapBIOS(0x9FC00000);
} }
@ -411,7 +449,6 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size)
return false; return false;
} }
static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address,
u32& value) u32& value)
{ {
@ -1089,34 +1126,36 @@ static void WriteCacheControl(u32 value)
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>
ALWAYS_INLINE static TickCount DoScratchpadAccess(PhysicalMemoryAddress address, u32& value) ALWAYS_INLINE static TickCount DoScratchpadAccess(PhysicalMemoryAddress address, u32& value)
{ {
using namespace Bus;
const PhysicalMemoryAddress cache_offset = address & DCACHE_OFFSET_MASK; const PhysicalMemoryAddress cache_offset = address & DCACHE_OFFSET_MASK;
if constexpr (size == MemoryAccessSize::Byte) if constexpr (size == MemoryAccessSize::Byte)
{ {
if constexpr (type == MemoryAccessType::Read) if constexpr (type == MemoryAccessType::Read)
value = ZeroExtend32(g_state.dcache[cache_offset]); value = ZeroExtend32(g_scratchpad[cache_offset]);
else else
g_state.dcache[cache_offset] = Truncate8(value); g_scratchpad[cache_offset] = Truncate8(value);
} }
else if constexpr (size == MemoryAccessSize::HalfWord) else if constexpr (size == MemoryAccessSize::HalfWord)
{ {
if constexpr (type == MemoryAccessType::Read) if constexpr (type == MemoryAccessType::Read)
{ {
u16 temp; u16 temp;
std::memcpy(&temp, &g_state.dcache[cache_offset], sizeof(temp)); std::memcpy(&temp, &g_scratchpad[cache_offset], sizeof(temp));
value = ZeroExtend32(temp); value = ZeroExtend32(temp);
} }
else else
{ {
u16 temp = Truncate16(value); u16 temp = Truncate16(value);
std::memcpy(&g_state.dcache[cache_offset], &temp, sizeof(temp)); std::memcpy(&g_scratchpad[cache_offset], &temp, sizeof(temp));
} }
} }
else if constexpr (size == MemoryAccessSize::Word) else if constexpr (size == MemoryAccessSize::Word)
{ {
if constexpr (type == MemoryAccessType::Read) if constexpr (type == MemoryAccessType::Read)
std::memcpy(&value, &g_state.dcache[cache_offset], sizeof(value)); std::memcpy(&value, &g_scratchpad[cache_offset], sizeof(value));
else else
std::memcpy(&g_state.dcache[cache_offset], &value, sizeof(value)); std::memcpy(&g_scratchpad[cache_offset], &value, sizeof(value));
} }
return 0; return 0;
@ -1524,7 +1563,7 @@ void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize
if (read_ticks) if (read_ticks)
*read_ticks = 0; *read_ticks = 0;
return &g_state.dcache[paddr & DCACHE_OFFSET_MASK]; return &g_scratchpad[paddr & DCACHE_OFFSET_MASK];
} }
if (paddr >= BIOS_BASE && paddr < (BIOS_BASE + BIOS_SIZE)) if (paddr >= BIOS_BASE && paddr < (BIOS_BASE + BIOS_SIZE))
@ -1555,7 +1594,7 @@ void* GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize
#endif #endif
if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION)
return &g_state.dcache[paddr & DCACHE_OFFSET_MASK]; return &g_scratchpad[paddr & DCACHE_OFFSET_MASK];
return nullptr; return nullptr;
} }

View File

@ -20,6 +20,9 @@ enum : u32
EXP1_BASE = 0x1F000000, EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000, EXP1_SIZE = 0x800000,
EXP1_MASK = EXP1_SIZE - 1, EXP1_MASK = EXP1_SIZE - 1,
SCRATCHPAD_BASE = 0x1F800000,
SCRATCHPAD_SIZE = 0x400,
SCRATCHPAD_MASK = SCRATCHPAD_SIZE - 1,
MEMCTRL_BASE = 0x1F801000, MEMCTRL_BASE = 0x1F801000,
MEMCTRL_SIZE = 0x40, MEMCTRL_SIZE = 0x40,
MEMCTRL_MASK = MEMCTRL_SIZE - 1, MEMCTRL_MASK = MEMCTRL_SIZE - 1,
@ -73,12 +76,15 @@ enum : TickCount
enum : size_t enum : size_t
{ {
FASTMEM_SCRATCHPAD_SIZE = 0x10000,
// Our memory arena contains storage for RAM and BIOS. // Our memory arena contains storage for RAM and BIOS.
MEMORY_ARENA_SIZE = RAM_SIZE + BIOS_SIZE, MEMORY_ARENA_SIZE = RAM_SIZE + FASTMEM_SCRATCHPAD_SIZE + BIOS_SIZE,
// Offsets within the memory arena. // Offsets within the memory arena.
MEMORY_ARENA_RAM_OFFSET = 0, MEMORY_ARENA_RAM_OFFSET = 0,
MEMORY_ARENA_BIOS_OFFSET = MEMORY_ARENA_RAM_OFFSET + RAM_SIZE, MEMORY_ARENA_SCRATCHPAD_OFFSET = MEMORY_ARENA_RAM_OFFSET + RAM_SIZE,
MEMORY_ARENA_BIOS_OFFSET = MEMORY_ARENA_SCRATCHPAD_OFFSET + FASTMEM_SCRATCHPAD_SIZE,
// Fastmem region size is 4GB to cover the entire 32-bit address space. // Fastmem region size is 4GB to cover the entire 32-bit address space.
FASTMEM_REGION_SIZE = UINT64_C(0x100000000) FASTMEM_REGION_SIZE = UINT64_C(0x100000000)
@ -90,7 +96,6 @@ void Reset();
bool DoState(StateWrapper& sw); bool DoState(StateWrapper& sw);
u8* GetFastmemBase(); u8* GetFastmemBase();
bool AllocateMemory();
void UpdateFastmemViews(bool enabled, bool isolate_cache); void UpdateFastmemViews(bool enabled, bool isolate_cache);
void SetExpansionROM(std::vector<u8> data); void SetExpansionROM(std::vector<u8> data);
@ -99,6 +104,7 @@ void SetBIOS(const std::vector<u8>& image);
extern std::bitset<CPU_CODE_CACHE_PAGE_COUNT> m_ram_code_bits; extern std::bitset<CPU_CODE_CACHE_PAGE_COUNT> m_ram_code_bits;
extern u8* g_ram; // 2MB RAM extern u8* g_ram; // 2MB RAM
extern u8* g_bios; // 512K BIOS ROM extern u8* g_bios; // 512K BIOS ROM
extern u8* g_scratchpad; // 1KB scratchpad as 4K (in fastmem)
/// Returns true if the address specified is writable (RAM). /// Returns true if the address specified is writable (RAM).
ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address) ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address)

View File

@ -122,7 +122,6 @@ bool DoState(StateWrapper& sw)
sw.Do(&g_state.next_load_delay_reg); sw.Do(&g_state.next_load_delay_reg);
sw.Do(&g_state.next_load_delay_value); sw.Do(&g_state.next_load_delay_value);
sw.Do(&g_state.cache_control.bits); sw.Do(&g_state.cache_control.bits);
sw.DoBytes(g_state.dcache.data(), g_state.dcache.size());
if (!GTE::DoState(sw)) if (!GTE::DoState(sw))
return false; return false;

View File

@ -81,8 +81,6 @@ struct State
u8* fastmem_base = nullptr; u8* fastmem_base = nullptr;
// data cache (used as scratchpad)
std::array<u8, DCACHE_SIZE> dcache = {};
std::array<u32, ICACHE_LINES> icache_tags = {}; std::array<u32, ICACHE_LINES> icache_tags = {};
std::array<u8, ICACHE_SIZE> icache_data = {}; std::array<u8, ICACHE_SIZE> icache_data = {};
}; };