From e382df0d41288491f4adb5eb2b5dcbebf9ebc0d2 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 2 May 2021 20:46:48 +1000 Subject: [PATCH] Support expanding RAM to 8MB (dev console) --- src/core/bus.cpp | 99 ++++++++++++------- src/core/bus.h | 22 +++-- src/core/cheats.cpp | 8 +- src/core/cpu_code_cache.cpp | 6 +- src/core/cpu_code_cache.h | 2 +- src/core/cpu_core.cpp | 3 + src/core/cpu_recompiler_code_generator.cpp | 2 +- .../cpu_recompiler_code_generator_aarch32.cpp | 2 +- .../cpu_recompiler_code_generator_aarch64.cpp | 2 +- .../cpu_recompiler_code_generator_generic.cpp | 2 +- .../cpu_recompiler_code_generator_x64.cpp | 2 +- src/core/dma.cpp | 45 +++++---- src/core/host_interface.cpp | 1 + src/core/save_state_version.h | 2 +- src/core/settings.cpp | 2 + src/core/settings.h | 1 + src/core/system.cpp | 2 +- src/duckstation-qt/cheatmanagerdialog.cpp | 2 +- src/duckstation-qt/consolesettingswidget.cpp | 10 ++ src/duckstation-qt/consolesettingswidget.ui | 7 ++ src/frontend-common/cheevos.cpp | 2 +- 21 files changed, 146 insertions(+), 78 deletions(-) diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 4b852ae82..ffdb0bdae 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -71,8 +71,11 @@ union MEMCTRL }; }; -std::bitset m_ram_code_bits{}; -u8* g_ram = nullptr; // 2MB RAM +std::bitset m_ram_code_bits{}; +u32 m_ram_code_page_count = 0; +u8* g_ram = nullptr; // 2MB RAM +u32 g_ram_size = 0; +u32 g_ram_mask = 0; u8 g_bios[BIOS_SIZE]{}; // 512K BIOS ROM static std::array m_exp1_access_time = {}; @@ -106,7 +109,7 @@ static constexpr auto m_fastmem_ram_mirrors = static std::tuple CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay); static void RecalculateMemoryTimings(); -static bool AllocateMemory(); +static bool AllocateMemory(bool enable_8mb_ram); static void ReleaseMemory(); static void SetCodePageFastmemProtection(u32 page_index, bool writable); @@ -125,7 +128,7 @@ static void SetCodePageFastmemProtection(u32 page_index, bool writable); bool Initialize() { - if (!AllocateMemory()) + if (!AllocateMemory(g_settings.enable_8mb_ram)) { g_host_interface->ReportError("Failed to allocate memory"); return false; @@ -153,7 +156,7 @@ void Shutdown() void Reset() { - std::memset(g_ram, 0, RAM_SIZE); + std::memset(g_ram, 0, g_ram_size); m_MEMCTRL.exp1_base = 0x1F000000; m_MEMCTRL.exp2_base = 0x1F802000; m_MEMCTRL.exp1_delay_size.bits = 0x0013243F; @@ -170,12 +173,25 @@ void Reset() bool DoState(StateWrapper& sw) { + u32 ram_size = g_ram_size; + sw.DoEx(&ram_size, 52, static_cast(RAM_2MB_SIZE)); + if (ram_size != g_ram_size) + { + const bool using_8mb_ram = (ram_size == RAM_8MB_SIZE); + ReleaseMemory(); + if (!AllocateMemory(using_8mb_ram)) + return false; + + UpdateFastmemViews(m_fastmem_mode); + CPU::UpdateFastmemBase(); + } + sw.Do(&m_exp1_access_time); sw.Do(&m_exp2_access_time); sw.Do(&m_bios_access_time); sw.Do(&m_cdrom_access_time); sw.Do(&m_spu_access_time); - sw.DoBytes(g_ram, RAM_SIZE); + sw.DoBytes(g_ram, g_ram_size); sw.DoBytes(g_bios, BIOS_SIZE); sw.DoArray(m_MEMCTRL.regs, countof(m_MEMCTRL.regs)); sw.Do(&m_ram_size_reg); @@ -255,7 +271,7 @@ void RecalculateMemoryTimings() m_spu_access_time[2] + 1); } -bool AllocateMemory() +bool AllocateMemory(bool enable_8mb_ram) { if (!m_memory_arena.Create(MEMORY_ARENA_SIZE, true, false)) { @@ -264,14 +280,20 @@ bool AllocateMemory() } // Create the base views. - g_ram = static_cast(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false)); + const u32 ram_size = enable_8mb_ram ? RAM_8MB_SIZE : RAM_2MB_SIZE; + const u32 ram_mask = enable_8mb_ram ? RAM_8MB_MASK : RAM_2MB_MASK; + g_ram = static_cast(m_memory_arena.CreateViewPtr(MEMORY_ARENA_RAM_OFFSET, ram_size, true, false)); if (!g_ram) { - Log_ErrorPrint("Failed to create base views of memory"); + Log_ErrorPrintf("Failed to create base views of memory (%u bytes RAM)", ram_size); return false; } - Log_InfoPrintf("RAM is %u bytes at %p", RAM_SIZE, g_ram); + g_ram_mask = ram_mask; + g_ram_size = ram_size; + m_ram_code_page_count = enable_8mb_ram ? RAM_8MB_CODE_PAGE_COUNT : RAM_2MB_CODE_PAGE_COUNT; + + Log_InfoPrintf("RAM is %u bytes at %p", g_ram_size, g_ram); return true; } @@ -279,8 +301,10 @@ void ReleaseMemory() { if (g_ram) { - m_memory_arena.ReleaseViewPtr(g_ram, RAM_SIZE); + m_memory_arena.ReleaseViewPtr(g_ram, g_ram_size); g_ram = nullptr; + g_ram_mask = 0; + g_ram_size = 0; } m_memory_arena.Destroy(); @@ -354,15 +378,15 @@ void UpdateFastmemViews(CPUFastmemMode mode) auto MapRAM = [](u32 base_address) { u8* map_address = m_fastmem_base + base_address; - auto view = m_memory_arena.CreateView(MEMORY_ARENA_RAM_OFFSET, RAM_SIZE, true, false, map_address); + auto view = m_memory_arena.CreateView(MEMORY_ARENA_RAM_OFFSET, g_ram_size, true, false, map_address); if (!view) { - Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, RAM_SIZE); + Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, g_ram_size); return; } // mark all pages with code as non-writable - for (u32 i = 0; i < RAM_CODE_PAGE_COUNT; i++) + for (u32 i = 0; i < m_ram_code_page_count; i++) { if (m_ram_code_bits[i]) { @@ -386,7 +410,7 @@ void UpdateFastmemViews(CPUFastmemMode mode) auto view = m_memory_arena.CreateReservedView(end_address_inclusive - start_address + 1, map_address); if (!view) { - Log_ErrorPrintf("Failed to map RAM at fastmem area %p (offset 0x%08X)", map_address, RAM_SIZE); + Log_ErrorPrintf("Failed to map reserved region %p (size 0x%08X)", map_address, end_address_inclusive - start_address + 1); return; } @@ -432,7 +456,7 @@ void UpdateFastmemViews(CPUFastmemMode mode) } auto MapRAM = [](u32 base_address) { - for (u32 address = 0; address < RAM_SIZE; address += HOST_PAGE_SIZE) + for (u32 address = 0; address < g_ram_size; address += HOST_PAGE_SIZE) { SetLUTFastmemPage(base_address + address, &g_ram[address], !m_ram_code_bits[FastmemAddressToLUTPageIndex(address)]); @@ -474,7 +498,7 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address) #endif case CPUFastmemMode::LUT: - return (paddr < RAM_SIZE); + return (paddr < g_ram_size); case CPUFastmemMode::Disabled: default: @@ -556,7 +580,7 @@ void ClearRAMCodePageFlags() if (m_fastmem_mode == CPUFastmemMode::LUT) { - for (u32 i = 0; i < RAM_CODE_PAGE_COUNT; i++) + for (u32 i = 0; i < m_ram_code_page_count; i++) { const u32 addr = (i * HOST_PAGE_SIZE); for (u32 mirror_start : m_fastmem_ram_mirrors) @@ -567,7 +591,7 @@ void ClearRAMCodePageFlags() bool IsCodePageAddress(PhysicalMemoryAddress address) { - return IsRAMAddress(address) ? m_ram_code_bits[(address & RAM_MASK) / HOST_PAGE_SIZE] : false; + return IsRAMAddress(address) ? m_ram_code_bits[(address & g_ram_mask) / HOST_PAGE_SIZE] : false; } bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size) @@ -575,7 +599,7 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size) if (!IsRAMAddress(start_address)) return false; - start_address = (start_address & RAM_MASK); + start_address = (start_address & g_ram_mask); const u32 end_address = start_address + size; while (start_address < end_address) @@ -592,10 +616,10 @@ bool HasCodePagesInRange(PhysicalMemoryAddress start_address, u32 size) std::optional GetMemoryRegionForAddress(PhysicalMemoryAddress address) { - if (address < RAM_SIZE) + if (address < RAM_2MB_SIZE) return MemoryRegion::RAM; else if (address < RAM_MIRROR_END) - return static_cast(static_cast(MemoryRegion::RAM) + (address / RAM_SIZE)); + return static_cast(static_cast(MemoryRegion::RAM) + (address / RAM_2MB_SIZE)); else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE)) return MemoryRegion::EXP1; else if (address >= CPU::DCACHE_LOCATION && address < (CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE)) @@ -609,10 +633,10 @@ std::optional GetMemoryRegionForAddress(PhysicalMemoryAddress addr static constexpr std::array, static_cast(MemoryRegion::Count)> s_code_region_ranges = {{ - {0, RAM_SIZE}, - {RAM_SIZE, RAM_SIZE * 2}, - {RAM_SIZE * 2, RAM_SIZE * 3}, - {RAM_SIZE * 3, RAM_MIRROR_END}, + {0, RAM_2MB_SIZE}, + {RAM_2MB_SIZE, RAM_2MB_SIZE * 2}, + {RAM_2MB_SIZE * 2, RAM_2MB_SIZE * 3}, + {RAM_2MB_SIZE * 3, RAM_MIRROR_END}, {EXP1_BASE, EXP1_BASE + EXP1_SIZE}, {CPU::DCACHE_LOCATION, CPU::DCACHE_LOCATION + CPU::DCACHE_SIZE}, {BIOS_BASE, BIOS_BASE + BIOS_SIZE}, @@ -633,11 +657,17 @@ u8* GetMemoryRegionPointer(MemoryRegion region) switch (region) { case MemoryRegion::RAM: - case MemoryRegion::RAMMirror1: - case MemoryRegion::RAMMirror2: - case MemoryRegion::RAMMirror3: return g_ram; + case MemoryRegion::RAMMirror1: + return (g_ram + (RAM_2MB_SIZE & g_ram_mask)); + + case MemoryRegion::RAMMirror2: + return (g_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask)); + + case MemoryRegion::RAMMirror3: + return (g_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask)); + case MemoryRegion::EXP1: return nullptr; @@ -734,14 +764,13 @@ static TickCount DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, P if (type == MemoryAccessType::Read) value = UINT32_C(0xFFFFFFFF); - return 1; + return (type == MemoryAccessType::Read) ? 1 : 0; } template ALWAYS_INLINE static TickCount DoRAMAccess(u32 offset, u32& value) { - // TODO: Configurable mirroring. - offset &= UINT32_C(0x1FFFFF); + offset &= g_ram_mask; if constexpr (type == MemoryAccessType::Read) { if constexpr (size == MemoryAccessSize::Byte) @@ -1270,7 +1299,7 @@ ALWAYS_INLINE_RELEASE bool DoInstructionRead(PhysicalMemoryAddress address, void if (address < RAM_MIRROR_END) { - std::memcpy(data, &g_ram[address & RAM_MASK], sizeof(u32) * word_count); + std::memcpy(data, &g_ram[address & g_ram_mask], sizeof(u32) * word_count); if constexpr (add_ticks) g_state.pending_ticks += (icache_read ? 1 : RAM_READ_TICKS) * word_count; @@ -1523,7 +1552,7 @@ static ALWAYS_INLINE TickCount DoMemoryAccess(VirtualMemoryAddress address, u32& } } - if (address < 0x800000) + if (address < RAM_MIRROR_END) { return DoRAMAccess(address, value); } @@ -1860,7 +1889,7 @@ void* GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize if (read_ticks) *read_ticks = RAM_READ_TICKS; - return &g_ram[paddr & RAM_MASK]; + return &g_ram[paddr & g_ram_mask]; } if ((paddr & DCACHE_LOCATION_MASK) == DCACHE_LOCATION) diff --git a/src/core/bus.h b/src/core/bus.h index 228962113..90762450c 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -15,8 +15,10 @@ namespace Bus { enum : u32 { RAM_BASE = 0x00000000, - RAM_SIZE = 0x200000, - RAM_MASK = RAM_SIZE - 1, + RAM_2MB_SIZE = 0x200000, + RAM_2MB_MASK = RAM_2MB_SIZE - 1, + RAM_8MB_SIZE = 0x800000, + RAM_8MB_MASK = RAM_8MB_SIZE - 1, RAM_MIRROR_END = 0x800000, EXP1_BASE = 0x1F000000, EXP1_SIZE = 0x800000, @@ -78,7 +80,7 @@ enum : TickCount enum : size_t { // Our memory arena contains storage for RAM. - MEMORY_ARENA_SIZE = RAM_SIZE, + MEMORY_ARENA_SIZE = RAM_8MB_SIZE, // Offsets within the memory arena. MEMORY_ARENA_RAM_OFFSET = 0, @@ -87,8 +89,12 @@ enum : size_t // Fastmem region size is 4GB to cover the entire 32-bit address space. FASTMEM_REGION_SIZE = UINT64_C(0x100000000), #endif +}; - RAM_CODE_PAGE_COUNT = (RAM_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE, +enum : u32 +{ + RAM_2MB_CODE_PAGE_COUNT = (RAM_2MB_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE, + RAM_8MB_CODE_PAGE_COUNT = (RAM_8MB_SIZE + (HOST_PAGE_SIZE + 1)) / HOST_PAGE_SIZE, FASTMEM_LUT_NUM_PAGES = 0x100000, // 0x100000000 >> 12 FASTMEM_LUT_NUM_SLOTS = FASTMEM_LUT_NUM_PAGES * 2, @@ -107,8 +113,10 @@ bool CanUseFastmemForAddress(VirtualMemoryAddress address); void SetExpansionROM(std::vector data); void SetBIOS(const std::vector& image); -extern std::bitset m_ram_code_bits; -extern u8* g_ram; // 2MB RAM +extern std::bitset m_ram_code_bits; +extern u8* g_ram; // 2MB-8MB RAM +extern u32 g_ram_size; // Active size of RAM. +extern u32 g_ram_mask; // Active address bits for RAM. extern u8 g_bios[BIOS_SIZE]; // 512K BIOS ROM /// Returns true if the address specified is writable (RAM). @@ -120,7 +128,7 @@ ALWAYS_INLINE static bool IsRAMAddress(PhysicalMemoryAddress address) /// Returns the code page index for a RAM address. ALWAYS_INLINE static u32 GetRAMCodePageIndex(PhysicalMemoryAddress address) { - return (address & RAM_MASK) / HOST_PAGE_SIZE; + return (address & g_ram_mask) / HOST_PAGE_SIZE; } /// Returns true if the specified page contains code. diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index bb6f3ba77..818d2ca2c 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -54,7 +54,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address) if (address < Bus::RAM_MIRROR_END) { - std::memcpy(&result, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(result)); + std::memcpy(&result, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(result)); return result; } @@ -84,12 +84,12 @@ static void DoMemoryWrite(PhysicalMemoryAddress address, T value) { // Only invalidate code when it changes. T old_value; - std::memcpy(&old_value, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(old_value)); + std::memcpy(&old_value, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(old_value)); if (old_value != value) { - std::memcpy(&Bus::g_ram[address & Bus::RAM_MASK], &value, sizeof(value)); + std::memcpy(&Bus::g_ram[address & Bus::g_ram_mask], &value, sizeof(value)); - const u32 code_page_index = Bus::GetRAMCodePageIndex(address & Bus::RAM_MASK); + const u32 code_page_index = Bus::GetRAMCodePageIndex(address & Bus::g_ram_mask); if (Bus::IsRAMCodePage(code_page_index)) CPU::CodeCache::InvalidateBlocksWithPageIndex(code_page_index); } diff --git a/src/core/cpu_code_cache.cpp b/src/core/cpu_code_cache.cpp index 61846f270..e0e4892fb 100644 --- a/src/core/cpu_code_cache.cpp +++ b/src/core/cpu_code_cache.cpp @@ -55,7 +55,7 @@ ALWAYS_INLINE static u32 GetFastMapIndex(u32 pc) { return ((pc & PHYSICAL_MEMORY_ADDRESS_MASK) >= Bus::BIOS_BASE) ? (FAST_MAP_RAM_SLOT_COUNT + ((pc & Bus::BIOS_MASK) >> 2)) : - ((pc & Bus::RAM_MASK) >> 2); + ((pc & Bus::g_ram_mask) >> 2); } static void CompileDispatcher(); @@ -102,7 +102,7 @@ static void UnlinkBlock(CodeBlock* block); static void ClearState(); static BlockMap s_blocks; -static std::array, Bus::RAM_CODE_PAGE_COUNT> m_ram_block_map; +static std::array, Bus::RAM_8MB_CODE_PAGE_COUNT> m_ram_block_map; #ifdef WITH_RECOMPILER static HostCodeMap s_host_code_map; @@ -694,7 +694,7 @@ void FastCompileBlockFunction() void InvalidateBlocksWithPageIndex(u32 page_index) { - DebugAssert(page_index < Bus::RAM_CODE_PAGE_COUNT); + DebugAssert(page_index < Bus::RAM_8MB_CODE_PAGE_COUNT); auto& blocks = m_ram_block_map[page_index]; for (CodeBlock* block : blocks) { diff --git a/src/core/cpu_code_cache.h b/src/core/cpu_code_cache.h index ec1ab662e..d2fcd0375 100644 --- a/src/core/cpu_code_cache.h +++ b/src/core/cpu_code_cache.h @@ -18,7 +18,7 @@ namespace CPU { enum : u32 { - FAST_MAP_RAM_SLOT_COUNT = Bus::RAM_SIZE / 4, + FAST_MAP_RAM_SLOT_COUNT = Bus::RAM_8MB_SIZE / 4, FAST_MAP_BIOS_SLOT_COUNT = Bus::BIOS_SIZE / 4, FAST_MAP_TOTAL_SLOT_COUNT = FAST_MAP_RAM_SLOT_COUNT + FAST_MAP_BIOS_SLOT_COUNT, }; diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 199bbd4b9..0615dfc03 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -180,6 +180,9 @@ bool DoState(StateWrapper& sw) sw.Do(&g_state.icache_data); } + if (sw.IsReading()) + UpdateFastmemBase(); + return !sw.HasError(); } diff --git a/src/core/cpu_recompiler_code_generator.cpp b/src/core/cpu_recompiler_code_generator.cpp index 7a7900ecf..f659b71f7 100644 --- a/src/core/cpu_recompiler_code_generator.cpp +++ b/src/core/cpu_recompiler_code_generator.cpp @@ -2868,7 +2868,7 @@ CodeGenerator::SpeculativeValue CodeGenerator::SpeculativeReadMemory(VirtualMemo if (Bus::IsRAMAddress(phys_addr)) { - u32 ram_offset = phys_addr & Bus::RAM_MASK; + u32 ram_offset = phys_addr & Bus::g_ram_mask; std::memcpy(&value, &Bus::g_ram[ram_offset], sizeof(value)); return value; } diff --git a/src/core/cpu_recompiler_code_generator_aarch32.cpp b/src/core/cpu_recompiler_code_generator_aarch32.cpp index a5ef8ffca..76bc5e2be 100644 --- a/src/core/cpu_recompiler_code_generator_aarch32.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch32.cpp @@ -2004,7 +2004,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher() m_emit->str(a32::r0, a32::MemOperand(GetHostReg32(RCPUPTR), offsetof(State, current_instruction_pc))); // r1 <- (pc & RAM_MASK) >> 2 - m_emit->and_(a32::r1, a32::r0, Bus::RAM_MASK); + m_emit->and_(a32::r1, a32::r0, Bus::g_ram_mask); m_emit->lsr(a32::r1, a32::r1, 2); // r2 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT diff --git a/src/core/cpu_recompiler_code_generator_aarch64.cpp b/src/core/cpu_recompiler_code_generator_aarch64.cpp index 3d6e4346f..15f77cfc9 100644 --- a/src/core/cpu_recompiler_code_generator_aarch64.cpp +++ b/src/core/cpu_recompiler_code_generator_aarch64.cpp @@ -2219,7 +2219,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher() m_emit->str(a64::w8, a64::MemOperand(GetHostReg64(RCPUPTR), offsetof(State, current_instruction_pc))); // w9 <- (pc & RAM_MASK) >> 2 - m_emit->and_(a64::w9, a64::w8, Bus::RAM_MASK); + m_emit->and_(a64::w9, a64::w8, Bus::g_ram_mask); m_emit->lsr(a64::w9, a64::w9, 2); // w10 <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT diff --git a/src/core/cpu_recompiler_code_generator_generic.cpp b/src/core/cpu_recompiler_code_generator_generic.cpp index deeb347df..613dd14d3 100644 --- a/src/core/cpu_recompiler_code_generator_generic.cpp +++ b/src/core/cpu_recompiler_code_generator_generic.cpp @@ -44,7 +44,7 @@ Value CodeGenerator::EmitLoadGuestMemory(const CodeBlockInstruction& cbi, const if (g_settings.IsUsingFastmem() && Bus::IsRAMAddress(static_cast(address.constant_value))) { // have to mask away the high bits for mirrors, since we don't map them in fastmem - EmitLoadGuestRAMFastmem(Value::FromConstantU32(static_cast(address.constant_value) & Bus::RAM_MASK), size, + EmitLoadGuestRAMFastmem(Value::FromConstantU32(static_cast(address.constant_value) & Bus::g_ram_mask), size, result); } else diff --git a/src/core/cpu_recompiler_code_generator_x64.cpp b/src/core/cpu_recompiler_code_generator_x64.cpp index 195d2fae4..d3ced6fc6 100644 --- a/src/core/cpu_recompiler_code_generator_x64.cpp +++ b/src/core/cpu_recompiler_code_generator_x64.cpp @@ -2968,7 +2968,7 @@ CodeCache::DispatcherFunction CodeGenerator::CompileDispatcher() // ebx <- (pc & RAM_MASK) >> 2 m_emit->mov(m_emit->ebx, m_emit->eax); - m_emit->and_(m_emit->ebx, Bus::RAM_MASK); + m_emit->and_(m_emit->ebx, Bus::g_ram_mask); m_emit->shr(m_emit->ebx, 2); // ecx <- ((pc & BIOS_MASK) >> 2) + FAST_MAP_RAM_SLOT_COUNT diff --git a/src/core/dma.cpp b/src/core/dma.cpp index 5765ff6a8..7aa1cd910 100644 --- a/src/core/dma.cpp +++ b/src/core/dma.cpp @@ -17,6 +17,11 @@ #endif Log_SetChannel(DMA); +static u32 GetAddressMask() +{ + return Bus::g_ram_mask & 0xFFFFFFFCu; +} + DMA g_dma; DMA::DMA() = default; @@ -293,6 +298,7 @@ TickCount DMA::GetTransferHaltTicks() const bool DMA::TransferChannel(Channel channel) { ChannelState& cs = m_state[static_cast(channel)]; + const u32 mask = GetAddressMask(); const bool copy_to_device = cs.channel_control.copy_to_device; @@ -307,13 +313,13 @@ bool DMA::TransferChannel(Channel channel) { const u32 word_count = cs.block_control.manual.GetWordCount(); Log_DebugPrintf("DMA%u: Copying %u words %s 0x%08X", static_cast(channel), word_count, - copy_to_device ? "from" : "to", current_address & ADDRESS_MASK); + copy_to_device ? "from" : "to", current_address & mask); TickCount used_ticks; if (copy_to_device) - used_ticks = TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, word_count); + used_ticks = TransferMemoryToDevice(channel, current_address & mask, increment, word_count); else - used_ticks = TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, word_count); + used_ticks = TransferDeviceToMemory(channel, current_address & mask, increment, word_count); CPU::AddPendingTicks(used_ticks); } @@ -328,20 +334,20 @@ bool DMA::TransferChannel(Channel channel) } Log_DebugPrintf("DMA%u: Copying linked list starting at 0x%08X to device", static_cast(channel), - current_address & ADDRESS_MASK); + current_address & mask); u8* ram_pointer = Bus::g_ram; TickCount remaining_ticks = GetTransferSliceTicks(); while (cs.request && remaining_ticks > 0) { u32 header; - std::memcpy(&header, &ram_pointer[current_address & ADDRESS_MASK], sizeof(header)); + std::memcpy(&header, &ram_pointer[current_address & mask], sizeof(header)); CPU::AddPendingTicks(10); remaining_ticks -= 10; const u32 word_count = header >> 24; const u32 next_address = header & UINT32_C(0x00FFFFFF); - Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X", current_address & ADDRESS_MASK, + Log_TracePrintf(" .. linked list entry at 0x%08X size=%u(%u words) next=0x%08X", current_address & mask, word_count * UINT32_C(4), word_count, next_address); if (word_count > 0) { @@ -349,7 +355,7 @@ bool DMA::TransferChannel(Channel channel) remaining_ticks -= 5; const TickCount block_ticks = - TransferMemoryToDevice(channel, (current_address + sizeof(header)) & ADDRESS_MASK, 4, word_count); + TransferMemoryToDevice(channel, (current_address + sizeof(header)) & mask, 4, word_count); CPU::AddPendingTicks(block_ticks); remaining_ticks -= block_ticks; } @@ -383,7 +389,7 @@ bool DMA::TransferChannel(Channel channel) Log_DebugPrintf("DMA%u: Copying %u blocks of size %u (%u total words) %s 0x%08X", static_cast(channel), cs.block_control.request.GetBlockCount(), cs.block_control.request.GetBlockSize(), cs.block_control.request.GetBlockCount() * cs.block_control.request.GetBlockSize(), - copy_to_device ? "from" : "to", current_address & ADDRESS_MASK); + copy_to_device ? "from" : "to", current_address & mask); const u32 block_size = cs.block_control.request.GetBlockSize(); u32 blocks_remaining = cs.block_control.request.GetBlockCount(); @@ -395,8 +401,7 @@ bool DMA::TransferChannel(Channel channel) { blocks_remaining--; - const TickCount ticks = - TransferMemoryToDevice(channel, current_address & ADDRESS_MASK, increment, block_size); + const TickCount ticks = TransferMemoryToDevice(channel, current_address & mask, increment, block_size); CPU::AddPendingTicks(ticks); ticks_remaining -= ticks; @@ -409,8 +414,7 @@ bool DMA::TransferChannel(Channel channel) { blocks_remaining--; - const TickCount ticks = - TransferDeviceToMemory(channel, current_address & ADDRESS_MASK, increment, block_size); + const TickCount ticks = TransferDeviceToMemory(channel, current_address & mask, increment, block_size); CPU::AddPendingTicks(ticks); ticks_remaining -= ticks; @@ -490,8 +494,9 @@ void DMA::UnhaltTransfer(TickCount ticks) TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 increment, u32 word_count) { const u32* src_pointer = reinterpret_cast(Bus::g_ram + address); + const u32 mask = GetAddressMask(); if (channel != Channel::GPU && - (static_cast(increment) < 0 || ((address + (increment * word_count)) & ADDRESS_MASK) <= address)) + (static_cast(increment) < 0 || ((address + (increment * word_count)) & mask) <= address)) { // Use temp buffer if it's wrapping around if (m_transfer_buffer.size() < word_count) @@ -502,7 +507,7 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen for (u32 i = 0; i < word_count; i++) { std::memcpy(&m_transfer_buffer[i], &ram_pointer[address], sizeof(u32)); - address = (address + increment) & ADDRESS_MASK; + address = (address + increment) & mask; } } @@ -518,7 +523,7 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen u32 value; std::memcpy(&value, &ram_pointer[address], sizeof(u32)); g_gpu->DMAWrite(address, value); - address = (address + increment) & ADDRESS_MASK; + address = (address + increment) & mask; } g_gpu->EndDMAWrite(); } @@ -546,6 +551,8 @@ TickCount DMA::TransferMemoryToDevice(Channel channel, u32 address, u32 incremen TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 increment, u32 word_count) { + const u32 mask = GetAddressMask(); + if (channel == Channel::OTC) { // clear ordering table @@ -553,9 +560,9 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen const u32 word_count_less_1 = word_count - 1; for (u32 i = 0; i < word_count_less_1; i++) { - u32 value = ((address - 4) & ADDRESS_MASK); + u32 value = ((address - 4) & mask); std::memcpy(&ram_pointer[address], &value, sizeof(value)); - address = (address - 4) & ADDRESS_MASK; + address = (address - 4) & mask; } const u32 terminator = UINT32_C(0xFFFFFF); @@ -565,7 +572,7 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen } u32* dest_pointer = reinterpret_cast(&Bus::g_ram[address]); - if (static_cast(increment) < 0 || ((address + (increment * word_count)) & ADDRESS_MASK) <= address) + if (static_cast(increment) < 0 || ((address + (increment * word_count)) & mask) <= address) { // Use temp buffer if it's wrapping around if (m_transfer_buffer.size() < word_count) @@ -604,7 +611,7 @@ TickCount DMA::TransferDeviceToMemory(Channel channel, u32 address, u32 incremen for (u32 i = 0; i < word_count; i++) { std::memcpy(&ram_pointer[address], &m_transfer_buffer[i], sizeof(u32)); - address = (address + increment) & ADDRESS_MASK; + address = (address + increment) & mask; } } diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index 474a590d6..8ffcf2880 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -475,6 +475,7 @@ std::string HostInterface::GetShaderCacheBasePath() const void HostInterface::SetDefaultSettings(SettingsInterface& si) { si.SetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION)); + si.SetBoolValue("Console", "Enable8MBRAM", false); si.SetFloatValue("Main", "EmulationSpeed", 1.0f); si.SetFloatValue("Main", "FastForwardSpeed", 0.0f); diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index 9a261d34f..2a6d64da8 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -2,7 +2,7 @@ #include "types.h" static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; -static constexpr u32 SAVE_STATE_VERSION = 51; +static constexpr u32 SAVE_STATE_VERSION = 52; static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index f77ce99e5..0abcbe901 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -149,6 +149,7 @@ void Settings::Load(SettingsInterface& si) region = ParseConsoleRegionName(si.GetStringValue("Console", "Region", "NTSC-U").c_str()).value_or(DEFAULT_CONSOLE_REGION); + enable_8mb_ram = si.GetBoolValue("Console", "Enable8MBRAM", false); emulation_speed = si.GetFloatValue("Main", "EmulationSpeed", 1.0f); fast_forward_speed = si.GetFloatValue("Main", "FastForwardSpeed", 0.0f); @@ -340,6 +341,7 @@ void Settings::Load(SettingsInterface& si) void Settings::Save(SettingsInterface& si) const { si.SetStringValue("Console", "Region", GetConsoleRegionName(region)); + si.SetBoolValue("Console", "Enable8MBRAM", enable_8mb_ram); si.SetFloatValue("Main", "EmulationSpeed", emulation_speed); si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed); diff --git a/src/core/settings.h b/src/core/settings.h index 71e24e74a..534f1d17a 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -212,6 +212,7 @@ struct Settings bool bios_patch_tty_enable = false; bool bios_patch_fast_boot = false; + bool enable_8mb_ram = false; std::array controller_types{}; bool controller_disable_analog_mode_forcing = false; diff --git a/src/core/system.cpp b/src/core/system.cpp index e29160ead..8ad14096e 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1874,7 +1874,7 @@ bool DumpRAM(const char* filename) if (!IsValid()) return false; - return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::RAM_SIZE); + return FileSystem::WriteBinaryFile(filename, Bus::g_ram, Bus::g_ram_size); } bool DumpVRAM(const char* filename) diff --git a/src/duckstation-qt/cheatmanagerdialog.cpp b/src/duckstation-qt/cheatmanagerdialog.cpp index 515cdea80..a6eac41b9 100644 --- a/src/duckstation-qt/cheatmanagerdialog.cpp +++ b/src/duckstation-qt/cheatmanagerdialog.cpp @@ -125,7 +125,7 @@ void CheatManagerDialog::connectUi() if (index == 0) { m_ui.scanStartAddress->setText(formatHexValue(0, 8)); - m_ui.scanEndAddress->setText(formatHexValue(Bus::RAM_SIZE, 8)); + m_ui.scanEndAddress->setText(formatHexValue(Bus::g_ram_size, 8)); } else if (index == 1) { diff --git a/src/duckstation-qt/consolesettingswidget.cpp b/src/duckstation-qt/consolesettingswidget.cpp index 42a6e4ae7..86822a76a 100644 --- a/src/duckstation-qt/consolesettingswidget.cpp +++ b/src/duckstation-qt/consolesettingswidget.cpp @@ -31,6 +31,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.region, "Console", "Region", &Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName, Settings::DEFAULT_CONSOLE_REGION); + SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.enable8MBRAM, "Console", "Enable8MBRAM", false); SettingWidgetBinder::BindWidgetToEnumSetting(m_host_interface, m_ui.cpuExecutionMode, "CPU", "ExecutionMode", &Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName, Settings::DEFAULT_CPU_EXECUTION_MODE); @@ -53,6 +54,15 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(QtHostInterface* host_interface, QW tr("When this option is chosen, the clock speed set below will be used.")); dialog->registerWidgetHelp(m_ui.cpuClockSpeed, tr("Overclocking Percentage"), tr("100%"), tr("Selects the percentage of the normal clock speed the emulated hardware will run at.")); + dialog->registerWidgetHelp( + m_ui.enable8MBRAM, tr("Enable 8MB RAM (Dev Console)"), tr("Unchecked"), + tr("Enables an additional 6MB of RAM, usually present on dev consoles. Games have to use a larger heap size for " + "this additional RAM to be usable, and may break games which rely on memory mirrors, so it should only be used " + "with compatible mods.")); + dialog->registerWidgetHelp( + m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"), + tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. In some " + "cases also eliminates stutter when games initiate audio track playback.")); dialog->registerWidgetHelp( m_ui.cdromReadSpeedup, tr("CDROM Read Speedup"), tr("None (Double Speed)"), tr("Speeds up CD-ROM reads by the specified factor. Only applies to double-speed reads, and is ignored when audio " diff --git a/src/duckstation-qt/consolesettingswidget.ui b/src/duckstation-qt/consolesettingswidget.ui index 525027e7e..7f38ff665 100644 --- a/src/duckstation-qt/consolesettingswidget.ui +++ b/src/duckstation-qt/consolesettingswidget.ui @@ -42,6 +42,13 @@ + + + + Enable 8MB RAM (Dev Console) + + + diff --git a/src/frontend-common/cheevos.cpp b/src/frontend-common/cheevos.cpp index b256e5966..b0a2ae85b 100644 --- a/src/frontend-common/cheevos.cpp +++ b/src/frontend-common/cheevos.cpp @@ -1140,7 +1140,7 @@ static T DoMemoryRead(PhysicalMemoryAddress address) if (address < Bus::RAM_MIRROR_END) { - std::memcpy(&result, &Bus::g_ram[address & Bus::RAM_MASK], sizeof(result)); + std::memcpy(&result, &Bus::g_ram[address & Bus::g_ram_mask], sizeof(result)); return result; }