Bus: Support 16MB expanded memory

16mb
Stenzek 4 months ago
parent a10d7f6ca8
commit 9431deb271
No known key found for this signature in database

@ -920,8 +920,8 @@ uint32_t Achievements::ClientReadMemory(uint32_t address, uint8_t* buffer, uint3
if ((address + num_bytes) > 0x200400U) [[unlikely]]
return 0;
const u8* src = (address >= 0x200000U) ? CPU::g_state.scratchpad.data() : Bus::g_ram;
const u32 offset = (address & Bus::RAM_2MB_MASK); // size guarded by check above
const u8* src = (address >= Bus::RAM_DEFAULT_SIZE) ? CPU::g_state.scratchpad.data() : Bus::g_ram;
const u32 offset = (address & Bus::RAM_DEFAULT_MASK); // size guarded by check above
switch (num_bytes)
{
@ -3626,8 +3626,8 @@ void Achievements::RAIntegrationWriteMemoryCallback(uint32_t address, uint8_t* b
// This can be called on the UI thread, so always queue it.
llvm::SmallVector<u8, 16> data(buffer, buffer + num_bytes);
Host::RunOnCoreThread([address, data = std::move(data)]() {
u8* src = (address >= 0x200000U) ? CPU::g_state.scratchpad.data() : Bus::g_ram;
const u32 offset = (address & Bus::RAM_2MB_MASK); // size guarded by check above
u8* src = (address >= Bus::RAM_DEFAULT_SIZE) ? CPU::g_state.scratchpad.data() : Bus::g_ram;
const u32 offset = (address & Bus::RAM_DEFAULT_MASK); // size guarded by check above
switch (data.size())
{

@ -122,7 +122,10 @@ union RAM_SIZE_REG
static void* s_shmem_handle = nullptr;
static std::string s_shmem_name;
std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits{};
// Sanity checks.
static_assert((Bus::RAM_MAX_SIZE % MIN_HOST_PAGE_SIZE) == 0, "RAM max size must be a multiple of host page size");
std::bitset<RAM_MAX_CODE_PAGE_COUNT> g_ram_code_bits{};
u8* g_ram = nullptr;
u8* g_unprotected_ram = nullptr;
u32 g_ram_size = 0;
@ -154,7 +157,7 @@ static bool s_kernel_initialize_hook_run = false;
static bool AllocateMemoryMap(bool export_shared_memory, Error* error);
static void ReleaseMemoryMap();
static void SetRAMSize(bool enable_8mb_ram);
static void SetRAMSize(u8 size);
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
static void RecalculateMemoryTimings();
@ -177,7 +180,7 @@ static void UpdateMappedRAMSize();
namespace MemoryMap {
static constexpr size_t RAM_OFFSET = 0;
static constexpr size_t RAM_SIZE = Bus::RAM_8MB_SIZE;
static constexpr size_t RAM_SIZE = Bus::RAM_MAX_SIZE;
static constexpr size_t BIOS_OFFSET = RAM_OFFSET + RAM_SIZE;
static constexpr size_t BIOS_SIZE = Bus::BIOS_SIZE;
static constexpr size_t LUT_OFFSET = BIOS_OFFSET + BIOS_SIZE;
@ -199,6 +202,8 @@ static constexpr size_t TOTAL_SIZE = LUT_OFFSET + LUT_SIZE;
bool Bus::AllocateMemoryMap(bool export_shared_memory, Error* error)
{
AssertMsg((RAM_MAX_SIZE % HOST_PAGE_SIZE) == 0, "Page size alignment is required for memory mapping");
INFO_LOG("Allocating{} shared memory map.", export_shared_memory ? " EXPORTED" : "");
if (export_shared_memory)
{
@ -252,7 +257,7 @@ bool Bus::AllocateMemoryMap(bool export_shared_memory, Error* error)
VERBOSE_LOG("LUTs are mapped at {}.", static_cast<void*>(g_memory_handlers));
g_memory_handlers_isc = g_memory_handlers + MEMORY_LUT_SLOTS;
g_ram_mapped_size = RAM_8MB_SIZE;
g_ram_mapped_size = RAM_DEFAULT_SIZE;
SetHandlers();
#ifndef __ANDROID__
@ -351,8 +356,8 @@ bool Bus::ReallocateMemoryMap(bool export_shared_memory, Error* error)
CPU::CodeCache::InvalidateAllRAMBlocks();
UnmapFastmemViews();
ram_backup.resize(RAM_8MB_SIZE);
std::memcpy(ram_backup.data(), g_unprotected_ram, RAM_8MB_SIZE);
ram_backup.resize(RAM_MAX_SIZE);
std::memcpy(ram_backup.data(), g_unprotected_ram, RAM_MAX_SIZE);
bios_backup.resize(BIOS_SIZE);
std::memcpy(bios_backup.data(), g_bios, BIOS_SIZE);
}
@ -364,7 +369,7 @@ bool Bus::ReallocateMemoryMap(bool export_shared_memory, Error* error)
if (System::IsValid())
{
UpdateMappedRAMSize();
std::memcpy(g_unprotected_ram, ram_backup.data(), RAM_8MB_SIZE);
std::memcpy(g_unprotected_ram, ram_backup.data(), RAM_MAX_SIZE);
std::memcpy(g_bios, bios_backup.data(), BIOS_SIZE);
MapFastmemViews();
}
@ -383,14 +388,29 @@ void Bus::CleanupMemoryMap()
void Bus::Initialize()
{
SetRAMSize(g_settings.cpu_enable_8mb_ram);
SetRAMSize(g_settings.cpu_ram_size);
MapFastmemViews();
}
void Bus::SetRAMSize(bool enable_8mb_ram)
void Bus::SetRAMSize(u8 size)
{
g_ram_size = enable_8mb_ram ? RAM_8MB_SIZE : RAM_2MB_SIZE;
g_ram_mask = enable_8mb_ram ? RAM_8MB_MASK : RAM_2MB_MASK;
static constexpr u32 one_mb = 1048576;
if (size != 2 && size != 4 && size != 8 && size != 16)
{
ERROR_LOG("Invalid RAM size: {} MB. Defaulting to {} MB.", size, RAM_DEFAULT_SIZE / one_mb);
size = RAM_DEFAULT_SIZE / one_mb;
}
const u32 new_size = size * one_mb;
DebugAssert(Common::IsPow2(new_size));
// Ensure no old protection was left.
if (new_size > g_ram_size)
MemMap::MemProtect(g_ram + g_ram_size, new_size - g_ram_size, PageProtect::ReadWrite);
g_ram_size = size * one_mb;
g_ram_mask = g_ram_size - 1;
#ifndef __ANDROID__
Exports::RAM_SIZE = g_ram_size;
@ -434,11 +454,10 @@ void Bus::Reset()
bool Bus::DoState(StateWrapper& sw)
{
u32 ram_size = g_ram_size;
sw.DoEx(&ram_size, 52, static_cast<u32>(RAM_2MB_SIZE));
sw.DoEx(&ram_size, 52, static_cast<u32>(RAM_DEFAULT_SIZE));
if (ram_size != g_ram_size)
{
const bool using_8mb_ram = (ram_size == RAM_8MB_SIZE);
SetRAMSize(using_8mb_ram);
SetRAMSize(static_cast<u8>(ram_size / 1048576));
RemapFastmemViews();
}
@ -595,7 +614,7 @@ void Bus::MapFastmemViews()
MapRAM(0xA0000000);
// Mirrors of 2MB
if (g_ram_size == RAM_2MB_SIZE)
if (g_ram_size == RAM_DEFAULT_SIZE)
{
// Instead of mapping all the RAM mirrors, we only map the KSEG0 uppermost mirror.
// This is where some games place their stack, so we avoid the backpatching overhead/slowdown,
@ -621,7 +640,37 @@ void Bus::MapFastmemViews()
for (u32 i = 0; i < FASTMEM_LUT_SLOTS; i++)
s_fastmem_lut[i] = GetLUTFastmemPointer(i << FASTMEM_LUT_PAGE_SHIFT, nullptr);
auto MapRAM = [](u32 base_address) {
static constexpr const std::array ranges = {
// KUSEG - cached
0x00000000u,
0x00200000u,
0x00400000u,
0x00600000u,
0x00800000u,
0x00A00000u,
// KSEG0 - cached
0x80000000u,
0x80200000u,
0x80400000u,
0x80600000u,
0x80800000u,
0x80A00000u,
0x80C00000u,
0x80E00000u,
// KSEG1 - uncached
0xA0000000u,
0xA0200000u,
0xA0400000u,
0xA0600000u,
0xA0800000u,
0xA0A00000u,
0xA0C00000u,
0xA0E00000u,
};
for (const u32 base_address : ranges)
{
// Don't map RAM that isn't accessible.
if (CPU::VirtualAddressToPhysical(base_address) >= g_ram_mapped_size)
return;
@ -633,25 +682,7 @@ void Bus::MapFastmemViews()
s_fastmem_lut[lut_index] = GetLUTFastmemPointer(base_address + address, ram_ptr);
ram_ptr += FASTMEM_LUT_PAGE_SIZE;
}
};
// KUSEG - cached
MapRAM(0x00000000);
MapRAM(0x00200000);
MapRAM(0x00400000);
MapRAM(0x00600000);
// KSEG0 - cached
MapRAM(0x80000000);
MapRAM(0x80200000);
MapRAM(0x80400000);
MapRAM(0x80600000);
// KSEG1 - uncached
MapRAM(0xA0000000);
MapRAM(0xA0200000);
MapRAM(0xA0400000);
MapRAM(0xA0600000);
}
}
CPU::UpdateMemoryPointers();
@ -689,7 +720,7 @@ bool Bus::CanUseFastmemForAddress(VirtualMemoryAddress address)
#endif
case CPUFastmemMode::LUT:
return (paddr < RAM_MIRROR_END);
return (paddr < g_ram_size);
case CPUFastmemMode::Disabled:
default:
@ -752,7 +783,7 @@ void Bus::ClearRAMCodePageFlags()
{
g_ram_code_bits.reset();
if (!MemMap::MemProtect(g_ram, RAM_8MB_SIZE, PageProtect::ReadWrite))
if (!MemMap::MemProtect(g_ram, g_ram_size, PageProtect::ReadWrite))
ERROR_LOG("Failed to restore RAM protection to read-write.");
#ifdef ENABLE_MMAP_FASTMEM
@ -806,10 +837,8 @@ const TickCount* Bus::GetMemoryAccessTimePtr(PhysicalMemoryAddress address, Memo
std::optional<Bus::MemoryRegion> Bus::GetMemoryRegionForAddress(PhysicalMemoryAddress address)
{
if (address < RAM_2MB_SIZE)
if (address < g_ram_size)
return MemoryRegion::RAM;
else if (address < RAM_MIRROR_END)
return static_cast<MemoryRegion>(static_cast<u32>(MemoryRegion::RAM) + (address / RAM_2MB_SIZE));
else if (address >= EXP1_BASE && address < (EXP1_BASE + EXP1_SIZE))
return MemoryRegion::EXP1;
else if (address >= CPU::SCRATCHPAD_ADDR && address < (CPU::SCRATCHPAD_ADDR + CPU::SCRATCHPAD_SIZE))
@ -823,10 +852,7 @@ std::optional<Bus::MemoryRegion> Bus::GetMemoryRegionForAddress(PhysicalMemoryAd
static constexpr std::array<std::tuple<PhysicalMemoryAddress, PhysicalMemoryAddress, bool>,
static_cast<u32>(Bus::MemoryRegion::Count)>
s_code_region_ranges = {{
{0, Bus::RAM_2MB_SIZE, true},
{Bus::RAM_2MB_SIZE, Bus::RAM_2MB_SIZE * 2, true},
{Bus::RAM_2MB_SIZE * 2, Bus::RAM_2MB_SIZE * 3, true},
{Bus::RAM_2MB_SIZE * 3, Bus::RAM_MIRROR_END, true},
{0, Bus::RAM_DEFAULT_SIZE, true},
{Bus::EXP1_BASE, Bus::EXP1_BASE + Bus::EXP1_SIZE, false},
{CPU::SCRATCHPAD_ADDR, CPU::SCRATCHPAD_ADDR + CPU::SCRATCHPAD_SIZE, true},
{Bus::BIOS_BASE, Bus::BIOS_BASE + Bus::BIOS_SIZE, false},
@ -839,6 +865,9 @@ PhysicalMemoryAddress Bus::GetMemoryRegionStart(MemoryRegion region)
PhysicalMemoryAddress Bus::GetMemoryRegionEnd(MemoryRegion region)
{
if (region == MemoryRegion::RAM)
return g_ram_mask + 1;
return std::get<1>(s_code_region_ranges[static_cast<u32>(region)]);
}
@ -854,15 +883,6 @@ u8* Bus::GetMemoryRegionPointer(MemoryRegion region)
case MemoryRegion::RAM:
return g_unprotected_ram;
case MemoryRegion::RAMMirror1:
return (g_unprotected_ram + (RAM_2MB_SIZE & g_ram_mask));
case MemoryRegion::RAMMirror2:
return (g_unprotected_ram + ((RAM_2MB_SIZE * 2) & g_ram_mask));
case MemoryRegion::RAMMirror3:
return (g_unprotected_ram + ((RAM_8MB_SIZE * 3) & g_ram_mask));
case MemoryRegion::EXP1:
return nullptr;
@ -2135,7 +2155,7 @@ void Bus::SetHandlers()
// KUSEG - Cached
// Cache isolated appears to affect KUSEG+KSEG0.
SET(g_memory_handlers, KUSEG | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KUSEG | RAM_BASE, g_ram_mapped_size, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KUSEG | CPU::SCRATCHPAD_ADDR, 0x1000, ScratchpadReadHandler, ScratchpadWriteHandler);
SET(g_memory_handlers, KUSEG | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
SET(g_memory_handlers, KUSEG | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
@ -2146,7 +2166,7 @@ void Bus::SetHandlers()
SET(g_memory_handlers_isc, KUSEG, 0x80000000, ICacheReadHandler, ICacheWriteHandler);
// KSEG0 - Cached
SET(g_memory_handlers, KSEG0 | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG0 | RAM_BASE, g_ram_mapped_size, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG0 | CPU::SCRATCHPAD_ADDR, 0x1000, ScratchpadReadHandler, ScratchpadWriteHandler);
SET(g_memory_handlers, KSEG0 | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
SET(g_memory_handlers, KSEG0 | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
@ -2157,7 +2177,7 @@ void Bus::SetHandlers()
SET(g_memory_handlers_isc, KSEG0, 0x20000000, ICacheReadHandler, ICacheWriteHandler);
// KSEG1 - Uncached
SETUC(KSEG1 | RAM_BASE, RAM_MIRROR_SIZE, RAMReadHandler, RAMWriteHandler);
SETUC(KSEG1 | RAM_BASE, g_ram_mapped_size, RAMReadHandler, RAMWriteHandler);
SETUC(KSEG1 | BIOS_BASE, BIOS_MIRROR_SIZE, BIOSReadHandler, IgnoreWriteHandler);
SETUC(KSEG1 | EXP1_BASE, EXP1_SIZE, EXP1ReadHandler, EXP1WriteHandler);
SETUC(KSEG1 | HW_BASE, HW_SIZE, HardwareReadHandler, HardwareWriteHandler);
@ -2173,51 +2193,41 @@ void Bus::UpdateMappedRAMSize()
{
const u32 prev_mapped_size = g_ram_mapped_size;
switch (s_RAM_SIZE.memory_window)
{
case 4: // 2MB memory + 6MB unmapped
{
// Used by Rock-Climbing - Mitouhou e no Chousen - Alps Hen (Japan).
// By default, all 8MB is mapped, so we only need to remap the high 6MB.
constexpr u32 MAPPED_SIZE = RAM_2MB_SIZE;
constexpr u32 UNMAPPED_START = RAM_BASE + MAPPED_SIZE;
constexpr u32 UNMAPPED_SIZE = RAM_MIRROR_SIZE - MAPPED_SIZE;
SET(g_memory_handlers, KUSEG | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
SET(g_memory_handlers, KSEG0 | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
SET(g_memory_handlers, KSEG1 | UNMAPPED_START, UNMAPPED_SIZE, UnmappedReadHandler, UnmappedWriteHandler);
g_ram_mapped_size = MAPPED_SIZE;
}
break;
// https://psx-spx.consoledev.net/memorycontrol/#1f801060h-ram_size-rw-usually-00000b88h-or-00000888h
static constexpr const u32 one_mb = 1024 * 1024;
static constexpr const u32 ram_mapped_sizes[] = {
1 * one_mb, // 000 = 1MB bank on /RAS0 + 15MB unmapped
4 * one_mb, // 001 = 4MB bank on /RAS0 + 12MB unmapped
2 * one_mb, // 010 = 1MB bank on /RAS0 + 1MB bank on /RAS1 (?) + 14MB unmapped
8 * one_mb, // 011 = 4MB bank on /RAS0 + 4MB bank on /RAS1 (?) + 8MB unmapped
2 * one_mb, // 100 = 2MB bank on /RAS0 + 14MB unmapped
16 * one_mb, // 101 = 8MB bank on /RAS0 + 8MB unmapped
4 * one_mb, // 110 = 2MB bank on /RAS0 + 2MB bank on /RAS1 (?) + 12MB unmapped
16 * one_mb, // 111 = 8MB bank on /RAS0 + 8MB bank on /RAS1 (?)
};
case 0: // 1MB memory + 7MB unmapped
case 1: // 4MB memory + 4MB unmapped
case 2: // 1MB memory + 1MB HighZ + 6MB unmapped
case 3: // 4MB memory + 4MB HighZ
case 6: // 2MB memory + 2MB HighZ + 4MB unmapped
case 7: // 8MB memory
{
// These aren't implemented because nothing is known to use them, so it can't be tested.
// If you find something that does, please let us know.
WARNING_LOG("Unhandled memory window 0x{} (register 0x{:08X}). Please report this game to developers.",
s_RAM_SIZE.memory_window.GetValue(), s_RAM_SIZE.bits);
}
[[fallthrough]];
const u32 mapped_size = ram_mapped_sizes[s_RAM_SIZE.memory_window];
if (mapped_size == prev_mapped_size)
return;
case 5: // 8MB memory
WARNING_LOG("RAM mapped size changed to {} MB", mapped_size / one_mb);
SET(g_memory_handlers, KUSEG | RAM_BASE, mapped_size, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG0 | RAM_BASE, mapped_size, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG1 | RAM_BASE, mapped_size, RAMReadHandler, RAMWriteHandler);
const u32 unmapped_size = RAM_MAX_SIZE - mapped_size;
if (unmapped_size > 0)
{
// We only unmap the upper 6MB above, so we only need to remap this as well.
constexpr u32 REMAP_START = RAM_BASE + RAM_2MB_SIZE;
constexpr u32 REMAP_SIZE = RAM_MIRROR_SIZE - RAM_2MB_SIZE;
SET(g_memory_handlers, KUSEG | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG0 | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
SET(g_memory_handlers, KSEG1 | REMAP_START, REMAP_SIZE, RAMReadHandler, RAMWriteHandler);
g_ram_mapped_size = RAM_8MB_SIZE;
}
break;
const u32 unmapped_base = RAM_BASE + mapped_size;
SET(g_memory_handlers, KUSEG | unmapped_base, unmapped_size, UnmappedReadHandler, UnmappedWriteHandler);
SET(g_memory_handlers, KSEG0 | unmapped_base, unmapped_size, UnmappedReadHandler, UnmappedWriteHandler);
SET(g_memory_handlers, KSEG1 | unmapped_base, unmapped_size, UnmappedReadHandler, UnmappedWriteHandler);
}
g_ram_mapped_size = mapped_size;
// Fastmem needs to be remapped.
if (prev_mapped_size != g_ram_mapped_size)
RemapFastmemViews();
}

@ -20,12 +20,10 @@ namespace Bus {
enum : u32
{
RAM_BASE = 0x00000000,
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,
RAM_MIRROR_SIZE = 0x800000,
RAM_DEFAULT_SIZE = 0x200000,
RAM_DEFAULT_MASK = RAM_DEFAULT_SIZE - 1,
RAM_MAX_SIZE = 0x1000000,
RAM_MAX_MASK = RAM_MAX_SIZE - 1,
EXP1_BASE = 0x1F000000,
EXP1_SIZE = 0x800000,
EXP1_MASK = EXP1_SIZE - 1,
@ -91,8 +89,7 @@ enum : TickCount
enum : u32
{
RAM_2MB_CODE_PAGE_COUNT = (RAM_2MB_SIZE + (MIN_HOST_PAGE_SIZE - 1)) / MIN_HOST_PAGE_SIZE,
RAM_8MB_CODE_PAGE_COUNT = (RAM_8MB_SIZE + (MIN_HOST_PAGE_SIZE - 1)) / MIN_HOST_PAGE_SIZE,
RAM_MAX_CODE_PAGE_COUNT = RAM_MAX_SIZE / MIN_HOST_PAGE_SIZE,
MEMORY_LUT_PAGE_SIZE = 4096,
MEMORY_LUT_PAGE_SHIFT = 12,
@ -144,7 +141,7 @@ void* GetFastmemBase(bool isc);
void RemapFastmemViews();
bool CanUseFastmemForAddress(VirtualMemoryAddress address);
extern std::bitset<RAM_8MB_CODE_PAGE_COUNT> g_ram_code_bits;
extern std::bitset<RAM_MAX_CODE_PAGE_COUNT> g_ram_code_bits;
extern u8* g_ram; // 2MB-8MB RAM
extern u8* g_unprotected_ram; // RAM without page protection, use for debugger access.
extern u32 g_ram_size; // Active size of RAM.
@ -160,7 +157,7 @@ extern std::array<TickCount, 3> g_spu_access_time;
/// Returns true if the address specified is writable (RAM).
ALWAYS_INLINE bool IsRAMAddress(PhysicalMemoryAddress address)
{
return address < RAM_MIRROR_END;
return (address < RAM_MAX_SIZE);
}
/// Returns the code page index for a RAM address.
@ -175,6 +172,12 @@ ALWAYS_INLINE bool IsRAMCodePage(u32 index)
return g_ram_code_bits[index];
}
/// Returns the number of RAM code pages for the current memory size.
ALWAYS_INLINE u32 GetRAMCodePageCount()
{
return (g_ram_size >> HOST_PAGE_SHIFT);
}
/// Flags a RAM region as code, so we know when to invalidate blocks.
void SetRAMCodePage(u32 index);
@ -206,9 +209,6 @@ const TickCount* GetMemoryAccessTimePtr(PhysicalMemoryAddress address, MemoryAcc
enum class MemoryRegion
{
RAM,
RAMMirror1,
RAMMirror2,
RAMMirror3,
EXP1,
Scratchpad,
BIOS,

@ -176,6 +176,7 @@ public:
bool has_options : 1;
bool disable_widescreen_rendering : 1;
bool enable_8mb_ram : 1;
bool enable_16mb_ram : 1;
bool disallow_for_achievements : 1;
};
@ -286,7 +287,7 @@ Cheats::CheatCode::~CheatCode() = default;
bool Cheats::CheatCode::HasAnySettingOverrides() const
{
return (m_metadata.disable_widescreen_rendering || m_metadata.enable_8mb_ram ||
return (m_metadata.disable_widescreen_rendering || m_metadata.enable_8mb_ram || m_metadata.enable_16mb_ram ||
m_metadata.override_aspect_ratio.has_value() || m_metadata.override_cpu_overclock.has_value());
}
@ -297,10 +298,15 @@ void Cheats::CheatCode::ApplySettingOverrides()
DEV_LOG("Disabling widescreen rendering from {} patch.", GetName());
g_settings.gpu_widescreen_hack = false;
}
if (m_metadata.enable_8mb_ram && !g_settings.cpu_enable_8mb_ram)
if (m_metadata.enable_16mb_ram && g_settings.cpu_ram_size != 16)
{
DEV_LOG("Enabling 16MB ram from {} patch.", GetName());
g_settings.cpu_ram_size = 16;
}
else if (m_metadata.enable_8mb_ram && g_settings.cpu_ram_size != 8)
{
DEV_LOG("Enabling 8MB ram from {} patch.", GetName());
g_settings.cpu_enable_8mb_ram = true;
g_settings.cpu_ram_size = 8;
}
if (m_metadata.override_aspect_ratio.has_value() && g_settings.display_aspect_ratio == DisplayAspectRatio::Auto())
{
@ -1643,7 +1649,13 @@ void Cheats::ParseFile(CheatCodeList* dst_list, const std::string_view file_cont
}
else if (key == "Enable8MBRAM")
{
next_code_metadata.enable_8mb_ram = StringUtil::FromChars<bool>(value).value_or(false);
next_code_metadata.enable_8mb_ram =
!next_code_metadata.enable_16mb_ram && StringUtil::FromChars<bool>(value).value_or(false);
}
else if (key == "Enable16MBRAM")
{
next_code_metadata.enable_16mb_ram = StringUtil::FromChars<bool>(value).value_or(false);
next_code_metadata.enable_8mb_ram = next_code_metadata.enable_8mb_ram && !next_code_metadata.enable_16mb_ram;
}
else if (key == "DisallowForAchievements")
{

@ -39,7 +39,7 @@ LOG_CHANNEL(CodeCache);
namespace CPU::CodeCache {
using LUTRangeList = std::array<std::pair<VirtualMemoryAddress, VirtualMemoryAddress>, 9>;
using PageProtectionArray = std::array<PageProtectionInfo, Bus::RAM_8MB_CODE_PAGE_COUNT>;
using PageProtectionArray = std::array<PageProtectionInfo, Bus::RAM_MAX_CODE_PAGE_COUNT>;
using BlockInstructionInfoPair = std::pair<Instruction, InstructionInfo>;
using BlockInstructionList = std::vector<BlockInstructionInfoPair>;
@ -565,7 +565,7 @@ void CPU::CodeCache::RemoveBlockFromPageList(Block* block)
void CPU::CodeCache::InvalidateBlocksWithPageIndex(u32 index)
{
DebugAssert(index < Bus::RAM_8MB_CODE_PAGE_COUNT);
DebugAssert(index < Bus::RAM_MAX_CODE_PAGE_COUNT);
Bus::ClearRAMCodePage(index);
BlockState new_block_state = BlockState::Invalidated;
@ -662,7 +662,8 @@ void CPU::CodeCache::InvalidateAllRAMBlocks()
void CPU::CodeCache::ClearBlocks()
{
for (u32 i = 0; i < Bus::RAM_8MB_CODE_PAGE_COUNT; i++)
const u32 page_count = Bus::GetRAMCodePageCount();
for (u32 i = 0; i < page_count; i++)
{
PageProtectionInfo& ppi = s_page_protection[i];
if (ppi.mode == PageProtectionMode::WriteProtected && ppi.first_block_in_page)
@ -689,7 +690,7 @@ PageFaultHandler::HandlerResult PageFaultHandler::HandlePageFault(void* exceptio
bool is_write)
{
if (Bus::g_ram && static_cast<const u8*>(fault_address) >= Bus::g_ram &&
static_cast<const u8*>(fault_address) < (Bus::g_ram + Bus::RAM_8MB_SIZE))
static_cast<const u8*>(fault_address) < (Bus::g_ram + Bus::g_ram_size))
{
// Writing to protected RAM.
DebugAssert(is_write);

@ -514,26 +514,22 @@ ALWAYS_INLINE_RELEASE void CPU::WriteRegDelayed(Reg rd, u32 value)
ALWAYS_INLINE_RELEASE bool CPU::IsCop0ExecutionBreakpointUnmasked()
{
static constexpr const u32 code_address_ranges[][2] = {
// KUSEG
{Bus::RAM_BASE, Bus::RAM_BASE | Bus::RAM_8MB_MASK},
{Bus::BIOS_BASE, Bus::BIOS_BASE | Bus::BIOS_MASK},
// KSEG0
{0x80000000u | Bus::RAM_BASE, 0x80000000u | Bus::RAM_BASE | Bus::RAM_8MB_MASK},
{0x80000000u | Bus::BIOS_BASE, 0x80000000u | Bus::BIOS_BASE | Bus::BIOS_MASK},
// KSEG1
{0xA0000000u | Bus::RAM_BASE, 0xA0000000u | Bus::RAM_BASE | Bus::RAM_8MB_MASK},
{0xA0000000u | Bus::BIOS_BASE, 0xA0000000u | Bus::BIOS_BASE | Bus::BIOS_MASK},
};
// TODO: Needs testing
const u32 ram_mapped_mask = Bus::g_ram_mapped_size - 1;
const u32 bpc = g_state.cop0_regs.BPC;
const u32 bpcm = g_state.cop0_regs.BPCM;
const u32 masked_bpc = bpc & bpcm;
for (const auto& [range_start, range_end] : code_address_ranges)
for (const u32 region : {0x00000000u /* KUSEG*/, 0x80000000u /* KSEG0 */, 0xA0000000u /* KSEG1 */})
{
if (masked_bpc >= (range_start & bpcm) && masked_bpc <= (range_end & bpcm))
const u32 ram_start = region | Bus::RAM_BASE;
const u32 ram_end = ram_start | ram_mapped_mask;
if (masked_bpc >= (ram_start & bpcm) && masked_bpc <= (ram_end & bpcm))
return true;
const u32 bios_start = region | Bus::BIOS_BASE;
const u32 bios_end = bios_start | Bus::BIOS_MASK;
if (masked_bpc >= (bios_start & bpcm) && masked_bpc <= (bios_end & bpcm))
return true;
}
@ -2798,7 +2794,7 @@ ALWAYS_INLINE_RELEASE bool CPU::DoInstructionRead(PhysicalMemoryAddress address,
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
address &= KSEG_MASK;
if (address < RAM_MIRROR_END)
if (address < g_ram_mapped_size)
{
std::memcpy(data, &g_ram[address & g_ram_mask], sizeof(u32) * word_count);
if constexpr (add_ticks)
@ -2842,7 +2838,7 @@ TickCount CPU::GetInstructionReadTicks(VirtualMemoryAddress address)
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
address &= KSEG_MASK;
if (address < RAM_MIRROR_END)
if (address < RAM_MAX_SIZE)
{
return RAM_READ_TICKS;
}
@ -2863,7 +2859,7 @@ TickCount CPU::GetICacheFillTicks(VirtualMemoryAddress address)
DebugAssert(VirtualAddressToPhysical(address) == (address & KSEG_MASK));
address &= KSEG_MASK;
if (address < RAM_MIRROR_END)
if (address < RAM_MAX_SIZE)
{
return 1 * ((ICACHE_LINE_SIZE - (address & (ICACHE_LINE_SIZE - 1))) / sizeof(u32));
}
@ -3128,7 +3124,7 @@ ALWAYS_INLINE bool CPU::DoSafeMemoryAccess(VirtualMemoryAddress address, u32& va
break;
}
if (address < RAM_MIRROR_END)
if (address < g_ram_mapped_size)
{
const u32 offset = address & g_ram_mask;
if constexpr (type == MemoryAccessType::Read)
@ -3308,7 +3304,7 @@ bool CPU::SafeReadMemoryBytes(VirtualMemoryAddress addr, void* data, u32 length)
using namespace Bus;
const u32 seg = (addr >> 29);
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= g_ram_mapped_size) ||
(((addr & g_ram_mask) + length) > g_ram_size))
{
u8* ptr = static_cast<u8*>(data);
@ -3332,7 +3328,7 @@ bool CPU::SafeWriteMemoryBytes(VirtualMemoryAddress addr, const void* data, u32
using namespace Bus;
const u32 seg = (addr >> 29);
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= g_ram_mapped_size) ||
(((addr & g_ram_mask) + length) > g_ram_size))
{
const u8* ptr = static_cast<const u8*>(data);
@ -3361,7 +3357,7 @@ bool CPU::SafeZeroMemoryBytes(VirtualMemoryAddress addr, u32 length)
using namespace Bus;
const u32 seg = (addr >> 29);
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= RAM_MIRROR_END) ||
if ((seg != 0 && seg != 4 && seg != 5) || (((addr + length) & KSEG_MASK) >= g_ram_mapped_size) ||
(((addr & g_ram_mask) + length) > g_ram_size))
{
while ((addr & 3u) != 0 && length > 0)
@ -3406,7 +3402,7 @@ void* CPU::GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccess
return nullptr;
const PhysicalMemoryAddress paddr = VirtualAddressToPhysical(address);
if (paddr < RAM_MIRROR_END)
if (paddr < g_ram_mapped_size)
{
if (read_ticks)
*read_ticks = RAM_READ_TICKS;
@ -3443,7 +3439,7 @@ void* CPU::GetDirectWriteMemoryPointer(VirtualMemoryAddress address, MemoryAcces
const PhysicalMemoryAddress paddr = address & KSEG_MASK;
if (paddr < RAM_MIRROR_END)
if (paddr < g_ram_mapped_size)
return &g_ram[paddr & g_ram_mask];
if ((paddr & SCRATCHPAD_ADDR_MASK) == SCRATCHPAD_ADDR)

@ -36,8 +36,8 @@ enum : u32
VERTEX_CACHE_WIDTH = 2048,
VERTEX_CACHE_HEIGHT = 2048,
VERTEX_CACHE_SIZE = VERTEX_CACHE_WIDTH * VERTEX_CACHE_HEIGHT,
PGXP_MEM_SIZE = (static_cast<u32>(Bus::RAM_8MB_SIZE) + static_cast<u32>(CPU::SCRATCHPAD_SIZE)) / 4,
PGXP_MEM_SCRATCH_OFFSET = Bus::RAM_8MB_SIZE / 4,
PGXP_MEM_SIZE = (static_cast<u32>(Bus::RAM_MAX_SIZE) + static_cast<u32>(CPU::SCRATCHPAD_SIZE)) / 4,
PGXP_MEM_SCRATCH_OFFSET = Bus::RAM_MAX_SIZE / 4,
};
enum : u32
@ -140,6 +140,7 @@ void CPU::PGXP::Initialize()
std::memset(g_state.pgxp_cop0, 0, sizeof(g_state.pgxp_cop0));
std::memset(g_state.pgxp_gte, 0, sizeof(g_state.pgxp_gte));
// TODO: Needs to be moved into the memory map
if (!s_mem)
{
s_mem = static_cast<PGXPValue*>(std::calloc(PGXP_MEM_SIZE, sizeof(PGXPValue)));
@ -297,7 +298,7 @@ ALWAYS_INLINE_RELEASE CPU::PGXPValue* CPU::PGXP::GetPtr(u32 addr)
// Don't worry about >512MB here for performance reasons.
const u32 paddr = (addr & KSEG_MASK);
if (paddr < Bus::RAM_MIRROR_END)
if (paddr < Bus::g_ram_size)
return &s_mem[(paddr & Bus::g_ram_mask) >> 2];
else
return nullptr;

@ -3027,7 +3027,9 @@ void FullscreenUI::DrawEmulationSettingsPage()
const u32 resolution_scale = GetEffectiveUIntSetting(bsi, "GPU", "ResolutionScale", 1);
const u32 multisamples = GetEffectiveUIntSetting(bsi, "GPU", "Multisamples", 1);
const bool use_software_renderer = GetEffectiveBoolSetting(bsi, "GPU", "UseSoftwareRendererForMemoryStates", false);
const bool enable_8mb_ram = GetEffectiveBoolSetting(bsi, "Console", "Enable8MBRAM", false);
const u8 ram_size =
static_cast<u8>(std::clamp<u32>(GetEffectiveUIntSetting(bsi, "CPU", "RAMSize", Settings::DEFAULT_CPU_RAM_SIZE),
Settings::MIN_CPU_RAM_SIZE, Settings::MAX_CPU_RAM_SIZE));
const float rewind_frequency = GetEffectiveFloatSetting(bsi, "Main", "RewindFrequency", 10.0f);
const s32 rewind_save_slots = GetEffectiveIntSetting(bsi, "Main", "RewindSaveSlots", 10);
const float duration =
@ -3036,7 +3038,7 @@ void FullscreenUI::DrawEmulationSettingsPage()
u64 ram_usage, vram_usage;
System::CalculateRewindMemoryUsage(rewind_save_slots, resolution_scale, multisamples, use_software_renderer,
enable_8mb_ram, &ram_usage, &vram_usage);
ram_size, &ram_usage, &vram_usage);
if (vram_usage > 0)
{
rewind_summary.format(

@ -587,8 +587,8 @@ void ImGuiManager::DrawEnhancementsOverlay(const GPUBackend* gpu)
if (g_settings.cpu_overclock_active)
text.append_format(" CPU={}%", g_settings.GetCPUOverclockPercent());
if (g_settings.cpu_enable_8mb_ram)
text.append(" 8MB");
if (g_settings.cpu_ram_size != Settings::DEFAULT_CPU_RAM_SIZE)
text.append_format(" {}MB", g_settings.cpu_ram_size);
if (g_settings.cdrom_read_speedup != 1)
text.append_format(" CDR={}x", g_settings.cdrom_read_speedup);
if (g_settings.cdrom_seek_speedup != 1)

@ -25,7 +25,7 @@ static bool IsValidScanAddress(VirtualMemoryAddress address)
}
const PhysicalMemoryAddress phys_address = CPU::VirtualAddressToPhysical(address);
if (phys_address < Bus::RAM_MIRROR_END)
if (phys_address < Bus::g_ram_mapped_size)
return true;
if (phys_address >= Bus::BIOS_BASE && phys_address < (Bus::BIOS_BASE + Bus::BIOS_SIZE))

@ -207,7 +207,6 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
ParseConsoleRegionName(
si.GetStringValue("Console", "Region", Settings::GetConsoleRegionName(Settings::DEFAULT_CONSOLE_REGION)).c_str())
.value_or(DEFAULT_CONSOLE_REGION);
cpu_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);
@ -245,6 +244,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
cpu_fastmem_mode = ParseCPUFastmemMode(
si.GetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(DEFAULT_CPU_FASTMEM_MODE)).c_str())
.value_or(DEFAULT_CPU_FASTMEM_MODE);
cpu_ram_size = static_cast<u8>(std::clamp<u32>(si.GetUIntValue("CPU", "RAMSize", DEFAULT_CPU_RAM_SIZE), 2u, 16u));
gpu_renderer = ParseRendererName(si.GetStringValue("GPU", "Renderer", GetRendererName(DEFAULT_GPU_RENDERER)).c_str())
.value_or(DEFAULT_GPU_RENDERER);
@ -606,7 +606,6 @@ void Settings::LoadPGXPSettings(const SettingsInterface& si)
void Settings::Save(SettingsInterface& si, bool ignore_base) const
{
si.SetStringValue("Console", "Region", GetConsoleRegionName(region));
si.SetBoolValue("Console", "Enable8MBRAM", cpu_enable_8mb_ram);
si.SetFloatValue("Main", "EmulationSpeed", emulation_speed);
si.SetFloatValue("Main", "FastForwardSpeed", fast_forward_speed);
@ -643,6 +642,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
si.SetBoolValue("CPU", "RecompilerBlockLinking", cpu_recompiler_block_linking);
si.SetBoolValue("CPU", "RecompilerICache", cpu_recompiler_icache);
si.SetStringValue("CPU", "FastmemMode", GetCPUFastmemModeName(cpu_fastmem_mode));
si.SetBoolValue("CPU", "RAMSize", cpu_ram_size);
si.SetStringValue("GPU", "Renderer", GetRendererName(gpu_renderer));
si.SetStringValue("GPU", "Adapter", gpu_adapter.c_str());
@ -1068,7 +1068,7 @@ void Settings::ApplySettingRestrictions()
region = ConsoleRegion::Auto;
cpu_overclock_enable = false;
cpu_overclock_active = false;
cpu_enable_8mb_ram = false;
cpu_ram_size = DEFAULT_CPU_RAM_SIZE;
gpu_resolution_scale = 1;
gpu_multisamples = 1;
gpu_automatic_resolution_scale = false;
@ -1421,6 +1421,26 @@ const char* Settings::GetDiscRegionDisplayName(DiscRegion region)
return Host::TranslateToCString("Settings", s_disc_region_display_names[static_cast<size_t>(region)], "DiscRegion");
}
std::span<const u8> Settings::GetCPURAMSizeOptions()
{
static constexpr const u8 options[] = {2, 4, 8, 16};
return options;
}
const char* Settings::GetCPURAMSizeDisplayName(u8 size)
{
if (size == 2)
return TRANSLATE("Settings", "2 MB (Retail Console)", "CPURAMSize");
else if (size == 4)
return TRANSLATE("Settings", "4 MB (Arcade Boards)", "CPURAMSize");
else if (size == 8)
return TRANSLATE("Settings", "8 MB (Dev Console)", "CPURAMSize");
else if (size == 16)
return TRANSLATE("Settings", "16 MB (Mods/Arcade Boards)", "CPURAMSize");
else
return "Unknown";
}
static constexpr const std::array s_cpu_execution_mode_names = {
"Interpreter",
"CachedInterpreter",

@ -292,7 +292,6 @@ struct Settings : public GPUSettings
bool cpu_recompiler_memory_exceptions : 1 = false;
bool cpu_recompiler_block_linking : 1 = true;
bool cpu_recompiler_icache : 1 = false;
bool cpu_enable_8mb_ram : 1 = false;
bool mdec_use_old_routines : 1 = false;
bool mdec_disable_cdrom_speedup : 1 = false;
@ -340,6 +339,8 @@ struct Settings : public GPUSettings
u32 cdrom_max_seek_speedup_cycles = DEFAULT_CDROM_MAX_SEEK_SPEEDUP_CYCLES;
u32 cdrom_max_read_speedup_cycles = DEFAULT_CDROM_MAX_READ_SPEEDUP_CYCLES;
u8 cpu_ram_size = DEFAULT_CPU_RAM_SIZE; // TODO: Move me up
u8 audio_output_volume = 100;
u8 audio_fast_forward_volume = 100;
@ -488,6 +489,9 @@ struct Settings : public GPUSettings
static const char* GetDiscRegionName(DiscRegion region);
static const char* GetDiscRegionDisplayName(DiscRegion region);
static std::span<const u8> GetCPURAMSizeOptions();
static const char* GetCPURAMSizeDisplayName(u8 size);
static std::optional<CPUExecutionMode> ParseCPUExecutionMode(const char* str);
static const char* GetCPUExecutionModeName(CPUExecutionMode mode);
static const char* GetCPUExecutionModeDisplayName(CPUExecutionMode mode);
@ -621,6 +625,9 @@ struct Settings : public GPUSettings
#else
static constexpr CPUFastmemMode DEFAULT_CPU_FASTMEM_MODE = CPUFastmemMode::LUT;
#endif
static constexpr u8 DEFAULT_CPU_RAM_SIZE = 2;
static constexpr u8 MIN_CPU_RAM_SIZE = 2;
static constexpr u8 MAX_CPU_RAM_SIZE = 16;
static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8;
static constexpr u32 DEFAULT_CDROM_MAX_SEEK_SPEEDUP_CYCLES = 30000;

@ -710,7 +710,7 @@ std::string_view System::GetTaintDisplayName(Taint taint)
TRANSLATE_DISAMBIG_NOOP("System", "CD-ROM Read Speedup", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "CD-ROM Seek Speedup", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Force Frame Timings", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "8MB RAM", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Expanded RAM", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Cheats", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Game Patches", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Memory Card Mismatch", "Taint"),
@ -2734,7 +2734,7 @@ bool System::AllocateMemoryStates(size_t state_count, bool recycle_old_textures)
// Allocate CPU buffers.
// TODO: Maybe look at host memory limits here...
const size_t size = GetMaxMemorySaveStateSize(g_settings.cpu_enable_8mb_ram, CPU::PGXP::ShouldSavePGXPState());
const size_t size = GetMaxMemorySaveStateSize(g_settings.cpu_ram_size, CPU::PGXP::ShouldSavePGXPState());
for (MemorySaveState& mss : s_state.memory_save_states)
{
mss.state_size = 0;
@ -3012,17 +3012,15 @@ bool System::SetBootMode(BootMode new_boot_mode, DiscRegion disc_region, Error*
return true;
}
size_t System::GetMaxSaveStateSize(bool enable_8mb_ram)
size_t System::GetMaxSaveStateSize(u8 ram_size)
{
// 5 megabytes is sufficient for now, at the moment they're around 4.3MB, or 10.3MB with 8MB RAM enabled.
static constexpr u32 MAX_2MB_SAVE_STATE_SIZE = 5 * 1024 * 1024;
static constexpr u32 MAX_8MB_SAVE_STATE_SIZE = 11 * 1024 * 1024;
return enable_8mb_ram ? MAX_8MB_SAVE_STATE_SIZE : MAX_2MB_SAVE_STATE_SIZE;
return (3 + ram_size) * 1024 * 1024;
}
size_t System::GetMaxMemorySaveStateSize(bool enable_8mb_ram, bool pgxp)
size_t System::GetMaxMemorySaveStateSize(u8 ram_size, bool pgxp)
{
return GetMaxSaveStateSize(enable_8mb_ram) + (pgxp ? CPU::PGXP::GetStateSize() : 0);
return GetMaxSaveStateSize(ram_size) + (pgxp ? CPU::PGXP::GetStateSize() : 0);
}
std::string System::GetMediaPathFromSaveState(const char* path)
@ -3560,7 +3558,7 @@ bool System::SaveStateToBuffer(SaveStateBuffer* buffer, Error* error, u32 screen
// write data
if (buffer->state_data.empty())
buffer->state_data.resize(GetMaxSaveStateSize(Bus::g_ram_size > Bus::RAM_2MB_SIZE));
buffer->state_data.resize(GetMaxSaveStateSize(static_cast<u8>(Bus::g_ram_size / 1048576)));
return SaveStateDataToBuffer(buffer->state_data, &buffer->state_size, error);
}
@ -5043,8 +5041,8 @@ void System::SetTaintsFromSettings()
SetTaint(Taint::CPUOverclock);
if (g_settings.gpu_force_video_timing != ForceVideoTimingMode::Disabled)
SetTaint(Taint::ForceFrameTimings);
if (g_settings.cpu_enable_8mb_ram)
SetTaint(Taint::RAM8MB);
if (g_settings.cpu_ram_size)
SetTaint(Taint::ExpandedRAM);
if (Cheats::GetActivePatchCount() > 0)
SetTaint(Taint::Patches);
if (Cheats::GetActiveCheatCount() > 0)
@ -5102,8 +5100,8 @@ void System::WarnAboutUnsafeSettings()
{
if (g_settings.cpu_overclock_active)
append(TRANSLATE_SV("System", "Overclock disabled."));
if (g_settings.cpu_enable_8mb_ram)
append(TRANSLATE_SV("System", "8MB RAM disabled."));
if (g_settings.cpu_ram_size != Settings::DEFAULT_CPU_RAM_SIZE)
append(TRANSLATE_SV("System", "RAM size set to default."));
if (g_settings.gpu_resolution_scale != 1)
append(TRANSLATE_SV("System", "Resolution scale set to 1x."));
if (g_settings.gpu_multisamples != 1)
@ -5191,8 +5189,8 @@ void System::WarnAboutUnsafeSettings()
TRANSLATE_SV("System", "PGXP Geometry Tolerance is not set to default. This may cause rendering errors."));
}
}
if (g_settings.cpu_enable_8mb_ram)
append(TRANSLATE_SV("System", "8MB RAM is enabled, this may be incompatible with some games."));
if (g_settings.cpu_ram_size != Settings::DEFAULT_CPU_RAM_SIZE)
append(TRANSLATE_SV("System", "Expanded RAM is enabled, this may be incompatible with some games."));
if (g_settings.cpu_execution_mode == CPUExecutionMode::CachedInterpreter)
append(TRANSLATE_SV("System", "Cached interpreter is being used, this may be incompatible with some games."));
@ -5256,11 +5254,10 @@ void System::LogUnsafeSettingsToConsole(const SmallStringBase& messages)
}
void System::CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u32 multisamples,
bool use_software_renderer, bool enable_8mb_ram, u64* ram_usage,
u64* vram_usage)
bool use_software_renderer, u8 ram_size, u64* ram_usage, u64* vram_usage)
{
const u32 real_resolution_scale = std::max<u32>(resolution_scale, 1u);
*ram_usage = GetMaxMemorySaveStateSize(enable_8mb_ram, false) * static_cast<u64>(num_saves);
*ram_usage = GetMaxMemorySaveStateSize(ram_size, false) * static_cast<u64>(num_saves);
*vram_usage = use_software_renderer ? 0 :
((static_cast<u64>(VRAM_WIDTH * real_resolution_scale) *
static_cast<u64>(VRAM_HEIGHT * real_resolution_scale) * 4) *
@ -5290,7 +5287,7 @@ void System::UpdateMemorySaveStateSettings()
u64 ram_usage, vram_usage;
CalculateRewindMemoryUsage(g_settings.rewind_save_slots, g_settings.gpu_resolution_scale,
g_settings.gpu_multisamples, g_settings.gpu_use_software_renderer_for_memory_states,
g_settings.cpu_enable_8mb_ram, &ram_usage, &vram_usage);
g_settings.cpu_ram_size, &ram_usage, &vram_usage);
INFO_LOG("Rewind is enabled, saving every {} frames, with {} slots and {}MB RAM and {}MB VRAM usage",
std::max(s_state.rewind_save_frequency, 1), g_settings.rewind_save_slots, ram_usage / 1048576,
vram_usage / 1048576);

@ -118,7 +118,7 @@ enum class Taint : u8
CDROMReadSpeedup,
CDROMSeekSpeedup,
ForceFrameTimings,
RAM8MB,
ExpandedRAM,
Cheats,
Patches,
MemoryCardMismatch,
@ -281,10 +281,10 @@ void ResetSystem();
bool CanPauseSystem(bool display_message);
/// Returns the maximum size of a save state, considering the current configuration.
size_t GetMaxSaveStateSize(bool enable_8mb_ram);
size_t GetMaxSaveStateSize(u8 ram_size);
/// Returns the maximum size of a save state that is not expected to be serialized to file.
size_t GetMaxMemorySaveStateSize(bool enable_8mb_ram, bool pgxp);
size_t GetMaxMemorySaveStateSize(u8 ram_size, bool pgxp);
/// Loads state from the specified path.
std::optional<bool> LoadState(const char* path, Error* error, bool save_undo_state, bool force_update_display);
@ -457,7 +457,7 @@ std::string GetImageForLoadingScreen(const std::string& game_path);
// Memory Save States (Rewind and Runahead)
//////////////////////////////////////////////////////////////////////////
void CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u32 multisamples, bool use_software_renderer,
bool enable_8mb_ram, u64* ram_usage, u64* vram_usage);
u8 ram_size, u64* ram_usage, u64* vram_usage);
void ClearMemorySaveStates(bool reallocate_resources, bool recycle_textures);
void SetRunaheadReplayFlag(bool is_analog_input);

@ -16,7 +16,7 @@
#include "moc_consolesettingswidget.cpp"
static constexpr const int CDROM_SPEEDUP_VALUES[] = {1, 2, 3, 4, 5, 6, 0};
static constexpr const u8 CDROM_SPEEDUP_VALUES[] = {1, 2, 3, 4, 5, 6, 0};
ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* parent)
: QWidget(parent), m_dialog(dialog)
@ -40,7 +40,9 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* pa
});
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "BIOS", "PatchFastBoot", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastForwardBoot, "BIOS", "FastForwardBoot", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enable8MBRAM, "Console", "Enable8MBRAM", false);
for (const u8& size : Settings::GetCPURAMSizeOptions())
m_ui.ramSize->addItem(Settings::GetCPURAMSizeDisplayName(size), QVariant(static_cast<uint>(size)));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.ramSize, "CPU", "RAMSize", Settings::DEFAULT_CPU_RAM_SIZE, Settings::GetCPURAMSizeOptions());
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastForwardMemoryCardAccess, "MemoryCards",
"FastForwardAccess", false);
connect(m_ui.fastBoot, &QCheckBox::checkStateChanged, this, &ConsoleSettingsWidget::onFastBootChanged);
@ -72,9 +74,9 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* pa
}
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromSeekSpeedup, "CDROM", "SeekSpeedup", 1,
CDROM_SPEEDUP_VALUES);
std::span<const u8>(CDROM_SPEEDUP_VALUES));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cdromReadSpeedup, "CDROM", "ReadSpeedup", 1,
CDROM_SPEEDUP_VALUES);
std::span<const u8>(CDROM_SPEEDUP_VALUES));
dialog->registerWidgetHelp(m_ui.region, tr("Region"), tr("Auto-Detect"),
tr("Determines the emulated hardware type."));
@ -93,7 +95,7 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* pa
tr("Fast forwards through memory card access, both loading and saving. Can reduce "
"waiting times in games that frequently access memory cards."));
dialog->registerWidgetHelp(
m_ui.enable8MBRAM, tr("Enable 8MB RAM (Dev Console)"), tr("Unchecked"),
m_ui.ramSize, tr("Enable 8MB RAM (Dev Console)"), tr("Unchecked"),
tr("Enables an additional 6MB of RAM to obtain a total of 2+6 = 8MB, usually present on dev consoles. Games have "
"to use a larger heap size for "
"this additional RAM to be usable. Titles which rely on memory mirrors may break, so it should only be used "

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>600</width>
<height>487</height>
<height>520</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -49,7 +49,17 @@
<item row="1" column="1">
<widget class="QComboBox" name="forceVideoTiming"/>
</item>
<item row="2" column="0" colspan="2">
<item row="2" column="0">
<widget class="QLabel" name="ramSizeLabel">
<property name="text">
<string>Installed RAM:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="ramSize"/>
</item>
<item row="3" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="fastBoot">
@ -72,13 +82,6 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="enable8MBRAM">
<property name="text">
<string>Enable 8MB RAM (Dev Console)</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

@ -265,14 +265,16 @@ void EmulationSettingsWidget::updateRewind()
const u32 multisamples = m_dialog->getEffectiveIntValue("GPU", "Multisamples", 1);
const bool use_software_renderer =
m_dialog->getEffectiveBoolValue("GPU", "UseSoftwareRendererForMemoryStates", false);
const bool enable_8mb_ram = m_dialog->getEffectiveBoolValue("Console", "Enable8MBRAM", false);
const u8 ram_size =
static_cast<u8>(std::clamp<s32>(m_dialog->getEffectiveIntValue("CPU", "RAMSize", Settings::DEFAULT_CPU_RAM_SIZE),
Settings::MIN_CPU_RAM_SIZE, Settings::MAX_CPU_RAM_SIZE));
const u32 frames = static_cast<u32>(m_ui.rewindSaveSlots->value());
const float frequency = static_cast<float>(m_ui.rewindSaveFrequency->value());
const float duration =
((frequency <= std::numeric_limits<float>::epsilon()) ? (1.0f / 60.0f) : frequency) * static_cast<float>(frames);
u64 ram_usage, vram_usage;
System::CalculateRewindMemoryUsage(frames, resolution_scale, multisamples, use_software_renderer, enable_8mb_ram,
System::CalculateRewindMemoryUsage(frames, resolution_scale, multisamples, use_software_renderer, ram_size,
&ram_usage, &vram_usage);
m_ui.rewindSummary->setText(

@ -813,16 +813,16 @@ inline void BindWidgetToIntSetting(SettingsInterface* sif, WidgetType* widget, s
}
}
template<typename WidgetType>
template<typename WidgetType, typename SpanT>
inline void BindWidgetToIntSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
int default_value, std::span<const int> values)
int default_value, std::span<const SpanT> values)
{
using Accessor = SettingAccessor<WidgetType>;
static constexpr auto value_to_index = [](s32 value, const std::span<const int> values) {
static constexpr auto value_to_index = [](s32 value, const std::span<const SpanT> values) {
for (size_t i = 0; i < values.size(); i++)
{
if (values[i] == value)
if (static_cast<s32>(values[i]) == value)
return static_cast<int>(i);
}

@ -722,7 +722,7 @@ void RegTestHost::DumpSystemStateHashes()
// don't save full state on gpu dump, it's not going to be complete...
if (!System::IsReplayingGPUDump())
{
DynamicHeapArray<u8> state_data(System::GetMaxSaveStateSize(g_settings.cpu_enable_8mb_ram));
DynamicHeapArray<u8> state_data(System::GetMaxSaveStateSize(g_settings.cpu_ram_size));
size_t state_data_size;
if (!System::SaveStateDataToBuffer(state_data, &state_data_size, &error))
{

Loading…
Cancel
Save