HW: stabilize original BootMii interaction

This commit is contained in:
2026-08-25 23:26:29 +02:00
parent 5387658e0c
commit b85667435c
5 changed files with 57 additions and 13 deletions
+5 -1
View File
@@ -77,7 +77,11 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
mmio->Register(base | PI_INTERRUPT_CAUSE, MMIO::DirectRead<u32>(&m_interrupt_cause),
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
auto& processor_interface = system.GetProcessorInterface();
processor_interface.m_interrupt_cause &= ~val;
// The reset-button bit is a live, active-low input state rather than an
// interrupt latch. Software can acknowledge the other causes, but must not be
// able to turn an unpressed reset button into a permanently pressed one.
processor_interface.m_interrupt_cause =
AcknowledgeInterruptCauses(processor_interface.m_interrupt_cause, val);
processor_interface.UpdateException();
}));
+5
View File
@@ -78,6 +78,11 @@ enum ErrorCause : u32
Reserved = 7,
};
constexpr u32 AcknowledgeInterruptCauses(u32 current, u32 acknowledged)
{
return current & ~(acknowledged & ~static_cast<u32>(INT_CAUSE_RST_BUTTON));
}
class ProcessorInterfaceManager
{
public:
+23 -9
View File
@@ -320,9 +320,12 @@ void VideoInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
return 1 + (vi.m_half_line_count) / 2;
}),
MMIO::ComplexWrite<u16>([](Core::System& system, u32, u16 val) {
WARN_LOG_FMT(
VIDEOINTERFACE,
"Changing vertical beam position to {:#06x} - not documented or implemented yet", val);
auto& vi = system.GetVideoInterface();
const u32 total_half_lines = vi.GetHalfLinesPerEvenField() + vi.GetHalfLinesPerOddField();
const u32 line = val == 0 ? 0 : static_cast<u32>(val - 1);
const u32 target_half_line = line * 2 + (vi.m_half_line_count & 1);
vi.m_half_line_count =
total_half_lines == 0 ? target_half_line : target_half_line % total_half_lines;
}));
mmio->Register(
base | VI_HORIZONTAL_BEAM_POSITION, MMIO::ComplexRead<u16>([](Core::System& system, u32) {
@@ -334,10 +337,20 @@ void VideoInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
return std::clamp<u16>(value, 1, vi.m_h_timing_0.HLW * 2);
}),
MMIO::ComplexWrite<u16>([](Core::System& system, u32, u16 val) {
WARN_LOG_FMT(
VIDEOINTERFACE,
"Changing horizontal beam position to {:#06x} - not documented or implemented yet",
val);
auto& vi = system.GetVideoInterface();
const u32 half_line_width = vi.m_h_timing_0.HLW;
if (half_line_width == 0)
return;
const u32 horizontal_position =
std::clamp<u32>(val, 1, static_cast<u32>(half_line_width) * 2);
const u32 target_half_line = horizontal_position > half_line_width ? 1 : 0;
vi.m_half_line_count = (vi.m_half_line_count & ~1u) | target_half_line;
const u64 ticks_into_line =
static_cast<u64>(horizontal_position - 1) * vi.GetTicksPerHalfLine() / half_line_width;
const u64 ticks = system.GetCoreTiming().GetTicks();
vi.m_ticks_last_line_start = ticks >= ticks_into_line ? ticks - ticks_into_line : 0;
}));
// The following MMIOs are interrupts related and update interrupt status
@@ -972,9 +985,10 @@ void VideoInterfaceManager::Update(u64 ticks)
// the beginning of a new full-line, update the timer
++m_half_line_count;
if (m_half_line_count == GetHalfLinesPerEvenField() + GetHalfLinesPerOddField())
const u32 total_half_lines = GetHalfLinesPerEvenField() + GetHalfLinesPerOddField();
if (total_half_lines != 0 && m_half_line_count >= total_half_lines)
{
m_half_line_count = 0;
m_half_line_count %= total_half_lines;
}
if (!(m_half_line_count & 1))
+9
View File
@@ -9,6 +9,7 @@
#include "Common/CommonTypes.h"
#include "Core/HW/GPFifo.h"
#include "Core/HW/MMIO.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/System.h"
// Tests that the UniqueID function returns a "unique enough" identifier
@@ -53,6 +54,14 @@ TEST(IsMMIOAddress, SpecialAddresses)
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D800F10, is_wii)); // Mirror of Wii MMIOs
}
TEST(ProcessorInterface, ResetButtonStateCannotBeAcknowledged)
{
constexpr u32 reset = ProcessorInterface::INT_CAUSE_RST_BUTTON;
EXPECT_EQ(reset, ProcessorInterface::AcknowledgeInterruptCauses(
reset | ProcessorInterface::INT_CAUSE_VI, 0xffffffffu));
EXPECT_EQ(0u, ProcessorInterface::AcknowledgeInterruptCauses(0, 0xffffffffu));
}
class MappingTest : public testing::Test
{
protected:
+15 -3
View File
@@ -295,10 +295,21 @@ An isolated boot probe using the local, mutually matching dumps has executed thi
EXI paths, published its EXI Broadway boot vector, released Broadway, and ran the original
`ppcboot.elf`. The interactive four-icon BootMii menu rendered without a host-side firmware
jump, a patched BootMii binary, or a synthesized SI reply.
21. BootMii exposed two remaining Broadway hardware differences. Its VI setup writes the vertical
and horizontal beam-position registers; ignoring those writes let Dolphin's half-line counter
escape the active field and prevented the next VI interrupt. The beam writes now reposition the
emulated raster and field wrapping tolerates an out-of-range position. BootMii also clears the
PI interrupt-cause register before polling the front-panel controls. The reset-button bit is a
live active-low input, not an acknowledgeable interrupt latch, so PI acknowledgements now
preserve it. This removed the false held-RESET state that selected the Wii icon and issued
`IPC_BOOT2_RUN(1, 2)` immediately. Cold-boot BootMii and HBC -> IOS254 -> MINI -> BootMii both
remain in the original interactive menu, and keyboard-backed GameCube navigation was validated
without modifying `armboot.bin`, `ppcboot.elf`, or `bootmii.ini`.
The probe never prints ROM, NAND, key, or firmware instruction bytes. The committed unit suite
covers ARM-to-Thumb loads into PC, high Starlet exception vectors, privileged `LDM ... ^` user-bank
transfers, latched bidirectional IPC control bits, empty-slot SDHCI reset/clock/status behavior,
transfers, latched bidirectional IPC control bits, the PI reset-button state surviving interrupt
acknowledgements, empty-slot SDHCI reset/clock/status behavior,
timer equal/future comparator matches with independent IRQ write-one-to-clear acknowledgement,
OHCI power-good/root-hub state, and a complete three-TD USB device-descriptor transaction. Targeted
development probes additionally exercised NAND read/program/erase and program-time ECC, SEEPROM
@@ -317,8 +328,8 @@ the three pre-existing bad-ECC pages in the source dump, a valid EXI reset vecto
The current end-to-end boundary is a rendered, controller-connected and post-health-screen System
Menu with its populated channel grid, followed by a successful original IOS80-to-IOS58 reload, a
rendered Homebrew Channel, LetterBomb reaching the interactive HackMii Installer menu, and the
dump's BootMii-as-boot2 installation reaching its original interactive UI through MINI and
rendered Homebrew Channel, LetterBomb reaching the interactive HackMii Installer menu, and both
cold-boot and IOS254 launches reaching a stable, navigable original BootMii UI through MINI and
`ppcboot.elf`. The path sustains PPC-to-original-IOS filesystem, DI, Bluetooth HID, SDIO/Wi-Fi and
network-service traffic. The stabilized Menu has been measured at 59.91 FPS and HBC at 59.94 FPS.
It proves the emulated first Wii Remote's pairing, L2CAP setup, command exchange and input-report
@@ -387,6 +398,7 @@ than a drop-in replacement for Dolphin's mature IOS HLE mode.
| Address space and devices | `Core/IOS/Starlet/StarletMemory.{h,cpp}` |
| Bluetooth pairing and Wii Remote HID | `Core/IOS/USB/Bluetooth/{BTBase,WiimoteDevice}.{h,cpp}` |
| IPC and Broadway reset | `Core/HW/WII_IPC.{h,cpp}` |
| Broadway VI and front-panel state | `Core/HW/VideoInterface.cpp`, `Core/HW/ProcessorInterface.{h,cpp}` |
| Mode selection/lifetime | `Core/HW/HW.cpp`, `Core/System.{h,cpp}` |
| Boot-path separation | `Core/Boot/Boot.cpp`, `Core/ConfigManager.cpp`, `Core/Core.cpp` |
| Configuration | `Core/Config/MainSettings.{h,cpp}` |