From d09dd7cbcddb8245b5b523d4764ceed5fee324cb Mon Sep 17 00:00:00 2001 From: John Burley Date: Wed, 24 Jun 2026 20:30:22 -0400 Subject: [PATCH 1/5] Merged into submission tree --- Source/Core/Core/HW/MemoryInterface.cpp | 31 +++++++++++++++++++++++++ Source/Core/Core/HW/WII_IPC.cpp | 14 +++++++++++ 2 files changed, 45 insertions(+) diff --git a/Source/Core/Core/HW/MemoryInterface.cpp b/Source/Core/Core/HW/MemoryInterface.cpp index 27f0177287..ba0015214f 100644 --- a/Source/Core/Core/HW/MemoryInterface.cpp +++ b/Source/Core/Core/HW/MemoryInterface.cpp @@ -10,6 +10,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Core/HW/MMIO.h" +#include "Core/System.h" +#include "Core/HW/Memmap.h" namespace MemoryInterface { @@ -30,6 +32,7 @@ enum MI_UNKNOWN1 = 0x020, MI_PROT_ADDR_LO = 0x022, MI_PROT_ADDR_HI = 0x024, + MI_MEM_CONFIG = 0x028, MI_TIMER0_HI = 0x032, MI_TIMER0_LO = 0x034, MI_TIMER1_HI = 0x036, @@ -73,6 +76,26 @@ void MemoryInterfaceManager::DoState(PointerWrap& p) p.Do(m_mi_mem); } +static u16 EncodeMemConfig(u32 ram_size) +{ + switch (ram_size) + { + case 0x1000000: // 16MiB + return 0; + case 0x1800000: // 24MiB + return 2; + case 0x2000000: // 32MiB + return 1; + case 0x3000000: // 48MiB + return 3; + case 0x4000000: // 64MiB + return 5; + default: + return 2; // Bespoke configs can't be represented in this bitfield + // Fallback to 24. Potentially dangerous, but when not emulating this register at all it is seen as 16 + } +} + void MemoryInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) { for (u32 i = MI_REGION0_FIRST; i <= MI_REGION3_LAST; i += 4) @@ -104,6 +127,14 @@ void MemoryInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | MI_PROT_ADDR_HI, MMIO::DirectRead(&m_mi_mem.prot_addr.lo), MMIO::DirectWrite(&m_mi_mem.prot_addr.lo)); + // MI RAM configuration strap. The low 3 bits encode the installed MEM1 + // size; the SDK uses this to populate OS global 0x80000028. + mmio->Register(base | MI_MEM_CONFIG, + MMIO::ComplexRead([](Core::System& system, u32) { + return EncodeMemConfig(system.GetMemory().GetRamSizeReal()); + }), + MMIO::Nop()); + for (u32 i = 0; i < m_mi_mem.timers.size(); ++i) { auto& timer = m_mi_mem.timers[i]; diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index c99c8afbf0..1de27068e5 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -13,6 +13,7 @@ #include "Core/HW/ProcessorInterface.h" #include "Core/IOS/IOS.h" #include "Core/System.h" +#include "Core/HW/Memmap.h" // This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because // of the IOS HLE @@ -56,6 +57,10 @@ enum UNK_180 = 0x180, UNK_1CC = 0x1cc, UNK_1D0 = 0x1d0, + + VERSION = 0x214, + + IS_128 = 0xB4216, }; // Indicates which pins are accessible by broadway. Writable by starlet only. @@ -129,6 +134,7 @@ void WiiIPC::Shutdown() void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) { + auto& memory = m_system.GetMemory(); mmio->Register(base | IPC_PPCMSG, MMIO::InvalidRead(), MMIO::DirectWrite(&m_ppc_msg)); mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead([](Core::System& system, u32) { @@ -256,6 +262,14 @@ void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) // Register some stubbed/unknown MMIOs required to make Wii games work. mmio->Register(base | PPCSPEED, MMIO::InvalidRead(), MMIO::Nop()); mmio->Register(base | VISOLID, MMIO::InvalidRead(), MMIO::Nop()); + // Sets the Hollywood version register to 0x11 (same as placed in lomem) + mmio->Register(base | VERSION, MMIO::Constant(0x00000011), MMIO::Nop()); + + const bool mem2_128 = memory.GetExRamSizeReal() == Memory::MEM2_SIZE_NDEV; + mmio->Register(base | IS_128, + MMIO::Constant(mem2_128 ? 1 : 0), + MMIO::Nop()); + mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1D0, MMIO::Constant(0), MMIO::Nop()); From 5be6c56a56862e940bc26ebed915f2138dda6e61 Mon Sep 17 00:00:00 2001 From: John Burley Date: Thu, 25 Jun 2026 16:36:01 -0400 Subject: [PATCH 2/5] satisfy linter --- Source/Core/Core/HW/WII_IPC.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 1de27068e5..7e666277a5 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -10,10 +10,10 @@ #include "Core/CoreTiming.h" #include "Core/HW/DVD/DVDInterface.h" #include "Core/HW/MMIO.h" +#include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" #include "Core/IOS/IOS.h" #include "Core/System.h" -#include "Core/HW/Memmap.h" // This is the intercommunication between ARM and PPC. Currently only PPC actually uses it, because // of the IOS HLE @@ -264,11 +264,9 @@ void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | VISOLID, MMIO::InvalidRead(), MMIO::Nop()); // Sets the Hollywood version register to 0x11 (same as placed in lomem) mmio->Register(base | VERSION, MMIO::Constant(0x00000011), MMIO::Nop()); - + const bool mem2_128 = memory.GetExRamSizeReal() == Memory::MEM2_SIZE_NDEV; - mmio->Register(base | IS_128, - MMIO::Constant(mem2_128 ? 1 : 0), - MMIO::Nop()); + mmio->Register(base | IS_128, MMIO::Constant(mem2_128 ? 1 : 0), MMIO::Nop()); mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); From 455eb5676254b388dd39feb44d8f9fb2ab5c5217 Mon Sep 17 00:00:00 2001 From: John Burley Date: Thu, 25 Jun 2026 18:29:47 -0400 Subject: [PATCH 3/5] Add row and mask register emulation --- Source/Core/Core/HW/WII_IPC.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 7e666277a5..9e1d086df3 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -60,7 +60,9 @@ enum VERSION = 0x214, - IS_128 = 0xB4216, + MEM2_ROWSEL = 0xB4212, + MEM2_RANKSEL = 0xB4216, + MEM2_ROWMSK = 0xB421A, }; // Indicates which pins are accessible by broadway. Writable by starlet only. @@ -265,8 +267,10 @@ void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) // Sets the Hollywood version register to 0x11 (same as placed in lomem) mmio->Register(base | VERSION, MMIO::Constant(0x00000011), MMIO::Nop()); - const bool mem2_128 = memory.GetExRamSizeReal() == Memory::MEM2_SIZE_NDEV; - mmio->Register(base | IS_128, MMIO::Constant(mem2_128 ? 1 : 0), MMIO::Nop()); + const bool mem2_is_128 = memory.GetExRamSizeReal() == Memory::MEM2_SIZE_NDEV; + mmio->Register(base | MEM2_ROWSEL, MMIO::Constant(4), MMIO::Nop()); + mmio->Register(base | MEM2_RANKSEL, MMIO::Constant(mem2_is_128 ? 1 : 7), MMIO::Nop()); + mmio->Register(base | MEM2_ROWMSK, MMIO::Constant(0xFFF), MMIO::Nop()); mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); From 51eae5618665428c99ccb1ea2295f48c0645602f Mon Sep 17 00:00:00 2001 From: John Burley Date: Fri, 26 Jun 2026 10:38:22 -0400 Subject: [PATCH 4/5] add the rest of the memory physical layout registers --- Source/Core/Core/HW/WII_IPC.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 9e1d086df3..75bc9776ff 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -60,9 +60,16 @@ enum VERSION = 0x214, + // Memory controller registers + + MEM2_COLSEL = 0xB4210, MEM2_ROWSEL = 0xB4212, + MEM2_BANKSEL = 0xB4214, MEM2_RANKSEL = 0xB4216, + + MEM2_COLMSK = 0xB4218, MEM2_ROWMSK = 0xB421A, + MEM2_BANKMSK = 0xB421C, }; // Indicates which pins are accessible by broadway. Writable by starlet only. @@ -268,9 +275,15 @@ void WiiIPC::RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | VERSION, MMIO::Constant(0x00000011), MMIO::Nop()); const bool mem2_is_128 = memory.GetExRamSizeReal() == Memory::MEM2_SIZE_NDEV; + + mmio->Register(base | MEM2_COLSEL, MMIO::Constant(6), MMIO::Nop()); mmio->Register(base | MEM2_ROWSEL, MMIO::Constant(4), MMIO::Nop()); + mmio->Register(base | MEM2_BANKSEL, MMIO::Constant(2), MMIO::Nop()); mmio->Register(base | MEM2_RANKSEL, MMIO::Constant(mem2_is_128 ? 1 : 7), MMIO::Nop()); + + mmio->Register(base | MEM2_COLMSK, MMIO::Constant(0x1FF), MMIO::Nop()); mmio->Register(base | MEM2_ROWMSK, MMIO::Constant(0xFFF), MMIO::Nop()); + mmio->Register(base | MEM2_BANKMSK, MMIO::Constant(7), MMIO::Nop()); mmio->Register(base | UNK_180, MMIO::Constant(0), MMIO::Nop()); mmio->Register(base | UNK_1CC, MMIO::Constant(0), MMIO::Nop()); From b5330d10922a85b3fb32e512247310ed46558e2f Mon Sep 17 00:00:00 2001 From: John Burley Date: Fri, 26 Jun 2026 10:49:38 -0400 Subject: [PATCH 5/5] satisfy linter --- Source/Core/Core/HW/MemoryInterface.cpp | 44 ++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Source/Core/Core/HW/MemoryInterface.cpp b/Source/Core/Core/HW/MemoryInterface.cpp index ba0015214f..ac9ddd116b 100644 --- a/Source/Core/Core/HW/MemoryInterface.cpp +++ b/Source/Core/Core/HW/MemoryInterface.cpp @@ -10,8 +10,8 @@ #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Core/HW/MMIO.h" -#include "Core/System.h" #include "Core/HW/Memmap.h" +#include "Core/System.h" namespace MemoryInterface { @@ -78,22 +78,23 @@ void MemoryInterfaceManager::DoState(PointerWrap& p) static u16 EncodeMemConfig(u32 ram_size) { - switch (ram_size) - { - case 0x1000000: // 16MiB - return 0; - case 0x1800000: // 24MiB - return 2; - case 0x2000000: // 32MiB - return 1; - case 0x3000000: // 48MiB - return 3; - case 0x4000000: // 64MiB - return 5; - default: - return 2; // Bespoke configs can't be represented in this bitfield - // Fallback to 24. Potentially dangerous, but when not emulating this register at all it is seen as 16 - } + switch (ram_size) + { + case 0x1000000: // 16MiB + return 0; + case 0x1800000: // 24MiB + return 2; + case 0x2000000: // 32MiB + return 1; + case 0x3000000: // 48MiB + return 3; + case 0x4000000: // 64MiB + return 5; + default: + return 2; // Bespoke configs can't be represented in this bitfield + // Fallback to 24. Potentially dangerous, but when not emulating this register at all + // it is seen as 16 + } } void MemoryInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -129,11 +130,10 @@ void MemoryInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base) // MI RAM configuration strap. The low 3 bits encode the installed MEM1 // size; the SDK uses this to populate OS global 0x80000028. - mmio->Register(base | MI_MEM_CONFIG, - MMIO::ComplexRead([](Core::System& system, u32) { - return EncodeMemConfig(system.GetMemory().GetRamSizeReal()); - }), - MMIO::Nop()); + mmio->Register(base | MI_MEM_CONFIG, MMIO::ComplexRead([](Core::System& system, u32) { + return EncodeMemConfig(system.GetMemory().GetRamSizeReal()); + }), + MMIO::Nop()); for (u32 i = 0; i < m_mi_mem.timers.size(); ++i) {