diff --git a/Source/Core/Core/HW/Memmap.cpp b/Source/Core/Core/HW/Memmap.cpp index bc7819db1b..72e5e265ef 100644 --- a/Source/Core/Core/HW/Memmap.cpp +++ b/Source/Core/Core/HW/Memmap.cpp @@ -118,7 +118,8 @@ bool IsInitialized() // with address translation turned off. (This is only used by the CPU; // other devices, like the GPU, use other rules, approximated by // Memory::GetPointer.) This memory is laid out as follows: -// [0x00000000, 0x01800000) - 24MB RAM +// [0x00000000, 0x02000000) - 32MB RAM +// [0x02000000, 0x08000000) - Mirrors of 32MB RAM // [0x08000000, 0x0C000000) - EFB "mapping" (not handled here) // [0x0C000000, 0x0E000000) - MMIO etc. (not handled here) // [0x10000000, 0x14000000) - 64MB RAM (Wii-only; slightly slower) @@ -127,13 +128,16 @@ bool IsInitialized() // with address translation turned on. Instead of changing the mapping // based on the BAT registers, we approximate the common BAT configuration // used by games: -// [0x00000000, 0x01800000) - 24MB RAM, cached access, normally only mapped +// [0x00000000, 0x02000000) - 32MB RAM, cached access, normally only mapped // during startup by Wii WADs +// [0x02000000, 0x08000000) - Mirrors of 32MB RAM (not implemented here) // [0x40000000, 0x50000000) - FakeVMEM // [0x70000000, 0x80000000) - FakeVMEM -// [0x80000000, 0x81800000) - 24MB RAM, cached access +// [0x80000000, 0x82000000) - 32MB RAM, cached access +// [0x82000000, 0x88000000) - Mirrors of 32MB RAM (not implemented here) // [0x90000000, 0x94000000) - 64MB RAM, Wii-only, cached access -// [0xC0000000, 0xC1800000) - 24MB RAM, uncached access +// [0xC0000000, 0xC2000000) - 32MB RAM, uncached access +// [0xC2000000, 0xC8000000) - Mirrors of 32MB RAM (not implemented here) // [0xC8000000, 0xCC000000) - EFB "mapping" (not handled here) // [0xCC000000, 0xCE000000) - MMIO etc. (not handled here) // [0xD0000000, 0xD4000000) - 64MB RAM, Wii-only, uncached access @@ -145,7 +149,16 @@ bool IsInitialized() // Each of these 4GB regions is followed by 4GB of empty space so overflows // in address computation in the JIT don't access the wrong memory. // +// The neighboring mirrors of RAM ([0x02000000, 0x08000000), etc.) exist because +// the bus masks off the bits in question for RAM accesses; using them is a +// terrible idea because the CPU cache won't handle them correctly, but a +// few buggy games (notably Rogue Squadron 2) use them by accident. They +// aren't backed by memory mappings because they are used very rarely. +// // Dolphin doesn't emulate the difference between cached and uncached access. +// +// TODO: The actual size of RAM is REALRAM_SIZE (24MB); the other 8MB shouldn't +// be backed by actual memory. static MemoryView views[] = { {&m_pRAM, 0x00000000, RAM_SIZE, 0}, diff --git a/Source/Core/Core/PowerPC/MMU.cpp b/Source/Core/Core/PowerPC/MMU.cpp index 718f93e45c..8a7e81915f 100644 --- a/Source/Core/Core/PowerPC/MMU.cpp +++ b/Source/Core/Core/PowerPC/MMU.cpp @@ -136,12 +136,17 @@ __forceinline static T ReadFromHardware(const u32 em_address) else return (T)Memory::mmio_mapping->Read::type>(em_address); } - if ((segment == 0x0 || segment == 0x8 || segment == 0xC) && (em_address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) + if (segment == 0x0 || segment == 0x8 || segment == 0xC) { - return bswap((*(const T*)&Memory::m_pRAM[em_address & 0x0FFFFFFF])); + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); } if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) { + // Handle EXRAM. + // TODO: Is this supposed to be mirrored like main RAM? return bswap((*(const T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF])); } if (segment == 0xE && (em_address < (0xE0000000 + Memory::L1_CACHE_SIZE))) @@ -165,9 +170,12 @@ __forceinline static T ReadFromHardware(const u32 em_address) else return (T)Memory::mmio_mapping->Read::type>(em_address | 0xC0000000); } - if (em_address < Memory::REALRAM_SIZE) + if (segment == 0x0) { - return bswap((*(const T*)&Memory::m_pRAM[em_address])); + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + return bswap((*(const T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK])); } if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) { @@ -254,13 +262,18 @@ __forceinline static void WriteToHardware(u32 em_address, const T data) return; } } - if ((segment == 0x8 || segment == 0xC) && (em_address & 0x0FFFFFFF) < Memory::REALRAM_SIZE) + if (segment == 0x0 || segment == 0x8 || segment == 0xC) { - *(T*)&Memory::m_pRAM[em_address & 0x0FFFFFFF] = bswap(data); + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); return; } if (Memory::m_pEXRAM && (segment == 0x9 || segment == 0xD) && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE) { + // Handle EXRAM. + // TODO: Is this supposed to be mirrored like main RAM? *(T*)&Memory::m_pEXRAM[em_address & 0x0FFFFFFF] = bswap(data); return; } @@ -304,9 +317,12 @@ __forceinline static void WriteToHardware(u32 em_address, const T data) return; } } - if (em_address < Memory::REALRAM_SIZE) + if (segment == 0x0) { - *(T*)&Memory::m_pRAM[em_address] = bswap(data); + // Handle RAM; the masking intentionally discards bits (essentially creating + // mirrors of memory). + // TODO: Only the first REALRAM_SIZE is supposed to be backed by actual memory. + *(T*)&Memory::m_pRAM[em_address & Memory::RAM_MASK] = bswap(data); return; } if (Memory::m_pEXRAM && segment == 0x1 && (em_address & 0x0FFFFFFF) < Memory::EXRAM_SIZE)