diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 340bca2c5..6e50e5055 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -70,8 +70,9 @@ union MEMCTRL }; std::bitset 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_scratchpad = nullptr; static std::array m_exp1_access_time = {}; static std::array m_exp2_access_time = {}; @@ -89,11 +90,15 @@ static std::string m_tty_line_buffer; static Common::MemoryArena m_memory_arena; static u8* m_fastmem_base = nullptr; static std::vector m_fastmem_ram_views; +static std::vector m_fastmem_scratchpad_views; +static std::vector m_fastmem_bios_views; static std::tuple CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay); static void RecalculateMemoryTimings(); 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_VALUE(offset, value) ((value) >> (((offset)&u32(3)) * 8u)) @@ -124,11 +129,13 @@ bool Initialize() void Shutdown() { - m_fastmem_ram_views.clear(); + UnmapFastmemViews(); if (g_ram) m_memory_arena.ReleaseViewPtr(g_ram, RAM_SIZE); if (g_bios) 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; } @@ -136,6 +143,7 @@ void Shutdown() void Reset() { std::memset(g_ram, 0, RAM_SIZE); + std::memset(g_scratchpad, 0, SCRATCHPAD_SIZE); m_MEMCTRL.exp1_base = 0x1F000000; m_MEMCTRL.exp2_base = 0x1F802000; m_MEMCTRL.exp1_delay_size.bits = 0x0013243F; @@ -159,6 +167,7 @@ bool DoState(StateWrapper& sw) sw.Do(&m_spu_access_time); sw.DoBytes(g_ram, RAM_SIZE); sw.DoBytes(g_bios, BIOS_SIZE); + sw.DoBytes(g_scratchpad, SCRATCHPAD_SIZE); sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs)); sw.Do(&m_ram_size_reg); sw.Do(&m_tty_line_buffer); @@ -248,6 +257,8 @@ bool AllocateMemory() // Create the base views. g_ram = static_cast(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false)); g_bios = static_cast(m_memory_arena.CreateViewPtr(MEMORY_ARENA_BIOS_OFFSET, BIOS_SIZE, true, false)); + g_scratchpad = static_cast( + m_memory_arena.CreateViewPtr(MEMORY_ARENA_SCRATCHPAD_OFFSET, FASTMEM_SCRATCHPAD_SIZE, true, false)); if (!g_ram || !g_bios) { Log_ErrorPrint("Failed to create base views of memory"); @@ -257,9 +268,16 @@ bool AllocateMemory() return true; } -void UpdateFastmemViews(bool enabled, bool isolate_cache) +void UnmapFastmemViews() { 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) { 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); 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"); - return; - } } } 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) { u8* map_address = m_fastmem_base + base_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; } - m_fastmem_ram_views.push_back(std::move(view.value())); + m_fastmem_bios_views.push_back(std::move(view.value())); }; if (!isolate_cache) { // KUSEG - cached MapRAM(0x00000000); + // MapScratchpad(0x1F800000); // MapBIOS(0x1FC00000); // KSEG0 - cached MapRAM(0x80000000); + // MapScratchpad(0x9F800000); // MapBIOS(0x9FC00000); } @@ -411,7 +449,6 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size) return false; } - static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value) { @@ -1089,34 +1126,36 @@ static void WriteCacheControl(u32 value) template ALWAYS_INLINE static TickCount DoScratchpadAccess(PhysicalMemoryAddress address, u32& value) { + using namespace Bus; + const PhysicalMemoryAddress cache_offset = address & DCACHE_OFFSET_MASK; if constexpr (size == MemoryAccessSize::Byte) { if constexpr (type == MemoryAccessType::Read) - value = ZeroExtend32(g_state.dcache[cache_offset]); + value = ZeroExtend32(g_scratchpad[cache_offset]); else - g_state.dcache[cache_offset] = Truncate8(value); + g_scratchpad[cache_offset] = Truncate8(value); } else if constexpr (size == MemoryAccessSize::HalfWord) { if constexpr (type == MemoryAccessType::Read) { u16 temp; - std::memcpy(&temp, &g_state.dcache[cache_offset], sizeof(temp)); + std::memcpy(&temp, &g_scratchpad[cache_offset], sizeof(temp)); value = ZeroExtend32(temp); } else { 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) { 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 - std::memcpy(&g_state.dcache[cache_offset], &value, sizeof(value)); + std::memcpy(&g_scratchpad[cache_offset], &value, sizeof(value)); } return 0; @@ -1524,7 +1563,7 @@ void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize if (read_ticks) *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)) @@ -1555,7 +1594,7 @@ void* GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize #endif if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) - return &g_state.dcache[paddr & DCACHE_OFFSET_MASK]; + return &g_scratchpad[paddr & DCACHE_OFFSET_MASK]; return nullptr; } diff --git a/src/core/bus.h b/src/core/bus.h index ef1905bee..921a68931 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -20,6 +20,9 @@ enum : u32 EXP1_BASE = 0x1F000000, EXP1_SIZE = 0x800000, EXP1_MASK = EXP1_SIZE - 1, + SCRATCHPAD_BASE = 0x1F800000, + SCRATCHPAD_SIZE = 0x400, + SCRATCHPAD_MASK = SCRATCHPAD_SIZE - 1, MEMCTRL_BASE = 0x1F801000, MEMCTRL_SIZE = 0x40, MEMCTRL_MASK = MEMCTRL_SIZE - 1, @@ -73,12 +76,15 @@ enum : TickCount enum : size_t { + FASTMEM_SCRATCHPAD_SIZE = 0x10000, + // 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. 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 = UINT64_C(0x100000000) @@ -90,7 +96,6 @@ void Reset(); bool DoState(StateWrapper& sw); u8* GetFastmemBase(); -bool AllocateMemory(); void UpdateFastmemViews(bool enabled, bool isolate_cache); void SetExpansionROM(std::vector data); @@ -99,6 +104,7 @@ void SetBIOS(const std::vector& image); extern std::bitset m_ram_code_bits; extern u8* g_ram; // 2MB RAM 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). ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address) diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index a26e8cc60..6b5ca23fc 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -122,7 +122,6 @@ bool DoState(StateWrapper& sw) sw.Do(&g_state.next_load_delay_reg); sw.Do(&g_state.next_load_delay_value); sw.Do(&g_state.cache_control.bits); - sw.DoBytes(g_state.dcache.data(), g_state.dcache.size()); if (!GTE::DoState(sw)) return false; diff --git a/src/core/cpu_core.h b/src/core/cpu_core.h index 58d396d30..24bb4b442 100644 --- a/src/core/cpu_core.h +++ b/src/core/cpu_core.h @@ -81,8 +81,6 @@ struct State u8* fastmem_base = nullptr; - // data cache (used as scratchpad) - std::array dcache = {}; std::array icache_tags = {}; std::array icache_data = {}; };