Track exact StarletOS bootstrap integration and checkpoint provenance
Recover 16 modified and 6 previously untracked integration files. All 22 source SHA-256s match the pre-publication StarletOS snapshot. Add handoff instructions, byte-preserving attributes and private backup exclusion. This commit publishes existing behavior; it does not claim a new full build or hardware qualification. The two preceding local commits and staged files were screened before publication.
This commit is contained in:
1 parent
a8dbbab62d
commit
54f5a74bbf
28 files changed
+9161
-7407
No files matched your search
+800
-795
File diff suppressed because it is too large.
Load diff
+865
-863
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,442 +1,443 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Core/USBUtils.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
|
||||
// DSP Backend Types
|
||||
#define BACKEND_NULLSOUND _trans("No Audio Output")
|
||||
#define BACKEND_ALSA "ALSA"
|
||||
#define BACKEND_CUBEB "Cubeb"
|
||||
#define BACKEND_OPENAL "OpenAL"
|
||||
#define BACKEND_PULSEAUDIO "Pulse"
|
||||
#define BACKEND_OPENSLES "OpenSLES"
|
||||
#define BACKEND_WASAPI _trans("WASAPI (Exclusive Mode)")
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
enum class CPUCore;
|
||||
}
|
||||
|
||||
namespace AudioCommon
|
||||
{
|
||||
enum class DPL2Quality;
|
||||
}
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
enum class EXIDeviceType : int;
|
||||
enum class Slot : int;
|
||||
} // namespace ExpansionInterface
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
enum SIDevices : int;
|
||||
}
|
||||
|
||||
namespace HSP
|
||||
{
|
||||
enum class HSPDeviceType : int;
|
||||
}
|
||||
|
||||
namespace Config
|
||||
{
|
||||
// Main.Core
|
||||
|
||||
extern const Info<bool> MAIN_SKIP_IPL;
|
||||
extern const Info<PowerPC::CPUCore> MAIN_CPU_CORE;
|
||||
extern const Info<bool> MAIN_JIT_FOLLOW_BRANCH;
|
||||
extern const Info<bool> MAIN_FASTMEM;
|
||||
extern const Info<bool> MAIN_PAGE_TABLE_FASTMEM;
|
||||
extern const Info<bool> MAIN_FASTMEM_ARENA;
|
||||
extern const Info<bool> MAIN_LARGE_ENTRY_POINTS_MAP;
|
||||
extern const Info<bool> MAIN_ACCURATE_CPU_CACHE;
|
||||
// Should really be in the DSP section, but we're kind of stuck with bad decisions made in the past.
|
||||
extern const Info<bool> MAIN_DSP_HLE;
|
||||
extern const Info<int> MAIN_MAX_FALLBACK;
|
||||
extern const Info<int> MAIN_TIMING_VARIANCE;
|
||||
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
|
||||
extern const Info<bool> MAIN_RUSH_FRAME_PRESENTATION;
|
||||
extern const Info<bool> MAIN_SMOOTH_EARLY_PRESENTATION;
|
||||
extern const Info<bool> MAIN_CPU_THREAD;
|
||||
extern const Info<bool> MAIN_LOAD_GAME_INTO_MEMORY;
|
||||
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
||||
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
||||
extern const Info<bool> MAIN_ENABLE_CHEATS;
|
||||
extern const Info<int> MAIN_GC_LANGUAGE;
|
||||
extern const Info<bool> MAIN_OVERRIDE_REGION_SETTINGS;
|
||||
extern const Info<bool> MAIN_DPL2_DECODER;
|
||||
extern const Info<AudioCommon::DPL2Quality> MAIN_DPL2_QUALITY;
|
||||
extern const Info<int> MAIN_AUDIO_LATENCY;
|
||||
extern const Info<int> MAIN_AUDIO_BUFFER_SIZE;
|
||||
extern const Info<bool> MAIN_AUDIO_FILL_GAPS;
|
||||
extern const Info<bool> MAIN_AUDIO_PRESERVE_PITCH;
|
||||
extern const Info<std::string> MAIN_MEMCARD_A_PATH;
|
||||
extern const Info<std::string> MAIN_MEMCARD_B_PATH;
|
||||
const Info<std::string>& GetInfoForMemcardPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_AGP_CART_A_PATH;
|
||||
extern const Info<std::string> MAIN_AGP_CART_B_PATH;
|
||||
const Info<std::string>& GetInfoForAGPCartPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH;
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH;
|
||||
const Info<std::string>& GetInfoForGCIPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE;
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE;
|
||||
const Info<std::string>& GetInfoForGCIPathOverride(ExpansionInterface::Slot slot);
|
||||
extern const Info<int> MAIN_MEMORY_CARD_SIZE;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_A;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_B;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_1;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_2;
|
||||
const Info<ExpansionInterface::EXIDeviceType>& GetInfoForEXIDevice(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_BBA_MAC;
|
||||
extern const Info<std::string> MAIN_BBA_XLINK_IP;
|
||||
extern const Info<bool> MAIN_BBA_XLINK_CHAT_OSD;
|
||||
extern const Info<std::string> MAIN_BBA_BUILTIN_DNS;
|
||||
extern const Info<std::string> MAIN_BBA_BUILTIN_IP;
|
||||
extern const Info<std::string> MAIN_BBA_TAPSERVER_DESTINATION;
|
||||
extern const Info<std::string> MAIN_MODEM_TAPSERVER_DESTINATION;
|
||||
const Info<SerialInterface::SIDevices>& GetInfoForSIDevice(int channel);
|
||||
const Info<bool>& GetInfoForAdapterRumble(int channel);
|
||||
const Info<bool>& GetInfoForSimulateKonga(int channel);
|
||||
extern const Info<bool> MAIN_WII_SD_CARD;
|
||||
extern const Info<bool> MAIN_WII_SD_CARD_ENABLE_FOLDER_SYNC;
|
||||
extern const Info<u64> MAIN_WII_SD_CARD_FILESIZE;
|
||||
extern const Info<bool> MAIN_WII_KEYBOARD;
|
||||
extern const Info<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING;
|
||||
extern const Info<std::string> MAIN_WIIMOTE_AUTO_CONNECT_ADDRESSES;
|
||||
extern const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER;
|
||||
extern const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE;
|
||||
extern const Info<bool> MAIN_MMU;
|
||||
extern const Info<bool> MAIN_PAUSE_ON_PANIC;
|
||||
extern const Info<int> MAIN_BB_DUMP_PORT;
|
||||
extern const Info<bool> MAIN_SYNC_GPU;
|
||||
extern const Info<int> MAIN_SYNC_GPU_MAX_DISTANCE;
|
||||
extern const Info<int> MAIN_SYNC_GPU_MIN_DISTANCE;
|
||||
extern const Info<float> MAIN_SYNC_GPU_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_FAST_DISC_SPEED;
|
||||
extern const Info<bool> MAIN_LOW_DCBZ_HACK;
|
||||
extern const Info<bool> MAIN_FLOAT_EXCEPTIONS;
|
||||
extern const Info<bool> MAIN_DIVIDE_BY_ZERO_EXCEPTIONS;
|
||||
extern const Info<bool> MAIN_FPRF;
|
||||
extern const Info<bool> MAIN_ACCURATE_NANS;
|
||||
extern const Info<bool> MAIN_ACCURATE_FMADDS;
|
||||
extern const Info<bool> MAIN_DISABLE_ICACHE;
|
||||
extern const Info<float> MAIN_EMULATION_SPEED;
|
||||
extern const Info<bool> MAIN_PRECISION_FRAME_TIMING;
|
||||
extern const Info<float> MAIN_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_OVERCLOCK_ENABLE;
|
||||
extern const Info<float> MAIN_VI_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_VI_OVERCLOCK_ENABLE;
|
||||
extern const Info<bool> MAIN_RAM_OVERRIDE_ENABLE;
|
||||
extern const Info<u32> MAIN_MEM1_SIZE;
|
||||
extern const Info<u32> MAIN_MEM2_SIZE;
|
||||
// Should really be part of System::GFX, but again, we're stuck with past mistakes.
|
||||
extern const Info<std::string> MAIN_GFX_BACKEND;
|
||||
extern const Info<HSP::HSPDeviceType> MAIN_HSP_DEVICE;
|
||||
extern const Info<u32> MAIN_ARAM_EXPANSION_SIZE;
|
||||
|
||||
enum class GPUDeterminismMode
|
||||
{
|
||||
Auto,
|
||||
Disabled,
|
||||
// This is currently the only mode. There will probably be at least
|
||||
// one more at some point.
|
||||
FakeCompletion,
|
||||
};
|
||||
extern const Info<std::string> MAIN_GPU_DETERMINISM_MODE;
|
||||
GPUDeterminismMode GetGPUDeterminismMode();
|
||||
|
||||
extern const Info<std::string> MAIN_PERF_MAP_DIR;
|
||||
extern const Info<bool> MAIN_CUSTOM_RTC_ENABLE;
|
||||
extern const Info<u32> MAIN_CUSTOM_RTC_VALUE;
|
||||
extern const Info<bool> MAIN_AUTO_DISC_CHANGE;
|
||||
extern const Info<bool> MAIN_ALLOW_SD_WRITES;
|
||||
extern const Info<bool> MAIN_ENABLE_SAVESTATES;
|
||||
extern const Info<DiscIO::Region> MAIN_FALLBACK_REGION;
|
||||
extern const Info<bool> MAIN_REAL_WII_REMOTE_REPEAT_REPORTS;
|
||||
extern const Info<s32> MAIN_OVERRIDE_BOOT_IOS;
|
||||
extern const Info<bool> MAIN_WII_IOS_LLE;
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Core/USBUtils.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
|
||||
// DSP Backend Types
|
||||
#define BACKEND_NULLSOUND _trans("No Audio Output")
|
||||
#define BACKEND_ALSA "ALSA"
|
||||
#define BACKEND_CUBEB "Cubeb"
|
||||
#define BACKEND_OPENAL "OpenAL"
|
||||
#define BACKEND_PULSEAUDIO "Pulse"
|
||||
#define BACKEND_OPENSLES "OpenSLES"
|
||||
#define BACKEND_WASAPI _trans("WASAPI (Exclusive Mode)")
|
||||
|
||||
namespace PowerPC
|
||||
{
|
||||
enum class CPUCore;
|
||||
}
|
||||
|
||||
namespace AudioCommon
|
||||
{
|
||||
enum class DPL2Quality;
|
||||
}
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
enum class EXIDeviceType : int;
|
||||
enum class Slot : int;
|
||||
} // namespace ExpansionInterface
|
||||
|
||||
namespace SerialInterface
|
||||
{
|
||||
enum SIDevices : int;
|
||||
}
|
||||
|
||||
namespace HSP
|
||||
{
|
||||
enum class HSPDeviceType : int;
|
||||
}
|
||||
|
||||
namespace Config
|
||||
{
|
||||
// Main.Core
|
||||
|
||||
extern const Info<bool> MAIN_SKIP_IPL;
|
||||
extern const Info<PowerPC::CPUCore> MAIN_CPU_CORE;
|
||||
extern const Info<bool> MAIN_JIT_FOLLOW_BRANCH;
|
||||
extern const Info<bool> MAIN_FASTMEM;
|
||||
extern const Info<bool> MAIN_PAGE_TABLE_FASTMEM;
|
||||
extern const Info<bool> MAIN_FASTMEM_ARENA;
|
||||
extern const Info<bool> MAIN_LARGE_ENTRY_POINTS_MAP;
|
||||
extern const Info<bool> MAIN_ACCURATE_CPU_CACHE;
|
||||
// Should really be in the DSP section, but we're kind of stuck with bad decisions made in the past.
|
||||
extern const Info<bool> MAIN_DSP_HLE;
|
||||
extern const Info<int> MAIN_MAX_FALLBACK;
|
||||
extern const Info<int> MAIN_TIMING_VARIANCE;
|
||||
extern const Info<bool> MAIN_CORRECT_TIME_DRIFT;
|
||||
extern const Info<bool> MAIN_RUSH_FRAME_PRESENTATION;
|
||||
extern const Info<bool> MAIN_SMOOTH_EARLY_PRESENTATION;
|
||||
extern const Info<bool> MAIN_CPU_THREAD;
|
||||
extern const Info<bool> MAIN_LOAD_GAME_INTO_MEMORY;
|
||||
extern const Info<bool> MAIN_SYNC_ON_SKIP_IDLE;
|
||||
extern const Info<std::string> MAIN_DEFAULT_ISO;
|
||||
extern const Info<bool> MAIN_ENABLE_CHEATS;
|
||||
extern const Info<int> MAIN_GC_LANGUAGE;
|
||||
extern const Info<bool> MAIN_OVERRIDE_REGION_SETTINGS;
|
||||
extern const Info<bool> MAIN_DPL2_DECODER;
|
||||
extern const Info<AudioCommon::DPL2Quality> MAIN_DPL2_QUALITY;
|
||||
extern const Info<int> MAIN_AUDIO_LATENCY;
|
||||
extern const Info<int> MAIN_AUDIO_BUFFER_SIZE;
|
||||
extern const Info<bool> MAIN_AUDIO_FILL_GAPS;
|
||||
extern const Info<bool> MAIN_AUDIO_PRESERVE_PITCH;
|
||||
extern const Info<std::string> MAIN_MEMCARD_A_PATH;
|
||||
extern const Info<std::string> MAIN_MEMCARD_B_PATH;
|
||||
const Info<std::string>& GetInfoForMemcardPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_AGP_CART_A_PATH;
|
||||
extern const Info<std::string> MAIN_AGP_CART_B_PATH;
|
||||
const Info<std::string>& GetInfoForAGPCartPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH;
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH;
|
||||
const Info<std::string>& GetInfoForGCIPath(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE;
|
||||
extern const Info<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE;
|
||||
const Info<std::string>& GetInfoForGCIPathOverride(ExpansionInterface::Slot slot);
|
||||
extern const Info<int> MAIN_MEMORY_CARD_SIZE;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_A;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SLOT_B;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_1;
|
||||
extern const Info<ExpansionInterface::EXIDeviceType> MAIN_SERIAL_PORT_2;
|
||||
const Info<ExpansionInterface::EXIDeviceType>& GetInfoForEXIDevice(ExpansionInterface::Slot slot);
|
||||
extern const Info<std::string> MAIN_BBA_MAC;
|
||||
extern const Info<std::string> MAIN_BBA_XLINK_IP;
|
||||
extern const Info<bool> MAIN_BBA_XLINK_CHAT_OSD;
|
||||
extern const Info<std::string> MAIN_BBA_BUILTIN_DNS;
|
||||
extern const Info<std::string> MAIN_BBA_BUILTIN_IP;
|
||||
extern const Info<std::string> MAIN_BBA_TAPSERVER_DESTINATION;
|
||||
extern const Info<std::string> MAIN_MODEM_TAPSERVER_DESTINATION;
|
||||
const Info<SerialInterface::SIDevices>& GetInfoForSIDevice(int channel);
|
||||
const Info<bool>& GetInfoForAdapterRumble(int channel);
|
||||
const Info<bool>& GetInfoForSimulateKonga(int channel);
|
||||
extern const Info<bool> MAIN_WII_SD_CARD;
|
||||
extern const Info<bool> MAIN_WII_SD_CARD_ENABLE_FOLDER_SYNC;
|
||||
extern const Info<u64> MAIN_WII_SD_CARD_FILESIZE;
|
||||
extern const Info<bool> MAIN_WII_KEYBOARD;
|
||||
extern const Info<bool> MAIN_WIIMOTE_CONTINUOUS_SCANNING;
|
||||
extern const Info<std::string> MAIN_WIIMOTE_AUTO_CONNECT_ADDRESSES;
|
||||
extern const Info<bool> MAIN_WIIMOTE_ENABLE_SPEAKER;
|
||||
extern const Info<bool> MAIN_CONNECT_WIIMOTES_FOR_CONTROLLER_INTERFACE;
|
||||
extern const Info<bool> MAIN_MMU;
|
||||
extern const Info<bool> MAIN_PAUSE_ON_PANIC;
|
||||
extern const Info<int> MAIN_BB_DUMP_PORT;
|
||||
extern const Info<bool> MAIN_SYNC_GPU;
|
||||
extern const Info<int> MAIN_SYNC_GPU_MAX_DISTANCE;
|
||||
extern const Info<int> MAIN_SYNC_GPU_MIN_DISTANCE;
|
||||
extern const Info<float> MAIN_SYNC_GPU_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_FAST_DISC_SPEED;
|
||||
extern const Info<bool> MAIN_LOW_DCBZ_HACK;
|
||||
extern const Info<bool> MAIN_FLOAT_EXCEPTIONS;
|
||||
extern const Info<bool> MAIN_DIVIDE_BY_ZERO_EXCEPTIONS;
|
||||
extern const Info<bool> MAIN_FPRF;
|
||||
extern const Info<bool> MAIN_ACCURATE_NANS;
|
||||
extern const Info<bool> MAIN_ACCURATE_FMADDS;
|
||||
extern const Info<bool> MAIN_DISABLE_ICACHE;
|
||||
extern const Info<float> MAIN_EMULATION_SPEED;
|
||||
extern const Info<bool> MAIN_PRECISION_FRAME_TIMING;
|
||||
extern const Info<float> MAIN_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_OVERCLOCK_ENABLE;
|
||||
extern const Info<float> MAIN_VI_OVERCLOCK;
|
||||
extern const Info<bool> MAIN_VI_OVERCLOCK_ENABLE;
|
||||
extern const Info<bool> MAIN_RAM_OVERRIDE_ENABLE;
|
||||
extern const Info<u32> MAIN_MEM1_SIZE;
|
||||
extern const Info<u32> MAIN_MEM2_SIZE;
|
||||
// Should really be part of System::GFX, but again, we're stuck with past mistakes.
|
||||
extern const Info<std::string> MAIN_GFX_BACKEND;
|
||||
extern const Info<HSP::HSPDeviceType> MAIN_HSP_DEVICE;
|
||||
extern const Info<u32> MAIN_ARAM_EXPANSION_SIZE;
|
||||
|
||||
enum class GPUDeterminismMode
|
||||
{
|
||||
Auto,
|
||||
Disabled,
|
||||
// This is currently the only mode. There will probably be at least
|
||||
// one more at some point.
|
||||
FakeCompletion,
|
||||
};
|
||||
extern const Info<std::string> MAIN_GPU_DETERMINISM_MODE;
|
||||
GPUDeterminismMode GetGPUDeterminismMode();
|
||||
|
||||
extern const Info<std::string> MAIN_PERF_MAP_DIR;
|
||||
extern const Info<bool> MAIN_CUSTOM_RTC_ENABLE;
|
||||
extern const Info<u32> MAIN_CUSTOM_RTC_VALUE;
|
||||
extern const Info<bool> MAIN_AUTO_DISC_CHANGE;
|
||||
extern const Info<bool> MAIN_ALLOW_SD_WRITES;
|
||||
extern const Info<bool> MAIN_ENABLE_SAVESTATES;
|
||||
extern const Info<DiscIO::Region> MAIN_FALLBACK_REGION;
|
||||
extern const Info<bool> MAIN_REAL_WII_REMOTE_REPEAT_REPORTS;
|
||||
extern const Info<s32> MAIN_OVERRIDE_BOOT_IOS;
|
||||
extern const Info<bool> MAIN_WII_IOS_LLE;
|
||||
extern const Info<bool> MAIN_WII_STARLET_JIT;
|
||||
extern const Info<bool> MAIN_WII_STARLET_JIT_MEMORY_PROFILING;
|
||||
extern const Info<bool> MAIN_WII_LLE_ETHERNET;
|
||||
extern const Info<std::string> MAIN_WII_NUS_SHOP_URL;
|
||||
extern const Info<bool> MAIN_WII_WIILINK_ENABLE;
|
||||
|
||||
// Main.DSP
|
||||
|
||||
extern const Info<bool> MAIN_DSP_THREAD;
|
||||
extern const Info<bool> MAIN_DSP_CAPTURE_LOG;
|
||||
extern const Info<bool> MAIN_DSP_JIT;
|
||||
extern const Info<bool> MAIN_DUMP_AUDIO;
|
||||
extern const Info<bool> MAIN_DUMP_AUDIO_SILENT;
|
||||
extern const Info<bool> MAIN_DUMP_UCODE;
|
||||
extern const Info<std::string> MAIN_AUDIO_BACKEND;
|
||||
extern const Info<int> MAIN_AUDIO_VOLUME;
|
||||
extern const Info<bool> MAIN_AUDIO_MUTED;
|
||||
extern const Info<bool> MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT;
|
||||
#ifdef _WIN32
|
||||
extern const Info<std::string> MAIN_WASAPI_DEVICE;
|
||||
#endif
|
||||
|
||||
bool ShouldUseDPL2Decoder();
|
||||
|
||||
// Main.Display
|
||||
|
||||
extern const Info<std::string> MAIN_FULLSCREEN_DISPLAY_RES;
|
||||
extern const Info<bool> MAIN_FULLSCREEN;
|
||||
extern const Info<bool> MAIN_RENDER_TO_MAIN;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_XPOS;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_YPOS;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_WIDTH;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_HEIGHT;
|
||||
extern const Info<bool> MAIN_RENDER_WINDOW_AUTOSIZE;
|
||||
extern const Info<bool> MAIN_KEEP_WINDOW_ON_TOP;
|
||||
extern const Info<bool> MAIN_DISABLE_SCREENSAVER;
|
||||
extern const Info<bool> MAIN_TIME_TRACKING;
|
||||
|
||||
// Main.General
|
||||
|
||||
extern const Info<std::string> MAIN_DUMP_PATH;
|
||||
extern const Info<std::string> MAIN_LOAD_PATH;
|
||||
extern const Info<std::string> MAIN_RESOURCEPACK_PATH;
|
||||
extern const Info<std::string> MAIN_FS_PATH;
|
||||
extern const Info<std::string> MAIN_WII_NUS_SHOP_URL;
|
||||
extern const Info<bool> MAIN_WII_WIILINK_ENABLE;
|
||||
|
||||
// Main.DSP
|
||||
|
||||
extern const Info<bool> MAIN_DSP_THREAD;
|
||||
extern const Info<bool> MAIN_DSP_CAPTURE_LOG;
|
||||
extern const Info<bool> MAIN_DSP_JIT;
|
||||
extern const Info<bool> MAIN_DUMP_AUDIO;
|
||||
extern const Info<bool> MAIN_DUMP_AUDIO_SILENT;
|
||||
extern const Info<bool> MAIN_DUMP_UCODE;
|
||||
extern const Info<std::string> MAIN_AUDIO_BACKEND;
|
||||
extern const Info<int> MAIN_AUDIO_VOLUME;
|
||||
extern const Info<bool> MAIN_AUDIO_MUTED;
|
||||
extern const Info<bool> MAIN_AUDIO_MUTE_ON_DISABLED_SPEED_LIMIT;
|
||||
#ifdef _WIN32
|
||||
extern const Info<std::string> MAIN_WASAPI_DEVICE;
|
||||
#endif
|
||||
|
||||
bool ShouldUseDPL2Decoder();
|
||||
|
||||
// Main.Display
|
||||
|
||||
extern const Info<std::string> MAIN_FULLSCREEN_DISPLAY_RES;
|
||||
extern const Info<bool> MAIN_FULLSCREEN;
|
||||
extern const Info<bool> MAIN_RENDER_TO_MAIN;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_XPOS;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_YPOS;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_WIDTH;
|
||||
extern const Info<int> MAIN_RENDER_WINDOW_HEIGHT;
|
||||
extern const Info<bool> MAIN_RENDER_WINDOW_AUTOSIZE;
|
||||
extern const Info<bool> MAIN_KEEP_WINDOW_ON_TOP;
|
||||
extern const Info<bool> MAIN_DISABLE_SCREENSAVER;
|
||||
extern const Info<bool> MAIN_TIME_TRACKING;
|
||||
|
||||
// Main.General
|
||||
|
||||
extern const Info<std::string> MAIN_DUMP_PATH;
|
||||
extern const Info<std::string> MAIN_LOAD_PATH;
|
||||
extern const Info<std::string> MAIN_RESOURCEPACK_PATH;
|
||||
extern const Info<std::string> MAIN_FS_PATH;
|
||||
extern const Info<std::string> MAIN_WII_LLE_DUMP_PATH;
|
||||
extern const Info<std::string> MAIN_WII_SD_CARD_IMAGE_PATH;
|
||||
extern const Info<std::string> MAIN_WII_SD_CARD_SYNC_FOLDER_PATH;
|
||||
extern const Info<std::string> MAIN_WFS_PATH;
|
||||
extern const Info<bool> MAIN_SHOW_LAG;
|
||||
extern const Info<bool> MAIN_SHOW_FRAME_COUNT;
|
||||
extern const Info<std::string> MAIN_WIRELESS_MAC;
|
||||
extern const Info<std::string> MAIN_GDB_SOCKET;
|
||||
extern const Info<int> MAIN_GDB_PORT;
|
||||
extern const Info<int> MAIN_ISO_PATH_COUNT;
|
||||
extern const Info<std::string> MAIN_SKYLANDERS_PATH;
|
||||
std::vector<std::string> GetIsoPaths();
|
||||
void SetIsoPaths(std::span<const std::string> paths);
|
||||
|
||||
// Main.GBA
|
||||
|
||||
#ifdef HAS_LIBMGBA
|
||||
extern const Info<std::string> MAIN_GBA_BIOS_PATH;
|
||||
extern const std::array<Info<std::string>, 5> MAIN_GBA_ROM_PATHS;
|
||||
extern const Info<std::string> MAIN_GBA_SAVES_PATH;
|
||||
extern const Info<bool> MAIN_GBA_SAVES_IN_ROM_PATH;
|
||||
|
||||
static constexpr std::size_t GBPLAYER_GBA_INDEX = 4;
|
||||
#endif
|
||||
|
||||
// Main.Network
|
||||
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_READ;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_WRITE;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_VERIFY_CERTIFICATES;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_ROOT_CA;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_PEER_CERT;
|
||||
extern const Info<bool> MAIN_NETWORK_DUMP_BBA;
|
||||
extern const Info<bool> MAIN_NETWORK_DUMP_AS_PCAP;
|
||||
extern const Info<int> MAIN_NETWORK_TIMEOUT;
|
||||
|
||||
// Main.Interface
|
||||
|
||||
extern const Info<bool> MAIN_USE_HIGH_CONTRAST_TOOLTIPS;
|
||||
extern const Info<bool> MAIN_USE_PANIC_HANDLERS;
|
||||
extern const Info<bool> MAIN_ABORT_ON_PANIC_ALERT;
|
||||
extern const Info<bool> MAIN_OSD_MESSAGES;
|
||||
extern const Info<int> MAIN_OSD_FONT_SIZE;
|
||||
extern const Info<bool> MAIN_SKIP_NKIT_WARNING;
|
||||
extern const Info<bool> MAIN_CONFIRM_ON_STOP;
|
||||
|
||||
enum class ShowCursor
|
||||
{
|
||||
Never,
|
||||
Constantly,
|
||||
OnMovement,
|
||||
};
|
||||
extern const Info<ShowCursor> MAIN_SHOW_CURSOR;
|
||||
|
||||
extern const Info<bool> MAIN_LOCK_CURSOR;
|
||||
extern const Info<std::string> MAIN_INTERFACE_LANGUAGE;
|
||||
extern const Info<bool> MAIN_SHOW_ACTIVE_TITLE;
|
||||
extern const Info<bool> MAIN_USE_BUILT_IN_TITLE_DATABASE;
|
||||
extern const Info<std::string> MAIN_THEME_NAME;
|
||||
extern const Info<bool> MAIN_PAUSE_ON_FOCUS_LOST;
|
||||
extern const Info<bool> MAIN_ENABLE_DEBUGGING;
|
||||
|
||||
// Main.Analytics
|
||||
|
||||
extern const Info<std::string> MAIN_ANALYTICS_ID;
|
||||
extern const Info<bool> MAIN_ANALYTICS_ENABLED;
|
||||
extern const Info<bool> MAIN_ANALYTICS_PERMISSION_ASKED;
|
||||
|
||||
// Main.GameList
|
||||
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_DRIVES;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WAD;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_ELF_DOL;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WII;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_GC;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_TRI;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_JPN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_PAL;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_USA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_AUSTRALIA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_FRANCE;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_GERMANY;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_ITALY;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_KOREA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_NETHERLANDS;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_RUSSIA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_SPAIN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_TAIWAN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WORLD;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_UNKNOWN;
|
||||
extern const Info<int> MAIN_GAMELIST_LIST_SORT;
|
||||
extern const Info<int> MAIN_GAMELIST_LIST_SORT_SECONDARY;
|
||||
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_PLATFORM;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_DESCRIPTION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_BANNER;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TITLE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_MAKER;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_NAME;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_PATH;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_GAME_ID;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_REGION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_SIZE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_FORMAT;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_BLOCK_SIZE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_COMPRESSION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TIME_PLAYED;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TAGS;
|
||||
|
||||
// Main.FifoPlayer
|
||||
|
||||
extern const Info<bool> MAIN_FIFOPLAYER_LOOP_REPLAY;
|
||||
extern const Info<bool> MAIN_FIFOPLAYER_EARLY_MEMORY_UPDATES;
|
||||
|
||||
// Main.AutoUpdate
|
||||
|
||||
extern const Info<std::string> MAIN_AUTOUPDATE_UPDATE_TRACK;
|
||||
extern const Info<std::string> MAIN_AUTOUPDATE_HASH_OVERRIDE;
|
||||
|
||||
// Main.Movie
|
||||
|
||||
extern const Info<bool> MAIN_MOVIE_PAUSE_MOVIE;
|
||||
extern const Info<std::string> MAIN_MOVIE_MOVIE_AUTHOR;
|
||||
extern const Info<bool> MAIN_MOVIE_DUMP_FRAMES;
|
||||
extern const Info<bool> MAIN_MOVIE_DUMP_FRAMES_SILENT;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_INPUT_DISPLAY;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_RTC;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_RERECORD;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_OSD;
|
||||
|
||||
// Main.Input
|
||||
|
||||
extern const Info<bool> MAIN_INPUT_BACKGROUND_INPUT;
|
||||
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_ENHANCED_REPORTS;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_WGI;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_DIRECTINPUT;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS;
|
||||
|
||||
// Main.Debug
|
||||
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LXZ_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LWZ_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LBZX_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_FLOATING_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_PAIRED_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_FLOATING_POINT_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_INTEGER_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_PAIRED_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_SYSTEM_REGISTERS_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_BRANCH_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_REGISTER_CACHE_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_ENABLE_PROFILING;
|
||||
|
||||
// Main.BluetoothPassthrough
|
||||
|
||||
extern const Info<bool> MAIN_BLUETOOTH_PASSTHROUGH_ENABLED;
|
||||
extern const Info<int> MAIN_BLUETOOTH_PASSTHROUGH_VID;
|
||||
extern const Info<int> MAIN_BLUETOOTH_PASSTHROUGH_PID;
|
||||
extern const Info<std::string> MAIN_BLUETOOTH_PASSTHROUGH_LINK_KEYS;
|
||||
|
||||
// Main.USBPassthrough
|
||||
|
||||
extern const Info<bool> MAIN_USB_PASSTHROUGH_DISGUISE_PLAYSTATION_AS_WII;
|
||||
extern const Info<std::string> MAIN_USB_PASSTHROUGH_DEVICES;
|
||||
std::set<USBUtils::DeviceInfo> GetUSBDeviceWhitelist();
|
||||
void SetUSBDeviceWhitelist(const std::set<USBUtils::DeviceInfo>& devices);
|
||||
|
||||
// Main.EmulatedUSBDevices
|
||||
|
||||
extern const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL;
|
||||
extern const Info<bool> MAIN_EMULATE_INFINITY_BASE;
|
||||
extern const Info<bool> MAIN_EMULATE_WII_SPEAK;
|
||||
extern const Info<std::string> MAIN_WII_SPEAK_MICROPHONE;
|
||||
extern const Info<bool> MAIN_WII_SPEAK_MUTED;
|
||||
extern const Info<s16> MAIN_WII_SPEAK_VOLUME_MODIFIER;
|
||||
|
||||
static constexpr std::size_t EMULATED_LOGITECH_MIC_COUNT = 4;
|
||||
|
||||
extern const std::array<Info<bool>, EMULATED_LOGITECH_MIC_COUNT> MAIN_EMULATE_LOGITECH_MIC;
|
||||
extern const std::array<Info<std::string>, EMULATED_LOGITECH_MIC_COUNT>
|
||||
MAIN_LOGITECH_MIC_MICROPHONE;
|
||||
extern const std::array<Info<bool>, EMULATED_LOGITECH_MIC_COUNT> MAIN_LOGITECH_MIC_MUTED;
|
||||
extern const std::array<Info<s16>, EMULATED_LOGITECH_MIC_COUNT> MAIN_LOGITECH_MIC_VOLUME_MODIFIER;
|
||||
|
||||
extern const Info<std::string> MAIN_TRIFORCE_IP_REDIRECTIONS;
|
||||
|
||||
// Main.WiimoteAudioRouting
|
||||
|
||||
static constexpr std::size_t WIIMOTE_SPEAKER_COUNT = 4;
|
||||
|
||||
extern const Info<bool> MAIN_WIIMOTE_AUDIO_ROUTING_ENABLED;
|
||||
extern const std::array<Info<bool>, WIIMOTE_SPEAKER_COUNT> MAIN_WIIMOTE_AUDIO_OUTPUT_ENABLED;
|
||||
extern const std::array<Info<std::string>, WIIMOTE_SPEAKER_COUNT> MAIN_WIIMOTE_AUDIO_OUTPUT_DEVICE;
|
||||
|
||||
// GameCube path utility functions
|
||||
|
||||
// Replaces NTSC-K with some other region, and doesn't replace non-NTSC-K regions
|
||||
DiscIO::Region ToGameCubeRegion(DiscIO::Region region);
|
||||
|
||||
// The region argument must be valid for GameCube (i.e. must not be NTSC-K)
|
||||
enum class RegionDirectoryStyle
|
||||
{
|
||||
Legacy,
|
||||
Modern,
|
||||
};
|
||||
const char* GetDirectoryForRegion(DiscIO::Region region,
|
||||
RegionDirectoryStyle style = RegionDirectoryStyle::Legacy);
|
||||
|
||||
std::string GetBootROMPath(const std::string& region_directory);
|
||||
// Builds the memory card according to the configuration with the given region and size. If the
|
||||
// given region is std::nullopt, the region in the configured path is used if there is one, or the
|
||||
// fallback region otherwise.
|
||||
std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region,
|
||||
u16 size_mb = 0x80);
|
||||
std::string GetMemcardPath(std::string configured_filename, ExpansionInterface::Slot slot,
|
||||
std::optional<DiscIO::Region> region, u16 size_mb = 0x80);
|
||||
bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot);
|
||||
std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region);
|
||||
std::string GetGCIFolderPath(std::string configured_folder, ExpansionInterface::Slot slot,
|
||||
std::optional<DiscIO::Region> region);
|
||||
bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot);
|
||||
bool AreCheatsEnabled();
|
||||
bool IsDebuggingEnabled();
|
||||
} // namespace Config
|
||||
extern const Info<std::string> MAIN_WII_STARLET_BOOTSTRAP_ELF;
|
||||
extern const Info<std::string> MAIN_WII_SD_CARD_IMAGE_PATH;
|
||||
extern const Info<std::string> MAIN_WII_SD_CARD_SYNC_FOLDER_PATH;
|
||||
extern const Info<std::string> MAIN_WFS_PATH;
|
||||
extern const Info<bool> MAIN_SHOW_LAG;
|
||||
extern const Info<bool> MAIN_SHOW_FRAME_COUNT;
|
||||
extern const Info<std::string> MAIN_WIRELESS_MAC;
|
||||
extern const Info<std::string> MAIN_GDB_SOCKET;
|
||||
extern const Info<int> MAIN_GDB_PORT;
|
||||
extern const Info<int> MAIN_ISO_PATH_COUNT;
|
||||
extern const Info<std::string> MAIN_SKYLANDERS_PATH;
|
||||
std::vector<std::string> GetIsoPaths();
|
||||
void SetIsoPaths(std::span<const std::string> paths);
|
||||
|
||||
// Main.GBA
|
||||
|
||||
#ifdef HAS_LIBMGBA
|
||||
extern const Info<std::string> MAIN_GBA_BIOS_PATH;
|
||||
extern const std::array<Info<std::string>, 5> MAIN_GBA_ROM_PATHS;
|
||||
extern const Info<std::string> MAIN_GBA_SAVES_PATH;
|
||||
extern const Info<bool> MAIN_GBA_SAVES_IN_ROM_PATH;
|
||||
|
||||
static constexpr std::size_t GBPLAYER_GBA_INDEX = 4;
|
||||
#endif
|
||||
|
||||
// Main.Network
|
||||
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_READ;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_WRITE;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_VERIFY_CERTIFICATES;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_ROOT_CA;
|
||||
extern const Info<bool> MAIN_NETWORK_SSL_DUMP_PEER_CERT;
|
||||
extern const Info<bool> MAIN_NETWORK_DUMP_BBA;
|
||||
extern const Info<bool> MAIN_NETWORK_DUMP_AS_PCAP;
|
||||
extern const Info<int> MAIN_NETWORK_TIMEOUT;
|
||||
|
||||
// Main.Interface
|
||||
|
||||
extern const Info<bool> MAIN_USE_HIGH_CONTRAST_TOOLTIPS;
|
||||
extern const Info<bool> MAIN_USE_PANIC_HANDLERS;
|
||||
extern const Info<bool> MAIN_ABORT_ON_PANIC_ALERT;
|
||||
extern const Info<bool> MAIN_OSD_MESSAGES;
|
||||
extern const Info<int> MAIN_OSD_FONT_SIZE;
|
||||
extern const Info<bool> MAIN_SKIP_NKIT_WARNING;
|
||||
extern const Info<bool> MAIN_CONFIRM_ON_STOP;
|
||||
|
||||
enum class ShowCursor
|
||||
{
|
||||
Never,
|
||||
Constantly,
|
||||
OnMovement,
|
||||
};
|
||||
extern const Info<ShowCursor> MAIN_SHOW_CURSOR;
|
||||
|
||||
extern const Info<bool> MAIN_LOCK_CURSOR;
|
||||
extern const Info<std::string> MAIN_INTERFACE_LANGUAGE;
|
||||
extern const Info<bool> MAIN_SHOW_ACTIVE_TITLE;
|
||||
extern const Info<bool> MAIN_USE_BUILT_IN_TITLE_DATABASE;
|
||||
extern const Info<std::string> MAIN_THEME_NAME;
|
||||
extern const Info<bool> MAIN_PAUSE_ON_FOCUS_LOST;
|
||||
extern const Info<bool> MAIN_ENABLE_DEBUGGING;
|
||||
|
||||
// Main.Analytics
|
||||
|
||||
extern const Info<std::string> MAIN_ANALYTICS_ID;
|
||||
extern const Info<bool> MAIN_ANALYTICS_ENABLED;
|
||||
extern const Info<bool> MAIN_ANALYTICS_PERMISSION_ASKED;
|
||||
|
||||
// Main.GameList
|
||||
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_DRIVES;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WAD;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_ELF_DOL;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WII;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_GC;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_TRI;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_JPN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_PAL;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_USA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_AUSTRALIA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_FRANCE;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_GERMANY;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_ITALY;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_KOREA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_NETHERLANDS;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_RUSSIA;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_SPAIN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_TAIWAN;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_WORLD;
|
||||
extern const Info<bool> MAIN_GAMELIST_LIST_UNKNOWN;
|
||||
extern const Info<int> MAIN_GAMELIST_LIST_SORT;
|
||||
extern const Info<int> MAIN_GAMELIST_LIST_SORT_SECONDARY;
|
||||
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_PLATFORM;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_DESCRIPTION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_BANNER;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TITLE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_MAKER;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_NAME;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_PATH;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_GAME_ID;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_REGION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_SIZE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_FORMAT;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_BLOCK_SIZE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_COMPRESSION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TIME_PLAYED;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TAGS;
|
||||
|
||||
// Main.FifoPlayer
|
||||
|
||||
extern const Info<bool> MAIN_FIFOPLAYER_LOOP_REPLAY;
|
||||
extern const Info<bool> MAIN_FIFOPLAYER_EARLY_MEMORY_UPDATES;
|
||||
|
||||
// Main.AutoUpdate
|
||||
|
||||
extern const Info<std::string> MAIN_AUTOUPDATE_UPDATE_TRACK;
|
||||
extern const Info<std::string> MAIN_AUTOUPDATE_HASH_OVERRIDE;
|
||||
|
||||
// Main.Movie
|
||||
|
||||
extern const Info<bool> MAIN_MOVIE_PAUSE_MOVIE;
|
||||
extern const Info<std::string> MAIN_MOVIE_MOVIE_AUTHOR;
|
||||
extern const Info<bool> MAIN_MOVIE_DUMP_FRAMES;
|
||||
extern const Info<bool> MAIN_MOVIE_DUMP_FRAMES_SILENT;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_INPUT_DISPLAY;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_RTC;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_RERECORD;
|
||||
extern const Info<bool> MAIN_MOVIE_SHOW_OSD;
|
||||
|
||||
// Main.Input
|
||||
|
||||
extern const Info<bool> MAIN_INPUT_BACKGROUND_INPUT;
|
||||
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_ENHANCED_REPORTS;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_WGI;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_DIRECTINPUT;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS;
|
||||
extern const Config::Info<std::string> MAIN_SDL_HINT_JOYSTICK_HIDAPI_VERTICAL_JOY_CONS;
|
||||
|
||||
// Main.Debug
|
||||
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LXZ_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LWZ_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_LBZX_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_FLOATING_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_LOAD_STORE_PAIRED_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_FLOATING_POINT_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_INTEGER_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_PAIRED_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_SYSTEM_REGISTERS_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_BRANCH_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_REGISTER_CACHE_OFF;
|
||||
extern const Info<bool> MAIN_DEBUG_JIT_ENABLE_PROFILING;
|
||||
|
||||
// Main.BluetoothPassthrough
|
||||
|
||||
extern const Info<bool> MAIN_BLUETOOTH_PASSTHROUGH_ENABLED;
|
||||
extern const Info<int> MAIN_BLUETOOTH_PASSTHROUGH_VID;
|
||||
extern const Info<int> MAIN_BLUETOOTH_PASSTHROUGH_PID;
|
||||
extern const Info<std::string> MAIN_BLUETOOTH_PASSTHROUGH_LINK_KEYS;
|
||||
|
||||
// Main.USBPassthrough
|
||||
|
||||
extern const Info<bool> MAIN_USB_PASSTHROUGH_DISGUISE_PLAYSTATION_AS_WII;
|
||||
extern const Info<std::string> MAIN_USB_PASSTHROUGH_DEVICES;
|
||||
std::set<USBUtils::DeviceInfo> GetUSBDeviceWhitelist();
|
||||
void SetUSBDeviceWhitelist(const std::set<USBUtils::DeviceInfo>& devices);
|
||||
|
||||
// Main.EmulatedUSBDevices
|
||||
|
||||
extern const Info<bool> MAIN_EMULATE_SKYLANDER_PORTAL;
|
||||
extern const Info<bool> MAIN_EMULATE_INFINITY_BASE;
|
||||
extern const Info<bool> MAIN_EMULATE_WII_SPEAK;
|
||||
extern const Info<std::string> MAIN_WII_SPEAK_MICROPHONE;
|
||||
extern const Info<bool> MAIN_WII_SPEAK_MUTED;
|
||||
extern const Info<s16> MAIN_WII_SPEAK_VOLUME_MODIFIER;
|
||||
|
||||
static constexpr std::size_t EMULATED_LOGITECH_MIC_COUNT = 4;
|
||||
|
||||
extern const std::array<Info<bool>, EMULATED_LOGITECH_MIC_COUNT> MAIN_EMULATE_LOGITECH_MIC;
|
||||
extern const std::array<Info<std::string>, EMULATED_LOGITECH_MIC_COUNT>
|
||||
MAIN_LOGITECH_MIC_MICROPHONE;
|
||||
extern const std::array<Info<bool>, EMULATED_LOGITECH_MIC_COUNT> MAIN_LOGITECH_MIC_MUTED;
|
||||
extern const std::array<Info<s16>, EMULATED_LOGITECH_MIC_COUNT> MAIN_LOGITECH_MIC_VOLUME_MODIFIER;
|
||||
|
||||
extern const Info<std::string> MAIN_TRIFORCE_IP_REDIRECTIONS;
|
||||
|
||||
// Main.WiimoteAudioRouting
|
||||
|
||||
static constexpr std::size_t WIIMOTE_SPEAKER_COUNT = 4;
|
||||
|
||||
extern const Info<bool> MAIN_WIIMOTE_AUDIO_ROUTING_ENABLED;
|
||||
extern const std::array<Info<bool>, WIIMOTE_SPEAKER_COUNT> MAIN_WIIMOTE_AUDIO_OUTPUT_ENABLED;
|
||||
extern const std::array<Info<std::string>, WIIMOTE_SPEAKER_COUNT> MAIN_WIIMOTE_AUDIO_OUTPUT_DEVICE;
|
||||
|
||||
// GameCube path utility functions
|
||||
|
||||
// Replaces NTSC-K with some other region, and doesn't replace non-NTSC-K regions
|
||||
DiscIO::Region ToGameCubeRegion(DiscIO::Region region);
|
||||
|
||||
// The region argument must be valid for GameCube (i.e. must not be NTSC-K)
|
||||
enum class RegionDirectoryStyle
|
||||
{
|
||||
Legacy,
|
||||
Modern,
|
||||
};
|
||||
const char* GetDirectoryForRegion(DiscIO::Region region,
|
||||
RegionDirectoryStyle style = RegionDirectoryStyle::Legacy);
|
||||
|
||||
std::string GetBootROMPath(const std::string& region_directory);
|
||||
// Builds the memory card according to the configuration with the given region and size. If the
|
||||
// given region is std::nullopt, the region in the configured path is used if there is one, or the
|
||||
// fallback region otherwise.
|
||||
std::string GetMemcardPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region,
|
||||
u16 size_mb = 0x80);
|
||||
std::string GetMemcardPath(std::string configured_filename, ExpansionInterface::Slot slot,
|
||||
std::optional<DiscIO::Region> region, u16 size_mb = 0x80);
|
||||
bool IsDefaultMemcardPathConfigured(ExpansionInterface::Slot slot);
|
||||
std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional<DiscIO::Region> region);
|
||||
std::string GetGCIFolderPath(std::string configured_folder, ExpansionInterface::Slot slot,
|
||||
std::optional<DiscIO::Region> region);
|
||||
bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot);
|
||||
bool AreCheatsEnabled();
|
||||
bool IsDebuggingEnabled();
|
||||
} // namespace Config
|
||||
+656
-652
File diff suppressed because it is too large.
Load diff
+159
-159
@@ -1,159 +1,159 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HW/HW.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/AddressSpace.h"
|
||||
#include "Core/HW/AudioInterface.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/EXI/EXI.h"
|
||||
#include "Core/HW/GPFifo.h"
|
||||
#include "Core/HW/HSP/HSP.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/MemoryInterface.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/HW/VideoInterface.h"
|
||||
#include "Core/HW/WII_IPC.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/IOS/Starlet/Starlet.h"
|
||||
#include "Core/State.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace HW
|
||||
{
|
||||
void Init(Core::System& system, const Sram* override_sram)
|
||||
{
|
||||
system.GetCoreTiming().Init();
|
||||
system.GetSystemTimers().PreInit();
|
||||
|
||||
State::Init(system);
|
||||
|
||||
// Init the whole Hardware
|
||||
system.GetAudioInterface().Init();
|
||||
system.GetVideoInterface().Init();
|
||||
system.GetSerialInterface().Init();
|
||||
system.GetProcessorInterface().Init();
|
||||
system.GetExpansionInterface().Init(override_sram); // Needs to be initialized before Memory
|
||||
system.GetHSP().Init();
|
||||
system.GetMemory().Init(); // Needs to be initialized before AddressSpace
|
||||
AddressSpace::Init();
|
||||
system.GetMemoryInterface().Init();
|
||||
system.GetDSP().Init(Config::Get(Config::MAIN_DSP_HLE));
|
||||
system.GetDVDInterface().Init();
|
||||
system.GetGPFifo().Init();
|
||||
system.GetCPU().Init(Config::Get(Config::MAIN_CPU_CORE));
|
||||
system.GetSystemTimers().Init();
|
||||
|
||||
if (system.IsWii())
|
||||
{
|
||||
system.GetWiiIPC().Init();
|
||||
if (Config::Get(Config::MAIN_WII_IOS_LLE))
|
||||
{
|
||||
auto starlet = std::make_unique<IOS::LLE::Starlet>(system);
|
||||
std::string error;
|
||||
if (starlet->Init(Config::Get(Config::MAIN_WII_LLE_DUMP_PATH), &error))
|
||||
{
|
||||
system.SetStarlet(std::move(starlet));
|
||||
system.GetWiiIPC().HoldBroadwayForStarletBoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlertFmtT("Could not start Wii IOS LLE: {0}", error);
|
||||
Core::SetState(system, Core::State::Stopping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IOS::HLE::Init(system); // Depends on Memory
|
||||
}
|
||||
}
|
||||
|
||||
system.GetMemory().InitMMIO(system);
|
||||
}
|
||||
|
||||
void Shutdown(Core::System& system)
|
||||
{
|
||||
// IOS should always be shut down regardless of IsWii because it can be running in GC mode (MIOS).
|
||||
if (system.GetStarlet())
|
||||
{
|
||||
system.GetStarlet()->Shutdown();
|
||||
system.SetStarlet(nullptr);
|
||||
}
|
||||
if (system.GetIOS())
|
||||
IOS::HLE::Shutdown(system); // Depends on Memory
|
||||
system.GetWiiIPC().Shutdown();
|
||||
|
||||
system.GetSystemTimers().Shutdown();
|
||||
system.GetCPU().Shutdown();
|
||||
system.GetDVDInterface().Shutdown();
|
||||
system.GetDSP().Shutdown();
|
||||
system.GetMemoryInterface().Shutdown();
|
||||
AddressSpace::Shutdown();
|
||||
system.GetMemory().Shutdown();
|
||||
system.GetHSP().Shutdown();
|
||||
system.GetExpansionInterface().Shutdown();
|
||||
system.GetSerialInterface().Shutdown();
|
||||
system.GetAudioInterface().Shutdown();
|
||||
|
||||
State::Shutdown();
|
||||
system.GetCoreTiming().Shutdown();
|
||||
}
|
||||
|
||||
void DoState(Core::System& system, PointerWrap& p)
|
||||
{
|
||||
system.GetMemory().DoState(p);
|
||||
p.DoMarker("Memory");
|
||||
system.GetMemoryInterface().DoState(p);
|
||||
p.DoMarker("MemoryInterface");
|
||||
system.GetVideoInterface().DoState(p);
|
||||
p.DoMarker("VideoInterface");
|
||||
system.GetSerialInterface().DoState(p);
|
||||
p.DoMarker("SerialInterface");
|
||||
system.GetProcessorInterface().DoState(p);
|
||||
p.DoMarker("ProcessorInterface");
|
||||
system.GetDSP().DoState(p);
|
||||
p.DoMarker("DSP");
|
||||
system.GetDVDInterface().DoState(p);
|
||||
p.DoMarker("DVDInterface");
|
||||
system.GetGPFifo().DoState(p);
|
||||
p.DoMarker("GPFifo");
|
||||
system.GetExpansionInterface().DoState(p);
|
||||
p.DoMarker("ExpansionInterface");
|
||||
system.GetAudioInterface().DoState(p);
|
||||
p.DoMarker("AudioInterface");
|
||||
system.GetHSP().DoState(p);
|
||||
p.DoMarker("HSP");
|
||||
|
||||
if (system.IsWii())
|
||||
{
|
||||
system.GetWiiIPC().DoState(p);
|
||||
p.DoMarker("IOS");
|
||||
if (system.GetStarlet())
|
||||
{
|
||||
system.GetStarlet()->DoState(p);
|
||||
p.DoMarker("IOS::LLE");
|
||||
}
|
||||
else if (system.GetIOS())
|
||||
{
|
||||
system.GetIOS()->DoState(p);
|
||||
p.DoMarker("IOS::HLE");
|
||||
}
|
||||
}
|
||||
|
||||
p.DoMarker("WIIHW");
|
||||
}
|
||||
} // namespace HW
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HW/HW.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/AddressSpace.h"
|
||||
#include "Core/HW/AudioInterface.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/DVD/DVDInterface.h"
|
||||
#include "Core/HW/EXI/EXI.h"
|
||||
#include "Core/HW/GPFifo.h"
|
||||
#include "Core/HW/HSP/HSP.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/MemoryInterface.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "Core/HW/VideoInterface.h"
|
||||
#include "Core/HW/WII_IPC.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/IOS/Starlet/Starlet.h"
|
||||
#include "Core/State.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
namespace HW
|
||||
{
|
||||
void Init(Core::System& system, const Sram* override_sram)
|
||||
{
|
||||
system.GetCoreTiming().Init();
|
||||
system.GetSystemTimers().PreInit();
|
||||
|
||||
State::Init(system);
|
||||
|
||||
// Init the whole Hardware
|
||||
system.GetAudioInterface().Init();
|
||||
system.GetVideoInterface().Init();
|
||||
system.GetSerialInterface().Init();
|
||||
system.GetProcessorInterface().Init();
|
||||
system.GetExpansionInterface().Init(override_sram); // Needs to be initialized before Memory
|
||||
system.GetHSP().Init();
|
||||
system.GetMemory().Init(); // Needs to be initialized before AddressSpace
|
||||
AddressSpace::Init();
|
||||
system.GetMemoryInterface().Init();
|
||||
system.GetDSP().Init(Config::Get(Config::MAIN_DSP_HLE));
|
||||
system.GetDVDInterface().Init();
|
||||
system.GetGPFifo().Init();
|
||||
system.GetCPU().Init(Config::Get(Config::MAIN_CPU_CORE));
|
||||
system.GetSystemTimers().Init();
|
||||
|
||||
if (system.IsWii())
|
||||
{
|
||||
system.GetWiiIPC().Init();
|
||||
if (Config::Get(Config::MAIN_WII_IOS_LLE))
|
||||
{
|
||||
auto starlet = IOS::LLE::Starlet::Create(system);
|
||||
std::string error;
|
||||
if (starlet->Init(Config::Get(Config::MAIN_WII_LLE_DUMP_PATH), &error))
|
||||
{
|
||||
system.SetStarlet(std::move(starlet));
|
||||
system.GetWiiIPC().HoldBroadwayForStarletBoot();
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlertFmtT("Could not start Wii IOS LLE: {0}", error);
|
||||
Core::SetState(system, Core::State::Stopping);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IOS::HLE::Init(system); // Depends on Memory
|
||||
}
|
||||
}
|
||||
|
||||
system.GetMemory().InitMMIO(system);
|
||||
}
|
||||
|
||||
void Shutdown(Core::System& system)
|
||||
{
|
||||
// IOS should always be shut down regardless of IsWii because it can be running in GC mode (MIOS).
|
||||
if (system.GetStarlet())
|
||||
{
|
||||
system.GetStarlet()->Shutdown();
|
||||
system.SetStarlet(nullptr);
|
||||
}
|
||||
if (system.GetIOS())
|
||||
IOS::HLE::Shutdown(system); // Depends on Memory
|
||||
system.GetWiiIPC().Shutdown();
|
||||
|
||||
system.GetSystemTimers().Shutdown();
|
||||
system.GetCPU().Shutdown();
|
||||
system.GetDVDInterface().Shutdown();
|
||||
system.GetDSP().Shutdown();
|
||||
system.GetMemoryInterface().Shutdown();
|
||||
AddressSpace::Shutdown();
|
||||
system.GetMemory().Shutdown();
|
||||
system.GetHSP().Shutdown();
|
||||
system.GetExpansionInterface().Shutdown();
|
||||
system.GetSerialInterface().Shutdown();
|
||||
system.GetAudioInterface().Shutdown();
|
||||
|
||||
State::Shutdown();
|
||||
system.GetCoreTiming().Shutdown();
|
||||
}
|
||||
|
||||
void DoState(Core::System& system, PointerWrap& p)
|
||||
{
|
||||
system.GetMemory().DoState(p);
|
||||
p.DoMarker("Memory");
|
||||
system.GetMemoryInterface().DoState(p);
|
||||
p.DoMarker("MemoryInterface");
|
||||
system.GetVideoInterface().DoState(p);
|
||||
p.DoMarker("VideoInterface");
|
||||
system.GetSerialInterface().DoState(p);
|
||||
p.DoMarker("SerialInterface");
|
||||
system.GetProcessorInterface().DoState(p);
|
||||
p.DoMarker("ProcessorInterface");
|
||||
system.GetDSP().DoState(p);
|
||||
p.DoMarker("DSP");
|
||||
system.GetDVDInterface().DoState(p);
|
||||
p.DoMarker("DVDInterface");
|
||||
system.GetGPFifo().DoState(p);
|
||||
p.DoMarker("GPFifo");
|
||||
system.GetExpansionInterface().DoState(p);
|
||||
p.DoMarker("ExpansionInterface");
|
||||
system.GetAudioInterface().DoState(p);
|
||||
p.DoMarker("AudioInterface");
|
||||
system.GetHSP().DoState(p);
|
||||
p.DoMarker("HSP");
|
||||
|
||||
if (system.IsWii())
|
||||
{
|
||||
system.GetWiiIPC().DoState(p);
|
||||
p.DoMarker("IOS");
|
||||
if (system.GetStarlet())
|
||||
{
|
||||
system.GetStarlet()->DoState(p);
|
||||
p.DoMarker("IOS::LLE");
|
||||
}
|
||||
else if (system.GetIOS())
|
||||
{
|
||||
system.GetIOS()->DoState(p);
|
||||
p.DoMarker("IOS::HLE");
|
||||
}
|
||||
}
|
||||
|
||||
p.DoMarker("WIIHW");
|
||||
}
|
||||
} // namespace HW
|
||||
+2660
-2627
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,222 @@
|
||||
// Copyright 2026 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/IOS/Starlet/BootstrapELF.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include "Core/IOS/Starlet/ARMCore.h"
|
||||
|
||||
namespace IOS::LLE
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr u32 TEXT_BASE = 0xffff0000;
|
||||
constexpr u64 TEXT_END = 0x1'0000'0000ULL;
|
||||
constexpr u32 DATA_BASE = 0xfffe0000;
|
||||
constexpr u32 DATA_END = 0xfffe4000;
|
||||
// Revolution IOS Phase 06H: MEM2, for the optional disposable-image text segment.
|
||||
constexpr u32 MEM2_BASE = 0x10000000;
|
||||
constexpr u64 MEM2_END = 0x14000000ULL;
|
||||
constexpr u32 TRACE_SIZE = 1032;
|
||||
constexpr u32 ELF_HEADER_SIZE = 52;
|
||||
constexpr u32 PROGRAM_HEADER_SIZE = 32;
|
||||
constexpr u32 SECTION_HEADER_SIZE = 40;
|
||||
constexpr u32 SYMBOL_SIZE = 16;
|
||||
|
||||
struct Segment
|
||||
{
|
||||
u32 offset = 0;
|
||||
u32 address = 0;
|
||||
u32 file_size = 0;
|
||||
u32 memory_size = 0;
|
||||
};
|
||||
|
||||
bool Fits(std::span<const u8> image, u64 offset, u64 size)
|
||||
{
|
||||
return offset <= image.size() && size <= image.size() - offset;
|
||||
}
|
||||
|
||||
u16 Read16(std::span<const u8> image, size_t offset)
|
||||
{
|
||||
return static_cast<u16>((static_cast<u16>(image[offset]) << 8) | image[offset + 1]);
|
||||
}
|
||||
|
||||
u32 Read32(std::span<const u8> image, size_t offset)
|
||||
{
|
||||
return (static_cast<u32>(image[offset]) << 24) | (static_cast<u32>(image[offset + 1]) << 16) |
|
||||
(static_cast<u32>(image[offset + 2]) << 8) | image[offset + 3];
|
||||
}
|
||||
|
||||
bool Fail(std::string* error, std::string_view reason)
|
||||
{
|
||||
if (error)
|
||||
*error = reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<std::string_view> SymbolName(std::span<const u8> image, u32 strings_offset,
|
||||
u32 strings_size, u32 name_offset)
|
||||
{
|
||||
if (name_offset >= strings_size)
|
||||
return std::nullopt;
|
||||
const size_t start = static_cast<size_t>(strings_offset) + name_offset;
|
||||
const auto first = image.begin() + start;
|
||||
const auto last = image.begin() + strings_offset + strings_size;
|
||||
const auto end = std::find(first, last, 0);
|
||||
if (end == last)
|
||||
return std::nullopt;
|
||||
return std::string_view(reinterpret_cast<const char*>(&*first), static_cast<size_t>(end - first));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool LoadBootstrapELF(std::span<const u8> image, ARMBus& bus, BootstrapELFInfo* info,
|
||||
std::string* error, bool allow_mem2_text)
|
||||
{
|
||||
if (!info)
|
||||
return Fail(error, "missing bootstrap ELF result");
|
||||
if (!Fits(image, 0, ELF_HEADER_SIZE) || image[0] != 0x7f || image[1] != 'E' || image[2] != 'L' ||
|
||||
image[3] != 'F' || image[4] != 1 || image[5] != 2 || image[6] != 1 ||
|
||||
Read16(image, 16) != 2 || Read16(image, 18) != 40 || Read32(image, 20) != 1 ||
|
||||
Read16(image, 40) != ELF_HEADER_SIZE)
|
||||
{
|
||||
return Fail(error, "expected ELF32 big-endian ARM executable");
|
||||
}
|
||||
|
||||
const u32 entry = Read32(image, 24);
|
||||
const u32 program_offset = Read32(image, 28);
|
||||
const u32 section_offset = Read32(image, 32);
|
||||
const u16 program_size = Read16(image, 42);
|
||||
const u16 program_count = Read16(image, 44);
|
||||
const u16 section_size = Read16(image, 46);
|
||||
const u16 section_count = Read16(image, 48);
|
||||
const bool program_count_valid = program_count == 2 || (allow_mem2_text && program_count == 3);
|
||||
if (entry != TEXT_BASE || program_size != PROGRAM_HEADER_SIZE || !program_count_valid ||
|
||||
section_size != SECTION_HEADER_SIZE || section_count == 0 ||
|
||||
!Fits(image, program_offset, static_cast<u64>(program_size) * program_count) ||
|
||||
!Fits(image, section_offset, static_cast<u64>(section_size) * section_count))
|
||||
{
|
||||
return Fail(error, "bootstrap ELF has an unsupported entry or header table");
|
||||
}
|
||||
|
||||
std::array<Segment, 3> storage;
|
||||
const std::span<Segment> segments(storage.data(), program_count);
|
||||
u32 text_count = 0;
|
||||
u32 data_count = 0;
|
||||
u32 mem2_count = 0;
|
||||
for (u32 index = 0; index < segments.size(); ++index)
|
||||
{
|
||||
const size_t offset = program_offset + index * PROGRAM_HEADER_SIZE;
|
||||
const u32 file_offset = Read32(image, offset + 4);
|
||||
const u32 address = Read32(image, offset + 8);
|
||||
const u32 physical_address = Read32(image, offset + 12);
|
||||
const u32 file_size = Read32(image, offset + 16);
|
||||
const u32 memory_size = Read32(image, offset + 20);
|
||||
const u32 flags = Read32(image, offset + 24);
|
||||
const bool text =
|
||||
address == TEXT_BASE && flags == 5 && static_cast<u64>(address) + memory_size <= TEXT_END;
|
||||
const bool data =
|
||||
address == DATA_BASE && flags == 6 && static_cast<u64>(address) + memory_size <= DATA_END;
|
||||
const bool mem2 = allow_mem2_text && flags == 5 && address >= MEM2_BASE &&
|
||||
static_cast<u64>(address) + memory_size <= MEM2_END;
|
||||
if (Read32(image, offset) != 1 || address != physical_address || file_size == 0 ||
|
||||
memory_size < file_size || !Fits(image, file_offset, file_size) ||
|
||||
(!text && !data && !mem2))
|
||||
{
|
||||
return Fail(error, "bootstrap ELF has an invalid SRAM load segment");
|
||||
}
|
||||
text_count += text;
|
||||
data_count += data;
|
||||
mem2_count += mem2;
|
||||
segments[index] = {file_offset, address, file_size, memory_size};
|
||||
}
|
||||
if (text_count != 1 || data_count != 1 || mem2_count != program_count - 2u)
|
||||
return Fail(error, "bootstrap ELF must have one text and one data segment");
|
||||
|
||||
BootstrapELFInfo parsed{entry};
|
||||
bool found_trace = false;
|
||||
bool found_fault_code = false;
|
||||
bool found_fault_lr = false;
|
||||
bool found_fault_spsr = false;
|
||||
for (u32 index = 0; index < section_count; ++index)
|
||||
{
|
||||
const size_t offset = section_offset + index * SECTION_HEADER_SIZE;
|
||||
if (Read32(image, offset + 4) != 2)
|
||||
continue;
|
||||
const u32 symbols_offset = Read32(image, offset + 16);
|
||||
const u32 symbols_size = Read32(image, offset + 20);
|
||||
const u32 strings_index = Read32(image, offset + 24);
|
||||
const u32 entry_size = Read32(image, offset + 36);
|
||||
if (entry_size != SYMBOL_SIZE || symbols_size % SYMBOL_SIZE != 0 ||
|
||||
!Fits(image, symbols_offset, symbols_size) || strings_index >= section_count)
|
||||
{
|
||||
return Fail(error, "bootstrap ELF has an invalid symbol table");
|
||||
}
|
||||
const size_t strings_header = section_offset + strings_index * SECTION_HEADER_SIZE;
|
||||
const u32 strings_offset = Read32(image, strings_header + 16);
|
||||
const u32 strings_size = Read32(image, strings_header + 20);
|
||||
if (Read32(image, strings_header + 4) != 3 || !Fits(image, strings_offset, strings_size))
|
||||
{
|
||||
return Fail(error, "bootstrap ELF has an invalid symbol string table");
|
||||
}
|
||||
for (u32 symbol = 0; symbol < symbols_size / SYMBOL_SIZE; ++symbol)
|
||||
{
|
||||
const size_t symbol_offset = symbols_offset + symbol * SYMBOL_SIZE;
|
||||
const auto name =
|
||||
SymbolName(image, strings_offset, strings_size, Read32(image, symbol_offset));
|
||||
if (!name)
|
||||
return Fail(error, "bootstrap ELF has an invalid symbol name");
|
||||
const u32 address = Read32(image, symbol_offset + 4);
|
||||
if (*name == "REV_TRACE")
|
||||
{
|
||||
if (Read32(image, symbol_offset + 8) != TRACE_SIZE)
|
||||
return Fail(error, "bootstrap ELF trace layout does not match the monitor");
|
||||
parsed.trace = address;
|
||||
found_trace = true;
|
||||
}
|
||||
else if (*name == "__fault_code")
|
||||
{
|
||||
parsed.fault_code = address;
|
||||
found_fault_code = true;
|
||||
}
|
||||
else if (*name == "__fault_lr")
|
||||
{
|
||||
parsed.fault_lr = address;
|
||||
found_fault_lr = true;
|
||||
}
|
||||
else if (*name == "__fault_spsr")
|
||||
{
|
||||
parsed.fault_spsr = address;
|
||||
found_fault_spsr = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto data_segment =
|
||||
std::find_if(segments.begin(), segments.end(),
|
||||
[](const Segment& segment) { return segment.address == DATA_BASE; });
|
||||
const auto in_data = [data_segment](u32 address, u32 size) {
|
||||
return address >= data_segment->address &&
|
||||
static_cast<u64>(address) + size <=
|
||||
static_cast<u64>(data_segment->address) + data_segment->memory_size;
|
||||
};
|
||||
if (!found_trace || !found_fault_code || !found_fault_lr || !found_fault_spsr ||
|
||||
!in_data(parsed.trace, TRACE_SIZE) || !in_data(parsed.fault_code, 4) ||
|
||||
!in_data(parsed.fault_lr, 4) || !in_data(parsed.fault_spsr, 4))
|
||||
{
|
||||
return Fail(error, "bootstrap ELF is missing the trace or fault symbols");
|
||||
}
|
||||
|
||||
for (const Segment& segment : segments)
|
||||
{
|
||||
for (u32 index = 0; index < segment.file_size; ++index)
|
||||
bus.Write8(segment.address + index, image[segment.offset + index]);
|
||||
for (u32 index = segment.file_size; index < segment.memory_size; ++index)
|
||||
bus.Write8(segment.address + index, 0);
|
||||
}
|
||||
*info = parsed;
|
||||
return true;
|
||||
}
|
||||
} // namespace IOS::LLE
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright 2026 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
namespace IOS::LLE
|
||||
{
|
||||
class ARMBus;
|
||||
|
||||
struct BootstrapELFInfo
|
||||
{
|
||||
u32 entry = 0;
|
||||
u32 trace = 0;
|
||||
u32 fault_code = 0;
|
||||
u32 fault_lr = 0;
|
||||
u32 fault_spsr = 0;
|
||||
};
|
||||
|
||||
// Load the Phase 01 ELF into a bus already configured with the high SRAM mapping.
|
||||
// All file and address validation completes before the first bus write.
|
||||
// Revolution IOS Phase 06H: `allow_mem2_text` (set only with the emulator-only disposable
|
||||
// writable NAND) additionally accepts one read/execute segment wholly inside MEM2. The SRAM
|
||||
// text and data segments stay mandatory; without the flag the rules are unchanged.
|
||||
bool LoadBootstrapELF(std::span<const u8> image, ARMBus& bus, BootstrapELFInfo* info,
|
||||
std::string* error, bool allow_mem2_text = false);
|
||||
} // namespace IOS::LLE
|
||||
@@ -4,18 +4,24 @@
|
||||
#include "Core/IOS/Starlet/Starlet.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/PerformanceTrace.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/CoreTiming.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/HW/WII_IPC.h"
|
||||
#include "Core/IOS/Starlet/ARMCore.h"
|
||||
#include "Core/IOS/Starlet/BootstrapELF.h"
|
||||
#include "Core/IOS/Starlet/StarletMemory.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
@@ -23,6 +29,11 @@
|
||||
|
||||
namespace IOS::LLE
|
||||
{
|
||||
std::unique_ptr<Starlet> Starlet::Create(Core::System& system)
|
||||
{
|
||||
return std::make_unique<Starlet>(system);
|
||||
}
|
||||
|
||||
Starlet::Starlet(Core::System& system) : m_system(system)
|
||||
{
|
||||
}
|
||||
@@ -37,11 +48,87 @@ bool Starlet::Init(const std::string& dump_directory, std::string* error)
|
||||
// Allocate the concrete bus here; its device-state members are part of the
|
||||
// allocation size and must stay in lockstep with StarletMemory's definition.
|
||||
m_memory = std::make_unique<StarletMemory>(m_system);
|
||||
if (!m_memory->Init(dump_directory, error))
|
||||
const std::string bootstrap_path = Config::Get(Config::MAIN_WII_STARLET_BOOTSTRAP_ELF);
|
||||
if (bootstrap_path.empty() && !m_memory->Init(dump_directory, error))
|
||||
{
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
if (!bootstrap_path.empty())
|
||||
{
|
||||
File::IOFile file(bootstrap_path, "rb");
|
||||
const u64 size = file ? file.GetSize() : 0;
|
||||
if (size == 0 || size > 16 * 1024 * 1024)
|
||||
{
|
||||
if (error)
|
||||
*error = "WiiStarletBootstrapELF must name a readable ELF of at most 16 MiB";
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
std::vector<u8> image(static_cast<size_t>(size));
|
||||
if (!file.ReadBytes(image.data(), image.size()))
|
||||
{
|
||||
if (error)
|
||||
*error = "could not read WiiStarletBootstrapELF";
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
m_memory->PrepareBootstrap();
|
||||
// Revolution IOS Phase 06H, emulator only: a disposable writable NAND, and with it the
|
||||
// MEM2 text segment of the disposable-image kernel. Nothing else accepts either.
|
||||
const char* disposable_source = std::getenv("REV_BOOTSTRAP_NAND_DISPOSABLE");
|
||||
const bool disposable = disposable_source && *disposable_source;
|
||||
BootstrapELFInfo info;
|
||||
if (!LoadBootstrapELF(image, *m_memory, &info, error, disposable))
|
||||
{
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
m_bootstrap = info;
|
||||
INFO_LOG_FMT(IOS, "Starlet bootstrap ELF loaded: {} entry={:#010x} trace={:#010x}",
|
||||
bootstrap_path, info.entry, info.trace);
|
||||
if (disposable)
|
||||
{
|
||||
const char* read_only_path = std::getenv("REV_BOOTSTRAP_NAND");
|
||||
const char* copy_path = std::getenv("REV_BOOTSTRAP_NAND_COPY");
|
||||
if ((read_only_path && *read_only_path) || !copy_path || !*copy_path)
|
||||
{
|
||||
if (error)
|
||||
*error = "REV_BOOTSTRAP_NAND_DISPOSABLE needs REV_BOOTSTRAP_NAND_COPY and excludes "
|
||||
"REV_BOOTSTRAP_NAND";
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
if (!m_memory->AttachDisposableNAND(disposable_source, copy_path, error))
|
||||
{
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
WARN_LOG_FMT(IOS, "Starlet bootstrap NAND DISPOSABLE: source {} (read-only), copy {}",
|
||||
disposable_source, copy_path);
|
||||
}
|
||||
// Revolution IOS Phase 04B: optionally expose a raw NAND image, strictly read-only, so a
|
||||
// bootstrap ELF can validate its NAND driver. Program and erase always fail in this mode.
|
||||
if (const char* nand_path = std::getenv("REV_BOOTSTRAP_NAND"); nand_path && *nand_path)
|
||||
{
|
||||
if (!m_memory->AttachReadOnlyNAND(nand_path, error))
|
||||
{
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG_FMT(IOS, "Starlet bootstrap NAND attached read-only: {}", nand_path);
|
||||
}
|
||||
// Revolution IOS Phase 04C: optional keys.bin so OTP reads match the attached dump.
|
||||
if (const char* keys_path = std::getenv("REV_BOOTSTRAP_KEYS"); keys_path && *keys_path)
|
||||
{
|
||||
if (!m_memory->AttachKeys(keys_path, error))
|
||||
{
|
||||
m_memory.reset();
|
||||
return false;
|
||||
}
|
||||
INFO_LOG_FMT(IOS, "Starlet bootstrap keys attached");
|
||||
}
|
||||
}
|
||||
// ARMCore owns generation-tagged software TLB and instruction caches, so
|
||||
// construct it only after the complete physical bus exists.
|
||||
m_core = std::make_unique<ARMCore>(*m_memory,
|
||||
@@ -51,7 +138,9 @@ bool Starlet::Init(const std::string& dump_directory, std::string* error)
|
||||
#else
|
||||
m_core->SetJitEnabled(false);
|
||||
#endif
|
||||
m_core->Reset(StarletMemory::BOOT_ROM_BASE);
|
||||
m_core->Reset(m_bootstrap ? m_bootstrap->entry : StarletMemory::BOOT_ROM_BASE);
|
||||
if (m_bootstrap)
|
||||
m_core->SetBigEndian(true);
|
||||
m_next_jit_diagnostic_instruction = 25'000'000;
|
||||
m_next_realtime_diagnostic_ms = Common::Timer::NowMs() + 1000;
|
||||
m_realtime_diagnostic_slice_count = 0;
|
||||
@@ -101,6 +190,7 @@ void Starlet::Shutdown()
|
||||
m_run_event = nullptr;
|
||||
m_core.reset();
|
||||
m_memory.reset();
|
||||
m_bootstrap.reset();
|
||||
}
|
||||
|
||||
void Starlet::DoState(PointerWrap& p)
|
||||
@@ -110,6 +200,14 @@ void Starlet::DoState(PointerWrap& p)
|
||||
return;
|
||||
m_memory->DoState(p);
|
||||
m_core->DoState(p);
|
||||
if (p.IsReadMode())
|
||||
{
|
||||
m_bootstrap_trace_length = 0;
|
||||
m_last_probe_status = 0;
|
||||
m_bootstrap_line_length = 0;
|
||||
m_bootstrap_outcome_logged = false;
|
||||
m_bootstrap_fault_logged = false;
|
||||
}
|
||||
}
|
||||
|
||||
u32 Starlet::GetPC() const
|
||||
@@ -201,6 +299,41 @@ void Starlet::RunSlice(s64 cycles_late)
|
||||
ARM_IDLE_SLICE_CYCLES :
|
||||
(ipc_handshake_active ? ARM_IPC_SLICE_CYCLES : ARM_ACTIVE_SLICE_CYCLES);
|
||||
m_core->RunCycles(arm_cycles);
|
||||
if (m_bootstrap && !m_bootstrap_outcome_logged)
|
||||
TraceBootstrap();
|
||||
// Observe the PPC test program's result word. This is diagnostic only: all
|
||||
// request and response traffic still passes through shared RAM and IPC MMIO.
|
||||
if (m_bootstrap)
|
||||
{
|
||||
constexpr u32 PPC_PROBE_STATUS_ADDRESS = 0x00003c00;
|
||||
const u32 status = m_system.GetMemory().Read_U32(PPC_PROBE_STATUS_ADDRESS);
|
||||
if ((status & 0xffff0000) == 0x52500000 && status != m_last_probe_status)
|
||||
{
|
||||
m_last_probe_status = status;
|
||||
INFO_LOG_FMT(IOS, "Broadway ios-probe status={:#010x}", status);
|
||||
if (status == 0x52500002 || status == 0x52500003 || status == 0x52500005 ||
|
||||
(status & 0xfffff000) == 0x5250e000)
|
||||
{
|
||||
constexpr u32 PPC_PROBE_COUNTERS_ADDRESS = 0x00003c20;
|
||||
INFO_LOG_FMT(IOS,
|
||||
"Broadway ios-probe counters sent={} received={} invalid={} duplicate={} "
|
||||
"timeout={}",
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS),
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 4),
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 8),
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 12),
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 16));
|
||||
// 0x52500005 / 0x5250e2xx: Revolution IOS Phase 04D /dev/fs cases.
|
||||
if (status == 0x52500003 || status == 0x52500005 ||
|
||||
(status & 0xffffff00) == 0x5250e100 || (status & 0xffffff00) == 0x5250e200)
|
||||
{
|
||||
INFO_LOG_FMT(IOS, "Broadway ios-probe checks={} failures={}",
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 20),
|
||||
m_system.GetMemory().Read_U32(PPC_PROBE_COUNTERS_ADDRESS + 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep host-clock reads and diagnostic formatting off the normal scheduler path.
|
||||
const bool check_realtime_diagnostic =
|
||||
@@ -415,4 +548,57 @@ void Starlet::RunSlice(s64 cycles_late)
|
||||
const s64 next = std::max<s64>(1, static_cast<s64>(broadway_cycles) - cycles_late);
|
||||
m_system.GetCoreTiming().ScheduleEvent(next, m_run_event);
|
||||
}
|
||||
|
||||
void Starlet::TraceBootstrap()
|
||||
{
|
||||
const BootstrapELFInfo& bootstrap = *m_bootstrap;
|
||||
const u32 fault_code = m_memory->Read32(bootstrap.fault_code);
|
||||
if (fault_code != 0 && !m_bootstrap_fault_logged)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS,
|
||||
"Starlet bootstrap exception {}: LR={:#010x} SPSR={:#010x} PC={:#010x}",
|
||||
fault_code, m_memory->Read32(bootstrap.fault_lr),
|
||||
m_memory->Read32(bootstrap.fault_spsr), m_core->GetRegister(15));
|
||||
m_bootstrap_fault_logged = true;
|
||||
m_bootstrap_outcome_logged = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_memory->Read32(bootstrap.trace) != 0x52455631)
|
||||
return;
|
||||
const u32 length = m_memory->Read32(bootstrap.trace + 4);
|
||||
if (length > 1024)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS, "Starlet bootstrap trace length is invalid: {}", length);
|
||||
m_bootstrap_outcome_logged = true;
|
||||
return;
|
||||
}
|
||||
if (length < m_bootstrap_trace_length)
|
||||
{
|
||||
m_bootstrap_trace_length = 0;
|
||||
m_bootstrap_line_length = 0;
|
||||
}
|
||||
for (u32 index = m_bootstrap_trace_length; index < length; ++index)
|
||||
{
|
||||
const char character = static_cast<char>(m_memory->Read8(bootstrap.trace + 8 + index));
|
||||
if (character == '\n')
|
||||
{
|
||||
const std::string_view line(m_bootstrap_line.data(), m_bootstrap_line_length);
|
||||
INFO_LOG_FMT(IOS, "Starlet bootstrap: {}", line);
|
||||
if (line == "REV:BOOT:IDLE" || line.starts_with("REV:PANIC") ||
|
||||
line.starts_with("REV:FATAL"))
|
||||
{
|
||||
INFO_LOG_FMT(IOS, "Starlet bootstrap stopped at PC={:#010x} after {} instructions",
|
||||
m_core->GetRegister(15), m_core->GetExecutedInstructions());
|
||||
m_bootstrap_outcome_logged = true;
|
||||
}
|
||||
m_bootstrap_line_length = 0;
|
||||
}
|
||||
else if (m_bootstrap_line_length < m_bootstrap_line.size())
|
||||
{
|
||||
m_bootstrap_line[m_bootstrap_line_length++] = character;
|
||||
}
|
||||
}
|
||||
m_bootstrap_trace_length = length;
|
||||
}
|
||||
} // namespace IOS::LLE
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/IOS/Starlet/BootstrapELF.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
@@ -32,6 +34,8 @@ class StarletMemory;
|
||||
class Starlet final
|
||||
{
|
||||
public:
|
||||
// Allocate in Starlet.cpp so callers never depend on this class's size.
|
||||
static std::unique_ptr<Starlet> Create(Core::System& system);
|
||||
explicit Starlet(Core::System& system);
|
||||
~Starlet();
|
||||
|
||||
@@ -77,10 +81,18 @@ private:
|
||||
|
||||
static void RunCallback(Core::System& system, u64 userdata, s64 cycles_late);
|
||||
void RunSlice(s64 cycles_late);
|
||||
void TraceBootstrap();
|
||||
|
||||
Core::System& m_system;
|
||||
std::unique_ptr<StarletMemory> m_memory;
|
||||
std::unique_ptr<ARMCore> m_core;
|
||||
std::optional<BootstrapELFInfo> m_bootstrap;
|
||||
std::array<char, 256> m_bootstrap_line{};
|
||||
u32 m_bootstrap_line_length = 0;
|
||||
u32 m_bootstrap_trace_length = 0;
|
||||
u32 m_last_probe_status = 0;
|
||||
bool m_bootstrap_outcome_logged = false;
|
||||
bool m_bootstrap_fault_logged = false;
|
||||
CoreTiming::EventType* m_run_event = nullptr;
|
||||
u64 m_next_jit_diagnostic_instruction = 25'000'000;
|
||||
u64 m_next_realtime_diagnostic_ms = 0;
|
||||
|
||||
@@ -726,6 +726,85 @@ void StarletMemory::Reset()
|
||||
InitializeWiimotes();
|
||||
}
|
||||
|
||||
void StarletMemory::PrepareBootstrap()
|
||||
{
|
||||
m_initialized = false;
|
||||
Reset();
|
||||
m_boot0_mapped = false;
|
||||
m_sram_split_mode = true;
|
||||
WriteRegister(HW_BOOT0, BOOT0_DISABLE);
|
||||
WriteRegister(HW_SRNPROT, SRNPROT_SRAM_SPLIT_MODE);
|
||||
}
|
||||
|
||||
bool StarletMemory::AttachReadOnlyNAND(const std::string& path, std::string* error)
|
||||
{
|
||||
m_nand_journal.reset();
|
||||
m_nand_overlay.clear();
|
||||
m_nand = File::IOFile(path, "rb", File::SharedAccess::Read);
|
||||
const u64 nand_size = m_nand ? m_nand.GetSize() : 0;
|
||||
if (nand_size != NAND_IMAGE_SIZE && nand_size != BOOTMII_NAND_IMAGE_SIZE)
|
||||
{
|
||||
m_nand.Close();
|
||||
if (error)
|
||||
*error = "the bootstrap NAND must be a 0x21000000-byte raw NAND image or a "
|
||||
"0x21000400-byte BootMii dump";
|
||||
return false;
|
||||
}
|
||||
m_nand_read_only = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StarletMemory::AttachDisposableNAND(const std::string& source, const std::string& copy,
|
||||
std::string* error)
|
||||
{
|
||||
m_nand_disposable_copy.Close();
|
||||
if (copy.empty() || File::Exists(copy))
|
||||
{
|
||||
if (error)
|
||||
*error = "the disposable NAND copy must name a file that does not exist yet";
|
||||
return false;
|
||||
}
|
||||
if (!AttachReadOnlyNAND(source, error))
|
||||
return false;
|
||||
// "x": creation fails if the file appeared since the check above.
|
||||
File::IOFile output(copy, "wbx");
|
||||
std::array<u8, 0x10000> buffer{};
|
||||
const u64 size = m_nand.GetSize();
|
||||
bool copied = output.IsOpen() && m_nand.Seek(0, File::SeekOrigin::Begin);
|
||||
for (u64 offset = 0; copied && offset < size; offset += buffer.size())
|
||||
{
|
||||
const size_t count = static_cast<size_t>(std::min<u64>(buffer.size(), size - offset));
|
||||
copied = m_nand.ReadArray(buffer.data(), count) && output.WriteArray(buffer.data(), count);
|
||||
}
|
||||
copied = copied && output.Flush();
|
||||
output.Close();
|
||||
if (copied)
|
||||
m_nand_disposable_copy = File::IOFile(copy, "r+b");
|
||||
if (!copied || !m_nand_disposable_copy || m_nand_disposable_copy.GetSize() != size)
|
||||
{
|
||||
m_nand_disposable_copy.Close();
|
||||
m_nand.Close();
|
||||
if (error)
|
||||
*error = "could not create the disposable NAND copy";
|
||||
return false;
|
||||
}
|
||||
m_nand_read_only = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StarletMemory::AttachKeys(const std::string& path, std::string* error)
|
||||
{
|
||||
File::IOFile keys_file(path, "rb");
|
||||
if (!keys_file || keys_file.GetSize() != m_keys.size() || !keys_file.ReadArray(&m_keys))
|
||||
{
|
||||
m_keys.fill(0);
|
||||
if (error)
|
||||
*error = "the bootstrap keys must be a 1024-byte BootMii keys.bin";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void StarletMemory::DoState(PointerWrap& p)
|
||||
{
|
||||
const std::lock_guard wifi_sdio_lock(m_wifi_sdio_register_mutex);
|
||||
@@ -2020,7 +2099,11 @@ void StarletMemory::ExecuteOHCI1HCICommand(const std::vector<u8>& command)
|
||||
case HCI_CMD_READ_STORED_LINK_KEY:
|
||||
{
|
||||
const bool read_all = parameter_size >= sizeof(hci_read_stored_link_key_cp) && command[9] != 0;
|
||||
const u16 key_count = read_all ? static_cast<u16>(m_wiimotes.size()) : 0;
|
||||
// Bootstrap mode resets these slots without constructing Wiimote devices.
|
||||
// Only initialized devices have identities and keys to return.
|
||||
const u16 key_count = read_all ? static_cast<u16>(std::ranges::count_if(
|
||||
m_wiimotes, [](const auto& wiimote) { return !!wiimote; })) :
|
||||
0;
|
||||
append_le16(&reply, 255);
|
||||
append_le16(&reply, key_count);
|
||||
if (key_count != 0)
|
||||
@@ -2028,6 +2111,8 @@ void StarletMemory::ExecuteOHCI1HCICommand(const std::vector<u8>& command)
|
||||
std::vector<u8> parameters = {static_cast<u8>(key_count)};
|
||||
for (const auto& wiimote : m_wiimotes)
|
||||
{
|
||||
if (!wiimote)
|
||||
continue;
|
||||
parameters.insert(parameters.end(), wiimote->GetBD().begin(), wiimote->GetBD().end());
|
||||
parameters.insert(parameters.end(), wiimote->GetLinkKey().begin(),
|
||||
wiimote->GetLinkKey().end());
|
||||
@@ -4154,6 +4239,21 @@ bool StarletMemory::CommitNANDPages(const NANDJournal::Pages& pages)
|
||||
const Common::PerformanceTrace::Scope trace(Common::PerformanceTrace::Region::NAND);
|
||||
if (m_nand_journal && !m_nand_journal->Append(pages))
|
||||
return false;
|
||||
// Phase 06H: mirror into the disposable copy first; a failure leaves the array unchanged.
|
||||
if (m_nand_disposable_copy)
|
||||
{
|
||||
for (const auto& [page, data] : pages)
|
||||
{
|
||||
if (!m_nand_disposable_copy.Seek(static_cast<s64>(page) * NAND_RAW_PAGE_SIZE,
|
||||
File::SeekOrigin::Begin) ||
|
||||
!m_nand_disposable_copy.WriteArray(data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!m_nand_disposable_copy.Flush())
|
||||
return false;
|
||||
}
|
||||
for (const auto& [page, data] : pages)
|
||||
m_nand_overlay.insert_or_assign(page, data);
|
||||
return true;
|
||||
@@ -4545,6 +4645,11 @@ bool StarletMemory::ReadNANDStatus(u32 command)
|
||||
|
||||
bool StarletMemory::StageNANDProgram(u32 command, bool random_data_input)
|
||||
{
|
||||
if (m_nand_read_only)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS, "Read-only bootstrap NAND refused program command {:#010x}", command);
|
||||
return false;
|
||||
}
|
||||
if (!(command & NAND_CTRL_WRITE))
|
||||
return false;
|
||||
|
||||
@@ -4590,7 +4695,7 @@ bool StarletMemory::StageNANDProgram(u32 command, bool random_data_input)
|
||||
bool StarletMemory::CommitNANDProgram()
|
||||
{
|
||||
Common::PerformanceTrace::Add(Common::PerformanceTrace::Counter::NANDPrograms);
|
||||
if (!m_nand_program_pending)
|
||||
if (m_nand_read_only || !m_nand_program_pending)
|
||||
return false;
|
||||
|
||||
NANDPage raw{};
|
||||
@@ -4628,6 +4733,11 @@ bool StarletMemory::CommitNANDProgram()
|
||||
|
||||
bool StarletMemory::StageNANDErase()
|
||||
{
|
||||
if (m_nand_read_only)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS, "Read-only bootstrap NAND refused erase setup");
|
||||
return false;
|
||||
}
|
||||
m_nand_erase_page = ReadRegister(NAND_ADDR2) & 0xffffff;
|
||||
m_nand_erase_pending = m_nand_erase_page < NAND_PAGE_COUNT;
|
||||
if (m_nand_erase_pending)
|
||||
@@ -4638,7 +4748,7 @@ bool StarletMemory::StageNANDErase()
|
||||
bool StarletMemory::CommitNANDErase()
|
||||
{
|
||||
Common::PerformanceTrace::Add(Common::PerformanceTrace::Counter::NANDErases);
|
||||
if (!m_nand_erase_pending)
|
||||
if (m_nand_read_only || !m_nand_erase_pending)
|
||||
return false;
|
||||
|
||||
const u32 block_start = m_nand_erase_page & ~(NAND_PAGES_PER_BLOCK - 1);
|
||||
|
||||
@@ -56,6 +56,22 @@ public:
|
||||
}
|
||||
|
||||
bool Init(const std::string& dump_directory, std::string* error);
|
||||
// Set up empty SRAM with BOOT0 hidden and the IOS-style high SRAM split for an external ELF.
|
||||
void PrepareBootstrap();
|
||||
// Bootstrap-ELF mode only: expose a raw NAND image to the NAND controller strictly read-only.
|
||||
// No journal is opened; every program or erase command then fails with the controller error
|
||||
// bit, so a Revolution IOS read-only driver can be validated without any write path.
|
||||
bool AttachReadOnlyNAND(const std::string& path, std::string* error);
|
||||
// Revolution IOS Phase 06H, emulator only: a disposable writable NAND. `source` is opened
|
||||
// read-only exactly as above and is never written. `copy` must not exist; it is created as a
|
||||
// byte-for-byte copy of the source, and every committed program or erase is mirrored into it
|
||||
// before the in-memory overlay changes, so it holds the mutated image for independent
|
||||
// checking. No journal is opened.
|
||||
bool AttachDisposableNAND(const std::string& source, const std::string& copy,
|
||||
std::string* error);
|
||||
// Revolution IOS Phase 04C: bootstrap mode loads no keys, so the OTP reads zero. This
|
||||
// loads a 1024-byte BootMii keys.bin so OTP reads return the console's own words.
|
||||
bool AttachKeys(const std::string& path, std::string* error);
|
||||
void Reset();
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
@@ -321,10 +337,13 @@ private:
|
||||
u64 m_arm_cycles = 0;
|
||||
u32 m_timer_offset = 0;
|
||||
bool m_initialized = false;
|
||||
bool m_nand_read_only = false;
|
||||
bool m_boot0_mapped = true;
|
||||
bool m_sram_split_mode = false;
|
||||
// Host persistence is not serialized; savestates contain the complete overlay above.
|
||||
std::unique_ptr<NANDJournal> m_nand_journal;
|
||||
// Phase 06H: the disposable copy mirroring committed NAND pages (bootstrap mode only).
|
||||
File::IOFile m_nand_disposable_copy;
|
||||
std::unique_ptr<AX88772> m_ethernet;
|
||||
std::unique_ptr<SlirpNetwork> m_ethernet_network;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/System.h"
|
||||
#include "DolphinNoGUI/Platform.h"
|
||||
|
||||
@@ -26,10 +28,43 @@ void PlatformHeadless::SetTitle(const std::string& title)
|
||||
|
||||
void PlatformHeadless::MainLoop()
|
||||
{
|
||||
bool diff_observed = false;
|
||||
while (m_running.IsSet())
|
||||
{
|
||||
UpdateRunningFlag();
|
||||
Core::HostDispatchJobs(Core::System::GetInstance());
|
||||
auto& system = Core::System::GetInstance();
|
||||
Core::HostDispatchJobs(system);
|
||||
if (!diff_observed && Core::IsRunning(system))
|
||||
{
|
||||
auto& memory = system.GetMemory();
|
||||
const u32 status = memory.Read_U32(0x00003c00);
|
||||
if (status == 0x52500004 || (status & 0xffffff00) == 0x5250e100)
|
||||
{
|
||||
diff_observed = true;
|
||||
INFO_LOG_FMT(IOS, "IOS_PROBE_DIFF_DONE status={:#010x}", status);
|
||||
constexpr u32 trace_base = 0x00003d00;
|
||||
const u32 count = memory.Read_U32(trace_base);
|
||||
if (count > 8)
|
||||
{
|
||||
ERROR_LOG_FMT(IOS, "IOS_PROBE_DIFF_BAD_COUNT count={}", count);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 index = 0; index < count; ++index)
|
||||
{
|
||||
const u32 record = trace_base + 0x20 + index * 24;
|
||||
INFO_LOG_FMT(IOS,
|
||||
"IOS_PROBE_JSON {{\"schema\":1,\"index\":{},\"operation\":{},"
|
||||
"\"argument\":{},\"return\":{},\"output\":{},\"ticks\":{},"
|
||||
"\"status\":{}}}",
|
||||
index, memory.Read_U32(record), memory.Read_U32(record + 4),
|
||||
static_cast<s32>(memory.Read_U32(record + 8)),
|
||||
memory.Read_U32(record + 12), memory.Read_U32(record + 16),
|
||||
memory.Read_U32(record + 20));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
enable_testing()
|
||||
add_custom_target(unittests)
|
||||
add_custom_command(TARGET unittests POST_BUILD COMMAND ${CMAKE_CTEST_COMMAND} "--output-on-failure")
|
||||
|
||||
string(APPEND CMAKE_RUNTIME_OUTPUT_DIRECTORY "/Tests")
|
||||
|
||||
add_executable(tests EXCLUDE_FROM_ALL UnitTestsMain.cpp StubHost.cpp)
|
||||
set_target_properties(tests PROPERTIES FOLDER Tests)
|
||||
target_link_libraries(tests PRIVATE fmt::fmt gtest::gtest core uicommon)
|
||||
add_test(NAME tests COMMAND tests)
|
||||
add_custom_command(TARGET tests POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Sys"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/Data/Sys" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Sys"
|
||||
)
|
||||
enable_testing()
|
||||
add_custom_target(unittests)
|
||||
add_custom_command(TARGET unittests POST_BUILD COMMAND ${CMAKE_CTEST_COMMAND} "--output-on-failure")
|
||||
|
||||
string(APPEND CMAKE_RUNTIME_OUTPUT_DIRECTORY "/Tests")
|
||||
|
||||
add_executable(tests EXCLUDE_FROM_ALL UnitTestsMain.cpp StubHost.cpp)
|
||||
set_target_properties(tests PROPERTIES FOLDER Tests)
|
||||
target_link_libraries(tests PRIVATE fmt::fmt gtest::gtest core uicommon)
|
||||
add_test(NAME tests COMMAND tests)
|
||||
add_custom_command(TARGET tests POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Sys"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/Data/Sys" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Sys"
|
||||
)
|
||||
add_dependencies(unittests tests)
|
||||
|
||||
macro(add_dolphin_test target)
|
||||
add_library(${target} OBJECT ${ARGN})
|
||||
target_link_libraries(${target} PUBLIC fmt::fmt gtest::gtest PRIVATE core uicommon)
|
||||
target_link_libraries(tests PRIVATE ${target})
|
||||
endmacro()
|
||||
|
||||
add_subdirectory(Common)
|
||||
add_subdirectory(Core)
|
||||
# Runs a real Starlet ELF through the fork's CPU and SRAM bus without NAND or a frontend.
|
||||
add_executable(StarletBootstrapProbe EXCLUDE_FROM_ALL
|
||||
${CMAKE_SOURCE_DIR}/Tools/StarletBootstrapProbe/StarletBootstrapProbe.cpp StubHost.cpp)
|
||||
target_link_libraries(StarletBootstrapProbe PRIVATE fmt::fmt core uicommon)
|
||||
|
||||
macro(add_dolphin_test target)
|
||||
add_library(${target} OBJECT ${ARGN})
|
||||
target_link_libraries(${target} PUBLIC fmt::fmt gtest::gtest PRIVATE core uicommon)
|
||||
target_link_libraries(tests PRIVATE ${target})
|
||||
endmacro()
|
||||
|
||||
add_subdirectory(Common)
|
||||
add_subdirectory(Core)
|
||||
add_subdirectory(VideoCommon)
|
||||
|
||||
# Opt-in local trace qualification; never starts a console or accesses a NAND dump.
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
add_dolphin_test(MMIOTest MMIOTest.cpp)
|
||||
add_dolphin_test(PageFaultTest PageFaultTest.cpp)
|
||||
add_dolphin_test(CoreTimingTest CoreTimingTest.cpp)
|
||||
add_dolphin_test(PatchAllowlistTest PatchAllowlistTest.cpp)
|
||||
|
||||
add_dolphin_test(DSPAcceleratorTest DSP/DSPAcceleratorTest.cpp)
|
||||
add_dolphin_test(DSPAssemblyTest
|
||||
DSP/DSPAssemblyTest.cpp
|
||||
DSP/DSPTestBinary.cpp
|
||||
DSP/DSPTestText.cpp
|
||||
DSP/HermesBinary.cpp
|
||||
DSP/HermesText.cpp
|
||||
)
|
||||
|
||||
add_dolphin_test(MMIOTest MMIOTest.cpp)
|
||||
add_dolphin_test(PageFaultTest PageFaultTest.cpp)
|
||||
add_dolphin_test(CoreTimingTest CoreTimingTest.cpp)
|
||||
add_dolphin_test(PatchAllowlistTest PatchAllowlistTest.cpp)
|
||||
|
||||
add_dolphin_test(DSPAcceleratorTest DSP/DSPAcceleratorTest.cpp)
|
||||
add_dolphin_test(DSPAssemblyTest
|
||||
DSP/DSPAssemblyTest.cpp
|
||||
DSP/DSPTestBinary.cpp
|
||||
DSP/DSPTestText.cpp
|
||||
DSP/HermesBinary.cpp
|
||||
DSP/HermesText.cpp
|
||||
)
|
||||
|
||||
add_dolphin_test(ESFormatsTest IOS/ES/FormatsTest.cpp)
|
||||
|
||||
add_dolphin_test(StarletARMCoreTest IOS/Starlet/ARMCoreTest.cpp)
|
||||
add_dolphin_test(StarletBootstrapELFTest IOS/Starlet/BootstrapELFTest.cpp)
|
||||
add_dolphin_test(StarletDMATest IOS/Starlet/DMATest.cpp)
|
||||
add_dolphin_test(StarletSRAMReadTest IOS/Starlet/SRAMReadTest.cpp)
|
||||
add_dolphin_test(StarletSRAMWriteTest IOS/Starlet/SRAMWriteTest.cpp)
|
||||
@@ -24,36 +25,36 @@ add_dolphin_test(StarletEthernetTest IOS/Starlet/AX88772Test.cpp)
|
||||
target_include_directories(StarletEthernetTest PRIVATE ${PROJECT_SOURCE_DIR}/Externals/libslirp/include)
|
||||
|
||||
add_dolphin_test(FileSystemTest IOS/FS/FileSystemTest.cpp)
|
||||
|
||||
add_dolphin_test(SkylandersTest IOS/USB/SkylandersTest.cpp)
|
||||
|
||||
if(_M_X86_64)
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
|
||||
add_dolphin_test(SkylandersTest IOS/USB/SkylandersTest.cpp)
|
||||
|
||||
if(_M_X86_64)
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
PowerPC/Jit64Common/ConvertDoubleToSingle.cpp
|
||||
PowerPC/Jit64Common/DCache.cpp
|
||||
PowerPC/Jit64Common/Fres.cpp
|
||||
PowerPC/Jit64Common/Frsqrte.cpp
|
||||
)
|
||||
elseif(_M_ARM_64)
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
PowerPC/JitArm64/ConvertSingleDouble.cpp
|
||||
PowerPC/JitArm64/FPRF.cpp
|
||||
PowerPC/JitArm64/Fres.cpp
|
||||
PowerPC/JitArm64/Frsqrte.cpp
|
||||
PowerPC/JitArm64/MovI2R.cpp
|
||||
)
|
||||
else()
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(PowerPCTest PRIVATE
|
||||
PowerPC/TestValues.h
|
||||
StubJit.h
|
||||
)
|
||||
PowerPC/Jit64Common/Fres.cpp
|
||||
PowerPC/Jit64Common/Frsqrte.cpp
|
||||
)
|
||||
elseif(_M_ARM_64)
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
PowerPC/JitArm64/ConvertSingleDouble.cpp
|
||||
PowerPC/JitArm64/FPRF.cpp
|
||||
PowerPC/JitArm64/Fres.cpp
|
||||
PowerPC/JitArm64/Frsqrte.cpp
|
||||
PowerPC/JitArm64/MovI2R.cpp
|
||||
)
|
||||
else()
|
||||
add_dolphin_test(PowerPCTest
|
||||
PowerPC/DivUtilsTest.cpp
|
||||
PowerPC/PageTableHostMappingTest.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
target_sources(PowerPCTest PRIVATE
|
||||
PowerPC/TestValues.h
|
||||
StubJit.h
|
||||
)
|
||||
@@ -0,0 +1,236 @@
|
||||
// Copyright 2026 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "Core/IOS/Starlet/ARMCore.h"
|
||||
#include "Core/IOS/Starlet/BootstrapELF.h"
|
||||
|
||||
namespace IOS::LLE
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr u32 TEXT_BASE = 0xffff0000;
|
||||
constexpr u32 DATA_BASE = 0xfffe0000;
|
||||
|
||||
class RecordingBus final : public ARMBus
|
||||
{
|
||||
public:
|
||||
u8 Read8(u32 address) override
|
||||
{
|
||||
const auto it = bytes.find(address);
|
||||
return it == bytes.end() ? 0 : it->second;
|
||||
}
|
||||
void Write8(u32 address, u8 value) override { bytes[address] = value; }
|
||||
|
||||
std::unordered_map<u32, u8> bytes;
|
||||
};
|
||||
|
||||
void Put16(std::array<u8, 0x300>& image, size_t offset, u16 value)
|
||||
{
|
||||
image[offset] = static_cast<u8>(value >> 8);
|
||||
image[offset + 1] = static_cast<u8>(value);
|
||||
}
|
||||
|
||||
void Put32(std::array<u8, 0x300>& image, size_t offset, u32 value)
|
||||
{
|
||||
image[offset] = static_cast<u8>(value >> 24);
|
||||
image[offset + 1] = static_cast<u8>(value >> 16);
|
||||
image[offset + 2] = static_cast<u8>(value >> 8);
|
||||
image[offset + 3] = static_cast<u8>(value);
|
||||
}
|
||||
|
||||
std::array<u8, 0x300> MakeImage()
|
||||
{
|
||||
std::array<u8, 0x300> image{};
|
||||
image[0] = 0x7f;
|
||||
image[1] = 'E';
|
||||
image[2] = 'L';
|
||||
image[3] = 'F';
|
||||
image[4] = 1; // ELF32
|
||||
image[5] = 2; // big endian
|
||||
image[6] = 1;
|
||||
Put16(image, 16, 2); // ET_EXEC
|
||||
Put16(image, 18, 40); // ARM
|
||||
Put32(image, 20, 1); // ELF version
|
||||
Put32(image, 24, TEXT_BASE);
|
||||
Put32(image, 28, 52); // program headers
|
||||
Put32(image, 32, 0x200); // section headers
|
||||
Put16(image, 40, 52);
|
||||
Put16(image, 42, 32);
|
||||
Put16(image, 44, 2);
|
||||
Put16(image, 46, 40);
|
||||
Put16(image, 48, 3);
|
||||
|
||||
Put32(image, 52, 1);
|
||||
Put32(image, 56, 0x100);
|
||||
Put32(image, 60, TEXT_BASE);
|
||||
Put32(image, 64, TEXT_BASE);
|
||||
Put32(image, 68, 4);
|
||||
Put32(image, 72, 8);
|
||||
Put32(image, 76, 5);
|
||||
image[0x100] = 0xea; // ARM branch instruction
|
||||
|
||||
Put32(image, 84, 1);
|
||||
Put32(image, 88, 0x110);
|
||||
Put32(image, 92, DATA_BASE);
|
||||
Put32(image, 96, DATA_BASE);
|
||||
Put32(image, 100, 4);
|
||||
Put32(image, 104, 0x420);
|
||||
Put32(image, 108, 6);
|
||||
image[0x110] = 0x12;
|
||||
image[0x111] = 0x34;
|
||||
image[0x112] = 0x56;
|
||||
image[0x113] = 0x78;
|
||||
|
||||
constexpr char names[] = "\0REV_TRACE\0__fault_code\0__fault_lr\0__fault_spsr";
|
||||
for (size_t index = 0; index < sizeof(names); ++index)
|
||||
image[0x180 + index] = static_cast<u8>(names[index]);
|
||||
Put32(image, 0x228 + 4, 3); // SHT_STRTAB
|
||||
Put32(image, 0x228 + 16, 0x180);
|
||||
Put32(image, 0x228 + 20, sizeof(names));
|
||||
Put32(image, 0x250 + 4, 2); // SHT_SYMTAB
|
||||
Put32(image, 0x250 + 16, 0x120);
|
||||
Put32(image, 0x250 + 20, 5 * 16);
|
||||
Put32(image, 0x250 + 24, 1);
|
||||
Put32(image, 0x250 + 36, 16);
|
||||
|
||||
const auto symbol = [&image](size_t index, u32 name, u32 address, u32 size) {
|
||||
const size_t offset = 0x120 + index * 16;
|
||||
Put32(image, offset, name);
|
||||
Put32(image, offset + 4, address);
|
||||
Put32(image, offset + 8, size);
|
||||
};
|
||||
symbol(1, 1, DATA_BASE + 8, 1032);
|
||||
symbol(2, 11, DATA_BASE + 0x410, 4);
|
||||
symbol(3, 24, DATA_BASE + 0x414, 4);
|
||||
symbol(4, 35, DATA_BASE + 0x418, 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
TEST(BootstrapELFTest, LoadsSegmentsAndZerosUninitializedData)
|
||||
{
|
||||
const auto image = MakeImage();
|
||||
RecordingBus bus;
|
||||
BootstrapELFInfo info;
|
||||
std::string error;
|
||||
ASSERT_TRUE(LoadBootstrapELF(image, bus, &info, &error)) << error;
|
||||
EXPECT_EQ(info.entry, TEXT_BASE);
|
||||
EXPECT_EQ(info.trace, DATA_BASE + 8);
|
||||
EXPECT_EQ(info.fault_spsr, DATA_BASE + 0x418);
|
||||
EXPECT_EQ(bus.Read8(TEXT_BASE), 0xea);
|
||||
EXPECT_EQ(bus.Read8(TEXT_BASE + 4), 0);
|
||||
EXPECT_EQ(bus.Read32(DATA_BASE), 0x12345678u);
|
||||
EXPECT_EQ(bus.Read32(DATA_BASE + 0x41c), 0u);
|
||||
EXPECT_EQ(bus.bytes.size(), size_t{8 + 0x420});
|
||||
}
|
||||
|
||||
TEST(BootstrapELFTest, RejectsMalformedImageBeforeWritingMemory)
|
||||
{
|
||||
auto image = MakeImage();
|
||||
RecordingBus bus;
|
||||
BootstrapELFInfo info;
|
||||
std::string error;
|
||||
image[5] = 1;
|
||||
EXPECT_FALSE(LoadBootstrapELF(image, bus, &info, &error));
|
||||
EXPECT_TRUE(bus.bytes.empty());
|
||||
|
||||
image = MakeImage();
|
||||
Put32(image, 0x120 + 2 * 16 + 4, DATA_BASE + 0x420);
|
||||
EXPECT_FALSE(LoadBootstrapELF(image, bus, &info, &error));
|
||||
EXPECT_TRUE(bus.bytes.empty());
|
||||
|
||||
image = MakeImage();
|
||||
Put32(image, 88, 0x300);
|
||||
EXPECT_FALSE(LoadBootstrapELF(image, bus, &info, &error));
|
||||
EXPECT_TRUE(bus.bytes.empty());
|
||||
}
|
||||
|
||||
// Revolution IOS Phase 06H: the optional MEM2 text segment of the emulator-only
|
||||
// disposable-image kernel, accepted only when the caller allows it.
|
||||
constexpr u32 MEM2_TEXT = 0x12600000;
|
||||
|
||||
std::array<u8, 0x300> MakeMem2Image(u32 address, u32 flags)
|
||||
{
|
||||
auto image = MakeImage();
|
||||
Put16(image, 44, 3);
|
||||
Put32(image, 116, 1);
|
||||
Put32(image, 120, 0x114);
|
||||
Put32(image, 124, address);
|
||||
Put32(image, 128, address);
|
||||
Put32(image, 132, 4);
|
||||
Put32(image, 136, 0x10);
|
||||
Put32(image, 140, flags);
|
||||
Put32(image, 0x114, 0xe12fff1e); // BX LR
|
||||
return image;
|
||||
}
|
||||
|
||||
TEST(BootstrapELFTest, Mem2TextSegmentOnlyWhenAllowed)
|
||||
{
|
||||
RecordingBus bus;
|
||||
BootstrapELFInfo info;
|
||||
std::string error;
|
||||
auto image = MakeMem2Image(MEM2_TEXT, 5);
|
||||
EXPECT_FALSE(LoadBootstrapELF(image, bus, &info, &error));
|
||||
EXPECT_TRUE(bus.bytes.empty());
|
||||
|
||||
ASSERT_TRUE(LoadBootstrapELF(image, bus, &info, &error, true)) << error;
|
||||
EXPECT_EQ(bus.Read32(MEM2_TEXT), 0xe12fff1eu);
|
||||
EXPECT_EQ(bus.Read32(MEM2_TEXT + 0xc), 0u);
|
||||
EXPECT_EQ(bus.Read8(TEXT_BASE), 0xea);
|
||||
EXPECT_EQ(bus.Read32(DATA_BASE), 0x12345678u);
|
||||
EXPECT_EQ(bus.bytes.size(), size_t{8 + 0x420 + 0x10});
|
||||
|
||||
RecordingBus plain;
|
||||
const auto two_segments = MakeImage();
|
||||
EXPECT_TRUE(LoadBootstrapELF(two_segments, plain, &info, &error, true)) << error;
|
||||
}
|
||||
|
||||
TEST(BootstrapELFTest, RejectsInvalidMem2TextSegmentBeforeWritingMemory)
|
||||
{
|
||||
RecordingBus bus;
|
||||
BootstrapELFInfo info;
|
||||
std::string error;
|
||||
// Writable, outside MEM2, crossing its end, or a second SRAM text segment.
|
||||
for (const auto& image : {MakeMem2Image(MEM2_TEXT, 6), MakeMem2Image(0x0fff0000, 5),
|
||||
MakeMem2Image(0x13fffff8, 5), MakeMem2Image(TEXT_BASE, 5)})
|
||||
{
|
||||
EXPECT_FALSE(LoadBootstrapELF(image, bus, &info, &error, true));
|
||||
EXPECT_TRUE(bus.bytes.empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ARMCoreTest, Armv5DoublewordTransfersAndAlignmentAbort)
|
||||
{
|
||||
RecordingBus bus;
|
||||
bus.Write32(TEXT_BASE, 0xe1c020d0); // LDRD r2, r3, [r0]
|
||||
bus.Write32(TEXT_BASE + 4, 0xe1c120f0); // STRD r2, r3, [r1]
|
||||
bus.Write32(DATA_BASE, 0x11223344);
|
||||
bus.Write32(DATA_BASE + 4, 0x55667788);
|
||||
|
||||
ARMCore core(bus);
|
||||
core.Reset(TEXT_BASE);
|
||||
core.SetBigEndian(true);
|
||||
core.SetRegister(0, DATA_BASE);
|
||||
core.SetRegister(1, DATA_BASE + 8);
|
||||
core.Step();
|
||||
EXPECT_EQ(core.GetRegister(2), 0x11223344u);
|
||||
EXPECT_EQ(core.GetRegister(3), 0x55667788u);
|
||||
core.Step();
|
||||
EXPECT_EQ(bus.Read32(DATA_BASE + 8), 0x11223344u);
|
||||
EXPECT_EQ(bus.Read32(DATA_BASE + 12), 0x55667788u);
|
||||
|
||||
core.Reset(TEXT_BASE);
|
||||
core.SetBigEndian(true);
|
||||
core.SetRegister(0, DATA_BASE + 4);
|
||||
core.Step();
|
||||
EXPECT_EQ(core.GetRegister(15), TEXT_BASE + 0x10);
|
||||
EXPECT_EQ(core.GetRegister(14), TEXT_BASE + 8);
|
||||
EXPECT_EQ(core.GetCP15State().fault_address, DATA_BASE + 4);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace IOS::LLE
|
||||
@@ -135,6 +135,21 @@ protected:
|
||||
EXPECT_EQ(m_memory->GetDMAMemoryPointer(address, 4), nullptr);
|
||||
}
|
||||
|
||||
void CheckBootstrapStoredKeys()
|
||||
{
|
||||
m_memory->PrepareBootstrap();
|
||||
for (const u8 read_all : {0, 1})
|
||||
{
|
||||
SCOPED_TRACE(read_all);
|
||||
m_memory->m_ohci1_hci_events.clear();
|
||||
m_memory->ExecuteOHCI1HCICommand({0x0d, 0x0c, 7, 0, 0, 0, 0, 0, 0, read_all});
|
||||
ASSERT_EQ(m_memory->m_ohci1_hci_events.size(), 1u);
|
||||
// Command Complete: capacity 255, zero stored keys, no Return Link Keys event.
|
||||
EXPECT_EQ(m_memory->m_ohci1_hci_events.front(),
|
||||
(std::vector<u8>{0x0e, 8, 1, 0x0d, 0x0c, 0, 0xff, 0, 0, 0}));
|
||||
}
|
||||
}
|
||||
|
||||
void CheckOHCI()
|
||||
{
|
||||
for (const u32 base : {0x10000U, 0x10010000U, 0x0d404000U})
|
||||
@@ -381,6 +396,11 @@ TEST_F(StarletDMATest, OHCIUsesTwoPhysicalPagesAndLittleEndianDescriptors)
|
||||
CheckOHCI();
|
||||
}
|
||||
|
||||
TEST_F(StarletDMATest, BootstrapReadStoredKeysHasNoWiimoteDevices)
|
||||
{
|
||||
CheckBootstrapStoredKeys();
|
||||
}
|
||||
|
||||
TEST_F(StarletDMATest, NANDSeparatesDataSpareAndECCIncludingPartialTransfers)
|
||||
{
|
||||
CheckNAND();
|
||||
|
||||
Reference in new issue
Block a user