mirror of
https://github.com/stenzek/duckstation.git
synced 2026-07-11 01:24:11 +02:00
Bus: Support 16MB expanded memory
This commit is contained in:
@@ -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())
|
||||
{
|
||||
|
||||
+108
-98
@@ -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,52 +2193,42 @@ void Bus::UpdateMappedRAMSize()
|
||||
{
|
||||
const u32 prev_mapped_size = g_ram_mapped_size;
|
||||
|
||||
switch (s_RAM_SIZE.memory_window)
|
||||
// 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 (?)
|
||||
};
|
||||
|
||||
const u32 mapped_size = ram_mapped_sizes[s_RAM_SIZE.memory_window];
|
||||
if (mapped_size == prev_mapped_size)
|
||||
return;
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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]];
|
||||
|
||||
case 5: // 8MB memory
|
||||
{
|
||||
// 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();
|
||||
RemapFastmemViews();
|
||||
}
|
||||
|
||||
#undef SET
|
||||
|
||||
+13
-13
@@ -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,
|
||||
|
||||
+16
-4
@@ -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);
|
||||
|
||||
+21
-25
@@ -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))
|
||||
|
||||
+23
-3
@@ -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",
|
||||
|
||||
+8
-1
@@ -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;
|
||||
|
||||
+16
-19
@@ -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);
|
||||
|
||||
+4
-4
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user