mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-13 21:12:09 +00:00
Merge branch 'master' of https://github.com/dolphin-emu/dolphin into dolphin-emu-master
This commit is contained in:
commit
7e6752e8fc
516 changed files with 60670 additions and 270317 deletions
|
@ -20,7 +20,7 @@ AlsaSound::~AlsaSound()
|
|||
m_thread_status.store(ALSAThreadStatus::STOPPING);
|
||||
|
||||
// Immediately lock and unlock mutex to prevent cv race.
|
||||
std::unique_lock<std::mutex>{cv_m};
|
||||
std::unique_lock<std::mutex>{cv_m}.unlock();
|
||||
|
||||
// Give the opportunity to the audio thread
|
||||
// to realize we are stopping the emulation
|
||||
|
@ -82,7 +82,7 @@ bool AlsaSound::SetRunning(bool running)
|
|||
m_thread_status.store(running ? ALSAThreadStatus::RUNNING : ALSAThreadStatus::PAUSED);
|
||||
|
||||
// Immediately lock and unlock mutex to prevent cv race.
|
||||
std::unique_lock<std::mutex>{cv_m};
|
||||
std::unique_lock<std::mutex>{cv_m}.unlock();
|
||||
|
||||
// Notify thread that status has changed
|
||||
cv.notify_one();
|
||||
|
|
|
@ -137,6 +137,12 @@ OpenSLESStream::~OpenSLESStream()
|
|||
}
|
||||
}
|
||||
|
||||
bool OpenSLESStream::SetRunning(bool running)
|
||||
{
|
||||
SLuint32 new_state = running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED;
|
||||
return (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, new_state) == SL_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void OpenSLESStream::SetVolume(int volume)
|
||||
{
|
||||
const SLmillibel attenuation =
|
||||
|
|
|
@ -14,7 +14,7 @@ class OpenSLESStream final : public SoundStream
|
|||
public:
|
||||
~OpenSLESStream() override;
|
||||
bool Init() override;
|
||||
bool SetRunning(bool running) override { return true; }
|
||||
bool SetRunning(bool running) override;
|
||||
void SetVolume(int volume) override;
|
||||
static bool IsValid() { return true; }
|
||||
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "AudioCommon/WaveFile.h"
|
||||
#include "AudioCommon/Mixer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "AudioCommon/Mixer.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IOFile.h"
|
||||
|
|
|
@ -30,3 +30,59 @@ endif()
|
|||
if (WIN32 AND ENABLE_AUTOUPDATE)
|
||||
add_subdirectory(WinUpdater)
|
||||
endif()
|
||||
|
||||
if (APPLE AND ENABLE_QT)
|
||||
set(DOLPHIN_MAC_BUNDLE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Dolphin.app")
|
||||
|
||||
add_custom_target(build_final_bundle ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory
|
||||
${DOLPHIN_MAC_BUNDLE}
|
||||
|
||||
COMMAND cp -R
|
||||
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DolphinQt.app
|
||||
${DOLPHIN_MAC_BUNDLE}
|
||||
|
||||
# HACK: The Updater does not support setting the executable bit on new files,
|
||||
# so don't use the new executable name, and instead continue to use "Dolphin".
|
||||
COMMAND ${CMAKE_COMMAND} -E rename
|
||||
${DOLPHIN_MAC_BUNDLE}/Contents/MacOS/DolphinQt
|
||||
${DOLPHIN_MAC_BUNDLE}/Contents/MacOS/Dolphin
|
||||
|
||||
COMMAND plutil
|
||||
-replace CFBundleExecutable -string Dolphin
|
||||
${DOLPHIN_MAC_BUNDLE}/Contents/Info.plist
|
||||
|
||||
DEPENDS dolphin-emu)
|
||||
|
||||
if (ENABLE_AUTOUPDATE)
|
||||
add_dependencies(build_final_bundle MacUpdater)
|
||||
|
||||
add_custom_command(TARGET build_final_bundle
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${DOLPHIN_MAC_BUNDLE}/Contents/Helpers"
|
||||
|
||||
COMMAND cp -R
|
||||
"$<TARGET_BUNDLE_DIR:MacUpdater>"
|
||||
"${DOLPHIN_MAC_BUNDLE}/Contents/Helpers/Dolphin Updater.app")
|
||||
|
||||
if (MACOS_CODE_SIGNING)
|
||||
add_custom_command(TARGET build_final_bundle
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
||||
"-t"
|
||||
"${MACOS_CODE_SIGNING_IDENTITY}"
|
||||
"${DOLPHIN_MAC_BUNDLE}/Contents/Helpers/Dolphin Updater.app")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MACOS_CODE_SIGNING)
|
||||
add_custom_command(TARGET build_final_bundle
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
||||
"-t"
|
||||
"-e" "${CMAKE_SOURCE_DIR}/Source/Core/DolphinQt/DolphinEmu$<$<CONFIG:Debug>:Debug>.entitlements"
|
||||
"${MACOS_CODE_SIGNING_IDENTITY}"
|
||||
"${DOLPHIN_MAC_BUNDLE}")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -87,26 +87,6 @@ void ARM64XEmitter::SetCodePtr(u8* ptr, u8* end, bool write_failed)
|
|||
m_lastCacheFlushEnd = ptr;
|
||||
}
|
||||
|
||||
const u8* ARM64XEmitter::GetCodePtr() const
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
u8* ARM64XEmitter::GetWritableCodePtr()
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
const u8* ARM64XEmitter::GetCodeEnd() const
|
||||
{
|
||||
return m_code_end;
|
||||
}
|
||||
|
||||
u8* ARM64XEmitter::GetWritableCodeEnd()
|
||||
{
|
||||
return m_code_end;
|
||||
}
|
||||
|
||||
void ARM64XEmitter::ReserveCodeSpace(u32 bytes)
|
||||
{
|
||||
for (u32 i = 0; i < bytes / 4; i++)
|
||||
|
|
|
@ -680,10 +680,10 @@ public:
|
|||
void SetCodePtr(u8* ptr, u8* end, bool write_failed = false);
|
||||
|
||||
void SetCodePtrUnsafe(u8* ptr, u8* end, bool write_failed = false);
|
||||
const u8* GetCodePtr() const;
|
||||
u8* GetWritableCodePtr();
|
||||
const u8* GetCodeEnd() const;
|
||||
u8* GetWritableCodeEnd();
|
||||
const u8* GetCodePtr() const { return m_code; }
|
||||
u8* GetWritableCodePtr() { return m_code; }
|
||||
const u8* GetCodeEnd() const { return m_code_end; }
|
||||
u8* GetWritableCodeEnd() { return m_code_end; }
|
||||
void ReserveCodeSpace(u32 bytes);
|
||||
u8* AlignCode16();
|
||||
u8* AlignCodePage();
|
||||
|
|
|
@ -15,11 +15,16 @@
|
|||
#include <Windows.h>
|
||||
#include <arm64intr.h>
|
||||
#include "Common/WindowsRegistry.h"
|
||||
#else
|
||||
#ifndef __FreeBSD__
|
||||
#elif defined(__linux__)
|
||||
#include <asm/hwcap.h>
|
||||
#endif
|
||||
#include <sys/auxv.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/auxv.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <machine/armreg.h>
|
||||
#include <machine/cpu.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
@ -183,7 +188,7 @@ static bool Read_MIDR_EL1(u64* value)
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#if defined(_WIN32) || defined(__linux__) || defined(__FreeBSD__)
|
||||
|
||||
static std::string MIDRToString(u64 midr)
|
||||
{
|
||||
|
@ -248,7 +253,7 @@ void CPUInfo::Detect()
|
|||
{
|
||||
cpu_id = MIDRToString(reg);
|
||||
}
|
||||
#else
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
// Linux, Android, and FreeBSD
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
@ -277,6 +282,33 @@ void CPUInfo::Detect()
|
|||
{
|
||||
cpu_id = MIDRToString(midr);
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD
|
||||
int mib[2];
|
||||
size_t len;
|
||||
char hwmodel[256];
|
||||
uint64_t isar0;
|
||||
|
||||
mib[0] = CTL_HW;
|
||||
mib[1] = HW_MODEL;
|
||||
len = std::size(hwmodel);
|
||||
if (sysctl(mib, 2, &hwmodel, &len, nullptr, 0) != -1)
|
||||
model_name = std::string(hwmodel, len - 1);
|
||||
|
||||
mib[0] = CTL_MACHDEP;
|
||||
mib[1] = CPU_ID_AA64ISAR0;
|
||||
len = sizeof(isar0);
|
||||
if (sysctl(mib, 2, &isar0, &len, nullptr, 0) != -1)
|
||||
{
|
||||
if (ID_AA64ISAR0_AES(isar0) >= ID_AA64ISAR0_AES_BASE)
|
||||
bAES = true;
|
||||
if (ID_AA64ISAR0_SHA1(isar0) >= ID_AA64ISAR0_SHA1_BASE)
|
||||
bSHA1 = true;
|
||||
if (ID_AA64ISAR0_SHA2(isar0) >= ID_AA64ISAR0_SHA2_BASE)
|
||||
bSHA2 = true;
|
||||
if (ID_AA64ISAR0_CRC32(isar0) >= ID_AA64ISAR0_CRC32_BASE)
|
||||
bCRC32 = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
model_name = ReplaceAll(model_name, ",", "_");
|
||||
|
|
|
@ -42,40 +42,40 @@ constexpr ExtendedMnemonicDesc INVALID_EXT_MNEMONIC = {0, nullptr};
|
|||
|
||||
// All operands as referenced by the Gekko/Broadway user manual
|
||||
// See section 12.1.2 under Chapter 12
|
||||
constexpr OperandDesc _A = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc _B = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc _BD = OperandDesc{Mask(16, 29), {0, true}};
|
||||
constexpr OperandDesc _BI = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc _BO = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc _C = OperandDesc{Mask(21, 25), {6, false}};
|
||||
constexpr OperandDesc _Crba = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc _Crbb = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc _Crbd = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc _Crfd = OperandDesc{Mask(6, 8), {23, false}};
|
||||
constexpr OperandDesc _Crfs = OperandDesc{Mask(11, 13), {18, false}};
|
||||
constexpr OperandDesc _CRM = OperandDesc{Mask(12, 19), {12, false}};
|
||||
constexpr OperandDesc _D = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc _FM = OperandDesc{Mask(7, 14), {17, false}};
|
||||
constexpr OperandDesc _W1 = OperandDesc{Mask(16, 16), {15, false}};
|
||||
constexpr OperandDesc _W2 = OperandDesc{Mask(21, 21), {10, false}};
|
||||
constexpr OperandDesc _IMM = OperandDesc{Mask(16, 19), {12, false}};
|
||||
constexpr OperandDesc _L = OperandDesc{Mask(10, 10), {21, false}};
|
||||
constexpr OperandDesc _LI = OperandDesc{Mask(6, 29), {0, true}};
|
||||
constexpr OperandDesc _MB = OperandDesc{Mask(21, 25), {6, false}};
|
||||
constexpr OperandDesc _ME = OperandDesc{Mask(26, 30), {1, false}};
|
||||
constexpr OperandDesc _NB = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc _Offd = OperandDesc{Mask(16, 31), {0, true}};
|
||||
constexpr OperandDesc _OffdPs = OperandDesc{Mask(20, 31), {0, true}};
|
||||
constexpr OperandDesc _S = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc _SH = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc _SIMM = OperandDesc{Mask(16, 31), {0, true}};
|
||||
constexpr OperandDesc _SPR = OperandDesc{Mask(11, 20), {11, false}};
|
||||
constexpr OperandDesc _SR = OperandDesc{Mask(12, 15), {16, false}};
|
||||
constexpr OperandDesc _TO = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc _TPR = OperandDesc{Mask(11, 20), {11, false}};
|
||||
constexpr OperandDesc _UIMM = OperandDesc{Mask(16, 31), {0, false}};
|
||||
constexpr OperandDesc _I1 = OperandDesc{Mask(17, 19), {12, false}};
|
||||
constexpr OperandDesc _I2 = OperandDesc{Mask(22, 24), {7, false}};
|
||||
constexpr OperandDesc OpDesc_A = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc OpDesc_B = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_BD = OperandDesc{Mask(16, 29), {0, true}};
|
||||
constexpr OperandDesc OpDesc_BI = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc OpDesc_BO = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_C = OperandDesc{Mask(21, 25), {6, false}};
|
||||
constexpr OperandDesc OpDesc_Crba = OperandDesc{Mask(11, 15), {16, false}};
|
||||
constexpr OperandDesc OpDesc_Crbb = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_Crbd = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_Crfd = OperandDesc{Mask(6, 8), {23, false}};
|
||||
constexpr OperandDesc OpDesc_Crfs = OperandDesc{Mask(11, 13), {18, false}};
|
||||
constexpr OperandDesc OpDesc_CRM = OperandDesc{Mask(12, 19), {12, false}};
|
||||
constexpr OperandDesc OpDesc_D = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_FM = OperandDesc{Mask(7, 14), {17, false}};
|
||||
constexpr OperandDesc OpDesc_W1 = OperandDesc{Mask(16, 16), {15, false}};
|
||||
constexpr OperandDesc OpDesc_W2 = OperandDesc{Mask(21, 21), {10, false}};
|
||||
constexpr OperandDesc OpDesc_IMM = OperandDesc{Mask(16, 19), {12, false}};
|
||||
constexpr OperandDesc OpDesc_L = OperandDesc{Mask(10, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_LI = OperandDesc{Mask(6, 29), {0, true}};
|
||||
constexpr OperandDesc OpDesc_MB = OperandDesc{Mask(21, 25), {6, false}};
|
||||
constexpr OperandDesc OpDesc_ME = OperandDesc{Mask(26, 30), {1, false}};
|
||||
constexpr OperandDesc OpDesc_NB = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_Offd = OperandDesc{Mask(16, 31), {0, true}};
|
||||
constexpr OperandDesc OpDesc_OffdPs = OperandDesc{Mask(20, 31), {0, true}};
|
||||
constexpr OperandDesc OpDesc_S = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_SH = OperandDesc{Mask(16, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_SIMM = OperandDesc{Mask(16, 31), {0, true}};
|
||||
constexpr OperandDesc OpDesc_SPR = OperandDesc{Mask(11, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_SR = OperandDesc{Mask(12, 15), {16, false}};
|
||||
constexpr OperandDesc OpDesc_TO = OperandDesc{Mask(6, 10), {21, false}};
|
||||
constexpr OperandDesc OpDesc_TPR = OperandDesc{Mask(11, 20), {11, false}};
|
||||
constexpr OperandDesc OpDesc_UIMM = OperandDesc{Mask(16, 31), {0, false}};
|
||||
constexpr OperandDesc OpDesc_I1 = OperandDesc{Mask(17, 19), {12, false}};
|
||||
constexpr OperandDesc OpDesc_I2 = OperandDesc{Mask(22, 24), {7, false}};
|
||||
} // namespace
|
||||
|
||||
void OperandList::Insert(size_t before, u32 val)
|
||||
|
@ -675,288 +675,293 @@ extern const CaseInsensitiveDict<ParseInfo, '.', '_', '+', '-'> extended_mnemoni
|
|||
// Defines all basic mnemonics that Broadway/Gekko supports
|
||||
extern const std::array<MnemonicDesc, NUM_MNEMONICS* VARIANT_PERMUTATIONS> mnemonics = {
|
||||
// A-2
|
||||
OERC_MNEMONIC(31, InsertVal(266, 22, 30), _D, _A, _B), // add
|
||||
OERC_MNEMONIC(31, InsertVal(10, 22, 30), _D, _A, _B), // addc
|
||||
OERC_MNEMONIC(31, InsertVal(138, 22, 30), _D, _A, _B), // adde
|
||||
BASIC_MNEMONIC(14, _D, _A, _SIMM), // addi
|
||||
BASIC_MNEMONIC(12, _D, _A, _SIMM), // addic
|
||||
BASIC_MNEMONIC(13, _D, _A, _SIMM), // addic.
|
||||
BASIC_MNEMONIC(15, _D, _A, _SIMM), // addis
|
||||
OERC_MNEMONIC(31, InsertVal(234, 22, 30), _D, _A), // addme
|
||||
OERC_MNEMONIC(31, InsertVal(202, 22, 30), _D, _A), // addze
|
||||
OERC_MNEMONIC(31, InsertVal(491, 22, 30), _D, _A, _B), // divw
|
||||
OERC_MNEMONIC(31, InsertVal(459, 22, 30), _D, _A, _B), // divwu
|
||||
RC_MNEMONIC(31, InsertVal(75, 22, 30), _D, _A, _B), // mulhw
|
||||
RC_MNEMONIC(31, InsertVal(11, 22, 30), _D, _A, _B), // mulhwu
|
||||
BASIC_MNEMONIC(7, _D, _A, _SIMM), // mulli
|
||||
OERC_MNEMONIC(31, InsertVal(235, 22, 30), _D, _A, _B), // mullw
|
||||
OERC_MNEMONIC(31, InsertVal(104, 22, 30), _D, _A), // neg
|
||||
OERC_MNEMONIC(31, InsertVal(40, 22, 30), _D, _A, _B), // subf
|
||||
OERC_MNEMONIC(31, InsertVal(8, 22, 30), _D, _A, _B), // subfc
|
||||
OERC_MNEMONIC(31, InsertVal(136, 22, 30), _D, _A, _B), // subfe
|
||||
BASIC_MNEMONIC(8, _D, _A, _SIMM), // subfic
|
||||
OERC_MNEMONIC(31, InsertVal(232, 22, 30), _D, _A), // subfme
|
||||
OERC_MNEMONIC(31, InsertVal(200, 22, 30), _D, _A), // subfze
|
||||
OERC_MNEMONIC(31, InsertVal(266, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // add
|
||||
OERC_MNEMONIC(31, InsertVal(10, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // addc
|
||||
OERC_MNEMONIC(31, InsertVal(138, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // adde
|
||||
BASIC_MNEMONIC(14, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addi
|
||||
BASIC_MNEMONIC(12, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addic
|
||||
BASIC_MNEMONIC(13, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addic.
|
||||
BASIC_MNEMONIC(15, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addis
|
||||
OERC_MNEMONIC(31, InsertVal(234, 22, 30), OpDesc_D, OpDesc_A), // addme
|
||||
OERC_MNEMONIC(31, InsertVal(202, 22, 30), OpDesc_D, OpDesc_A), // addze
|
||||
OERC_MNEMONIC(31, InsertVal(491, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // divw
|
||||
OERC_MNEMONIC(31, InsertVal(459, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // divwu
|
||||
RC_MNEMONIC(31, InsertVal(75, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mulhw
|
||||
RC_MNEMONIC(31, InsertVal(11, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mulhwu
|
||||
BASIC_MNEMONIC(7, OpDesc_D, OpDesc_A, OpDesc_SIMM), // mulli
|
||||
OERC_MNEMONIC(31, InsertVal(235, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mullw
|
||||
OERC_MNEMONIC(31, InsertVal(104, 22, 30), OpDesc_D, OpDesc_A), // neg
|
||||
OERC_MNEMONIC(31, InsertVal(40, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subf
|
||||
OERC_MNEMONIC(31, InsertVal(8, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subfc
|
||||
OERC_MNEMONIC(31, InsertVal(136, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subfe
|
||||
BASIC_MNEMONIC(8, OpDesc_D, OpDesc_A, OpDesc_SIMM), // subfic
|
||||
OERC_MNEMONIC(31, InsertVal(232, 22, 30), OpDesc_D, OpDesc_A), // subfme
|
||||
OERC_MNEMONIC(31, InsertVal(200, 22, 30), OpDesc_D, OpDesc_A), // subfze
|
||||
|
||||
// A-3
|
||||
MNEMONIC(31, InsertVal(0, 21, 30), _Crfd, _L, _A, _B), // cmp
|
||||
BASIC_MNEMONIC(11, _Crfd, _L, _A, _SIMM), // cmpi
|
||||
MNEMONIC(31, InsertVal(32, 21, 30), _Crfd, _L, _A, _B), // cmpl
|
||||
BASIC_MNEMONIC(10, _Crfd, _L, _A, _UIMM), // cmpli
|
||||
MNEMONIC(31, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_B), // cmp
|
||||
BASIC_MNEMONIC(11, OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_SIMM), // cmpi
|
||||
MNEMONIC(31, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_B), // cmpl
|
||||
BASIC_MNEMONIC(10, OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_UIMM), // cmpli
|
||||
|
||||
// A-4
|
||||
RC_MNEMONIC(31, InsertVal(28, 21, 30), _A, _S, _B), // and
|
||||
RC_MNEMONIC(31, InsertVal(60, 21, 30), _A, _S, _B), // andc
|
||||
BASIC_MNEMONIC(28, _A, _S, _UIMM), // andi.
|
||||
BASIC_MNEMONIC(29, _A, _S, _UIMM), // andis.
|
||||
RC_MNEMONIC(31, InsertVal(26, 21, 30), _A, _S), // cntlzw
|
||||
RC_MNEMONIC(31, InsertVal(284, 21, 30), _A, _S, _B), // eqv
|
||||
RC_MNEMONIC(31, InsertVal(954, 21, 30), _A, _S), // extsb
|
||||
RC_MNEMONIC(31, InsertVal(922, 21, 30), _A, _S), // extsh
|
||||
RC_MNEMONIC(31, InsertVal(476, 21, 30), _A, _S, _B), // nand
|
||||
RC_MNEMONIC(31, InsertVal(124, 21, 30), _A, _S, _B), // nor
|
||||
RC_MNEMONIC(31, InsertVal(444, 21, 30), _A, _S, _B), // or
|
||||
RC_MNEMONIC(31, InsertVal(412, 21, 30), _A, _S, _B), // orc
|
||||
BASIC_MNEMONIC(24, _A, _S, _UIMM), // ori
|
||||
BASIC_MNEMONIC(25, _A, _S, _UIMM), // oris
|
||||
RC_MNEMONIC(31, InsertVal(316, 21, 30), _A, _S, _B), // xor
|
||||
BASIC_MNEMONIC(26, _A, _S, _UIMM), // xori
|
||||
BASIC_MNEMONIC(27, _A, _S, _UIMM), // xoris
|
||||
RC_MNEMONIC(31, InsertVal(28, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // and
|
||||
RC_MNEMONIC(31, InsertVal(60, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // andc
|
||||
BASIC_MNEMONIC(28, OpDesc_A, OpDesc_S, OpDesc_UIMM), // andi.
|
||||
BASIC_MNEMONIC(29, OpDesc_A, OpDesc_S, OpDesc_UIMM), // andis.
|
||||
RC_MNEMONIC(31, InsertVal(26, 21, 30), OpDesc_A, OpDesc_S), // cntlzw
|
||||
RC_MNEMONIC(31, InsertVal(284, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // eqv
|
||||
RC_MNEMONIC(31, InsertVal(954, 21, 30), OpDesc_A, OpDesc_S), // extsb
|
||||
RC_MNEMONIC(31, InsertVal(922, 21, 30), OpDesc_A, OpDesc_S), // extsh
|
||||
RC_MNEMONIC(31, InsertVal(476, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // nand
|
||||
RC_MNEMONIC(31, InsertVal(124, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // nor
|
||||
RC_MNEMONIC(31, InsertVal(444, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // or
|
||||
RC_MNEMONIC(31, InsertVal(412, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // orc
|
||||
BASIC_MNEMONIC(24, OpDesc_A, OpDesc_S, OpDesc_UIMM), // ori
|
||||
BASIC_MNEMONIC(25, OpDesc_A, OpDesc_S, OpDesc_UIMM), // oris
|
||||
RC_MNEMONIC(31, InsertVal(316, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // xor
|
||||
BASIC_MNEMONIC(26, OpDesc_A, OpDesc_S, OpDesc_UIMM), // xori
|
||||
BASIC_MNEMONIC(27, OpDesc_A, OpDesc_S, OpDesc_UIMM), // xoris
|
||||
|
||||
// A-5
|
||||
RC_MNEMONIC(20, 0, _A, _S, _SH, _MB, _ME), // rlwimi
|
||||
RC_MNEMONIC(21, 0, _A, _S, _SH, _MB, _ME), // rlwinm
|
||||
RC_MNEMONIC(23, 0, _A, _S, _B, _MB, _ME), // rlwnm
|
||||
RC_MNEMONIC(20, 0, OpDesc_A, OpDesc_S, OpDesc_SH, OpDesc_MB, OpDesc_ME), // rlwimi
|
||||
RC_MNEMONIC(21, 0, OpDesc_A, OpDesc_S, OpDesc_SH, OpDesc_MB, OpDesc_ME), // rlwinm
|
||||
RC_MNEMONIC(23, 0, OpDesc_A, OpDesc_S, OpDesc_B, OpDesc_MB, OpDesc_ME), // rlwnm
|
||||
|
||||
// A-6
|
||||
RC_MNEMONIC(31, InsertVal(24, 21, 30), _A, _S, _B), // slw
|
||||
RC_MNEMONIC(31, InsertVal(792, 21, 30), _A, _S, _B), // sraw
|
||||
RC_MNEMONIC(31, InsertVal(824, 21, 30), _A, _S, _SH), // srawi
|
||||
RC_MNEMONIC(31, InsertVal(536, 21, 30), _A, _S, _B), // srw
|
||||
RC_MNEMONIC(31, InsertVal(24, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // slw
|
||||
RC_MNEMONIC(31, InsertVal(792, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // sraw
|
||||
RC_MNEMONIC(31, InsertVal(824, 21, 30), OpDesc_A, OpDesc_S, OpDesc_SH), // srawi
|
||||
RC_MNEMONIC(31, InsertVal(536, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // srw
|
||||
|
||||
// A-7
|
||||
RC_MNEMONIC(63, InsertVal(21, 26, 30), _D, _A, _B), // fadd
|
||||
RC_MNEMONIC(59, InsertVal(21, 26, 30), _D, _A, _B), // fadds
|
||||
RC_MNEMONIC(63, InsertVal(18, 26, 30), _D, _A, _B), // fdiv
|
||||
RC_MNEMONIC(59, InsertVal(18, 26, 30), _D, _A, _B), // fdivs
|
||||
RC_MNEMONIC(63, InsertVal(25, 26, 30), _D, _A, _C), // fmul
|
||||
RC_MNEMONIC(59, InsertVal(25, 26, 30), _D, _A, _C), // fmuls
|
||||
RC_MNEMONIC(59, InsertVal(24, 26, 30), _D, _B), // fres
|
||||
RC_MNEMONIC(63, InsertVal(26, 26, 30), _D, _B), // frsqrte
|
||||
RC_MNEMONIC(63, InsertVal(20, 26, 30), _D, _A, _B), // fsub
|
||||
RC_MNEMONIC(59, InsertVal(20, 26, 30), _D, _A, _B), // fsubs
|
||||
RC_MNEMONIC(63, InsertVal(23, 26, 30), _D, _A, _C, _B), // fsel
|
||||
RC_MNEMONIC(63, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fadd
|
||||
RC_MNEMONIC(59, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fadds
|
||||
RC_MNEMONIC(63, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fdiv
|
||||
RC_MNEMONIC(59, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fdivs
|
||||
RC_MNEMONIC(63, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // fmul
|
||||
RC_MNEMONIC(59, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // fmuls
|
||||
RC_MNEMONIC(59, InsertVal(24, 26, 30), OpDesc_D, OpDesc_B), // fres
|
||||
RC_MNEMONIC(63, InsertVal(26, 26, 30), OpDesc_D, OpDesc_B), // frsqrte
|
||||
RC_MNEMONIC(63, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fsub
|
||||
RC_MNEMONIC(59, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fsubs
|
||||
RC_MNEMONIC(63, InsertVal(23, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fsel
|
||||
|
||||
// A-8
|
||||
RC_MNEMONIC(63, InsertVal(29, 26, 30), _D, _A, _C, _B), // fmadd
|
||||
RC_MNEMONIC(59, InsertVal(29, 26, 30), _D, _A, _C, _B), // fmadds
|
||||
RC_MNEMONIC(63, InsertVal(28, 26, 30), _D, _A, _C, _B), // fmsub
|
||||
RC_MNEMONIC(59, InsertVal(28, 26, 30), _D, _A, _C, _B), // fmsubs
|
||||
RC_MNEMONIC(63, InsertVal(31, 26, 30), _D, _A, _C, _B), // fnmadd
|
||||
RC_MNEMONIC(59, InsertVal(31, 26, 30), _D, _A, _C, _B), // fnmadds
|
||||
RC_MNEMONIC(63, InsertVal(30, 26, 30), _D, _A, _C, _B), // fnmsub
|
||||
RC_MNEMONIC(59, InsertVal(30, 26, 30), _D, _A, _C, _B), // fnmsubs
|
||||
RC_MNEMONIC(63, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmadd
|
||||
RC_MNEMONIC(59, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmadds
|
||||
RC_MNEMONIC(63, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmsub
|
||||
RC_MNEMONIC(59, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmsubs
|
||||
RC_MNEMONIC(63, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmadd
|
||||
RC_MNEMONIC(59, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmadds
|
||||
RC_MNEMONIC(63, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmsub
|
||||
RC_MNEMONIC(59, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmsubs
|
||||
|
||||
// A-9
|
||||
RC_MNEMONIC(63, InsertVal(14, 21, 30), _D, _B), // fctiw
|
||||
RC_MNEMONIC(63, InsertVal(15, 21, 30), _D, _B), // fctiwz
|
||||
RC_MNEMONIC(63, InsertVal(12, 21, 30), _D, _B), // frsp
|
||||
RC_MNEMONIC(63, InsertVal(14, 21, 30), OpDesc_D, OpDesc_B), // fctiw
|
||||
RC_MNEMONIC(63, InsertVal(15, 21, 30), OpDesc_D, OpDesc_B), // fctiwz
|
||||
RC_MNEMONIC(63, InsertVal(12, 21, 30), OpDesc_D, OpDesc_B), // frsp
|
||||
|
||||
// A-10
|
||||
MNEMONIC(63, InsertVal(32, 21, 30), _Crfd, _A, _B), // fcmpo
|
||||
MNEMONIC(63, InsertVal(0, 21, 30), _Crfd, _A, _B), // fcmpu
|
||||
MNEMONIC(63, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // fcmpo
|
||||
MNEMONIC(63, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // fcmpu
|
||||
|
||||
// A-11
|
||||
MNEMONIC(63, InsertVal(64, 21, 30), _Crfd, _Crfs), // mcrfs
|
||||
RC_MNEMONIC(63, InsertVal(583, 21, 30), _D), // mffs
|
||||
RC_MNEMONIC(63, InsertVal(70, 21, 30), _Crbd), // mtfsb0
|
||||
RC_MNEMONIC(63, InsertVal(38, 21, 30), _Crbd), // mtfsb1
|
||||
RC_MNEMONIC(63, InsertVal(711, 21, 30), _FM, _B), // mtfsf
|
||||
RC_MNEMONIC(63, InsertVal(134, 21, 30), _Crfd, _IMM), // mtfsfi
|
||||
MNEMONIC(63, InsertVal(64, 21, 30), OpDesc_Crfd, OpDesc_Crfs), // mcrfs
|
||||
RC_MNEMONIC(63, InsertVal(583, 21, 30), OpDesc_D), // mffs
|
||||
RC_MNEMONIC(63, InsertVal(70, 21, 30), OpDesc_Crbd), // mtfsb0
|
||||
RC_MNEMONIC(63, InsertVal(38, 21, 30), OpDesc_Crbd), // mtfsb1
|
||||
RC_MNEMONIC(63, InsertVal(711, 21, 30), OpDesc_FM, OpDesc_B), // mtfsf
|
||||
RC_MNEMONIC(63, InsertVal(134, 21, 30), OpDesc_Crfd, OpDesc_IMM), // mtfsfi
|
||||
|
||||
// A-12
|
||||
BASIC_MNEMONIC(34, _D, _Offd, _A), // lbz
|
||||
BASIC_MNEMONIC(35, _D, _Offd, _A), // lbzu
|
||||
MNEMONIC(31, InsertVal(119, 21, 30), _D, _A, _B), // lbzux
|
||||
MNEMONIC(31, InsertVal(87, 21, 30), _D, _A, _B), // lbzx
|
||||
BASIC_MNEMONIC(42, _D, _Offd, _A), // lha
|
||||
BASIC_MNEMONIC(43, _D, _Offd, _A), // lhau
|
||||
MNEMONIC(31, InsertVal(375, 21, 30), _D, _A, _B), // lhaux
|
||||
MNEMONIC(31, InsertVal(343, 21, 30), _D, _A, _B), // lhax
|
||||
BASIC_MNEMONIC(40, _D, _Offd, _A), // lhz
|
||||
BASIC_MNEMONIC(41, _D, _Offd, _A), // lhzu
|
||||
MNEMONIC(31, InsertVal(311, 21, 30), _D, _A, _B), // lhzux
|
||||
MNEMONIC(31, InsertVal(279, 21, 30), _D, _A, _B), // lhzx
|
||||
BASIC_MNEMONIC(32, _D, _Offd, _A), // lwz
|
||||
BASIC_MNEMONIC(33, _D, _Offd, _A), // lwzu
|
||||
MNEMONIC(31, InsertVal(55, 21, 30), _D, _A, _B), // lwzux
|
||||
MNEMONIC(31, InsertVal(23, 21, 30), _D, _A, _B), // lwzx
|
||||
BASIC_MNEMONIC(34, OpDesc_D, OpDesc_Offd, OpDesc_A), // lbz
|
||||
BASIC_MNEMONIC(35, OpDesc_D, OpDesc_Offd, OpDesc_A), // lbzu
|
||||
MNEMONIC(31, InsertVal(119, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lbzux
|
||||
MNEMONIC(31, InsertVal(87, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lbzx
|
||||
BASIC_MNEMONIC(42, OpDesc_D, OpDesc_Offd, OpDesc_A), // lha
|
||||
BASIC_MNEMONIC(43, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhau
|
||||
MNEMONIC(31, InsertVal(375, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhaux
|
||||
MNEMONIC(31, InsertVal(343, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhax
|
||||
BASIC_MNEMONIC(40, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhz
|
||||
BASIC_MNEMONIC(41, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhzu
|
||||
MNEMONIC(31, InsertVal(311, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhzux
|
||||
MNEMONIC(31, InsertVal(279, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhzx
|
||||
BASIC_MNEMONIC(32, OpDesc_D, OpDesc_Offd, OpDesc_A), // lwz
|
||||
BASIC_MNEMONIC(33, OpDesc_D, OpDesc_Offd, OpDesc_A), // lwzu
|
||||
MNEMONIC(31, InsertVal(55, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwzux
|
||||
MNEMONIC(31, InsertVal(23, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwzx
|
||||
|
||||
// A-13
|
||||
BASIC_MNEMONIC(38, _S, _Offd, _A), // stb
|
||||
BASIC_MNEMONIC(39, _S, _Offd, _A), // stbu
|
||||
MNEMONIC(31, InsertVal(247, 21, 30), _S, _A, _B), // stbux
|
||||
MNEMONIC(31, InsertVal(215, 21, 30), _S, _A, _B), // stbx
|
||||
BASIC_MNEMONIC(44, _S, _Offd, _A), // sth
|
||||
BASIC_MNEMONIC(45, _S, _Offd, _A), // sthu
|
||||
MNEMONIC(31, InsertVal(439, 21, 30), _S, _A, _B), // sthux
|
||||
MNEMONIC(31, InsertVal(407, 21, 30), _S, _A, _B), // sthx
|
||||
BASIC_MNEMONIC(36, _S, _Offd, _A), // stw
|
||||
BASIC_MNEMONIC(37, _S, _Offd, _A), // stwu
|
||||
MNEMONIC(31, InsertVal(183, 21, 30), _S, _A, _B), // stwux
|
||||
MNEMONIC(31, InsertVal(151, 21, 30), _S, _A, _B), // stwx
|
||||
BASIC_MNEMONIC(38, OpDesc_S, OpDesc_Offd, OpDesc_A), // stb
|
||||
BASIC_MNEMONIC(39, OpDesc_S, OpDesc_Offd, OpDesc_A), // stbu
|
||||
MNEMONIC(31, InsertVal(247, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stbux
|
||||
MNEMONIC(31, InsertVal(215, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stbx
|
||||
BASIC_MNEMONIC(44, OpDesc_S, OpDesc_Offd, OpDesc_A), // sth
|
||||
BASIC_MNEMONIC(45, OpDesc_S, OpDesc_Offd, OpDesc_A), // sthu
|
||||
MNEMONIC(31, InsertVal(439, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthux
|
||||
MNEMONIC(31, InsertVal(407, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthx
|
||||
BASIC_MNEMONIC(36, OpDesc_S, OpDesc_Offd, OpDesc_A), // stw
|
||||
BASIC_MNEMONIC(37, OpDesc_S, OpDesc_Offd, OpDesc_A), // stwu
|
||||
MNEMONIC(31, InsertVal(183, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwux
|
||||
MNEMONIC(31, InsertVal(151, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwx
|
||||
|
||||
// A-14
|
||||
MNEMONIC(31, InsertVal(790, 21, 30), _D, _A, _B), // lhbrx
|
||||
MNEMONIC(31, InsertVal(534, 21, 30), _D, _A, _B), // lwbrx
|
||||
MNEMONIC(31, InsertVal(918, 21, 30), _S, _A, _B), // sthbrx
|
||||
MNEMONIC(31, InsertVal(662, 21, 30), _S, _A, _B), // stwbrx
|
||||
MNEMONIC(31, InsertVal(790, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhbrx
|
||||
MNEMONIC(31, InsertVal(534, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwbrx
|
||||
MNEMONIC(31, InsertVal(918, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthbrx
|
||||
MNEMONIC(31, InsertVal(662, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwbrx
|
||||
|
||||
// A-15
|
||||
BASIC_MNEMONIC(46, _D, _Offd, _A), // lmw
|
||||
BASIC_MNEMONIC(47, _S, _Offd, _A), // stmw
|
||||
BASIC_MNEMONIC(46, OpDesc_D, OpDesc_Offd, OpDesc_A), // lmw
|
||||
BASIC_MNEMONIC(47, OpDesc_S, OpDesc_Offd, OpDesc_A), // stmw
|
||||
|
||||
// A-16
|
||||
MNEMONIC(31, InsertVal(597, 21, 30), _D, _A, _NB), // lswi
|
||||
MNEMONIC(31, InsertVal(533, 21, 30), _D, _A, _B), // lswx
|
||||
MNEMONIC(31, InsertVal(725, 21, 30), _S, _A, _NB), // stswi
|
||||
MNEMONIC(31, InsertVal(661, 21, 30), _S, _A, _B), // stswx
|
||||
MNEMONIC(31, InsertVal(597, 21, 30), OpDesc_D, OpDesc_A, OpDesc_NB), // lswi
|
||||
MNEMONIC(31, InsertVal(533, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lswx
|
||||
MNEMONIC(31, InsertVal(725, 21, 30), OpDesc_S, OpDesc_A, OpDesc_NB), // stswi
|
||||
MNEMONIC(31, InsertVal(661, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stswx
|
||||
|
||||
// A-17
|
||||
MNEMONIC(31, InsertVal(854, 21, 30)), // eieio
|
||||
MNEMONIC(19, InsertVal(150, 21, 30)), // isync
|
||||
MNEMONIC(31, InsertVal(20, 21, 30), _D, _A, _B), // lwarx
|
||||
MNEMONIC(31, InsertVal(150, 21, 30) | InsertVal(1, 31, 31), _S, _A, _B), // stwcx.
|
||||
MNEMONIC(31, InsertVal(598, 21, 30)), // sync
|
||||
MNEMONIC(31, InsertVal(854, 21, 30)), // eieio
|
||||
MNEMONIC(19, InsertVal(150, 21, 30)), // isync
|
||||
MNEMONIC(31, InsertVal(20, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwarx
|
||||
MNEMONIC(31, InsertVal(150, 21, 30) | InsertVal(1, 31, 31), OpDesc_S, OpDesc_A,
|
||||
OpDesc_B), // stwcx.
|
||||
MNEMONIC(31, InsertVal(598, 21, 30)), // sync
|
||||
|
||||
// A-18
|
||||
BASIC_MNEMONIC(50, _D, _Offd, _A), // lfd
|
||||
BASIC_MNEMONIC(51, _D, _Offd, _A), // lfdu
|
||||
MNEMONIC(31, InsertVal(631, 21, 30), _D, _A, _B), // lfdux
|
||||
MNEMONIC(31, InsertVal(599, 21, 30), _D, _A, _B), // lfdx
|
||||
BASIC_MNEMONIC(48, _D, _Offd, _A), // lfs
|
||||
BASIC_MNEMONIC(49, _D, _Offd, _A), // lfsu
|
||||
MNEMONIC(31, InsertVal(567, 21, 30), _D, _A, _B), // lfsux
|
||||
MNEMONIC(31, InsertVal(535, 21, 30), _D, _A, _B), // lfsx
|
||||
BASIC_MNEMONIC(50, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfd
|
||||
BASIC_MNEMONIC(51, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfdu
|
||||
MNEMONIC(31, InsertVal(631, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfdux
|
||||
MNEMONIC(31, InsertVal(599, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfdx
|
||||
BASIC_MNEMONIC(48, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfs
|
||||
BASIC_MNEMONIC(49, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfsu
|
||||
MNEMONIC(31, InsertVal(567, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfsux
|
||||
MNEMONIC(31, InsertVal(535, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfsx
|
||||
|
||||
// A-19
|
||||
BASIC_MNEMONIC(54, _S, _Offd, _A), // stfd
|
||||
BASIC_MNEMONIC(55, _S, _Offd, _A), // stfdu
|
||||
MNEMONIC(31, InsertVal(759, 21, 30), _S, _A, _B), // stfdux
|
||||
MNEMONIC(31, InsertVal(727, 21, 30), _S, _A, _B), // stfdx
|
||||
MNEMONIC(31, InsertVal(983, 21, 30), _S, _A, _B), // stfiwx
|
||||
BASIC_MNEMONIC(52, _S, _Offd, _A), // stfs
|
||||
BASIC_MNEMONIC(53, _S, _Offd, _A), // stfsu
|
||||
MNEMONIC(31, InsertVal(695, 21, 30), _S, _A, _B), // stfsux
|
||||
MNEMONIC(31, InsertVal(663, 21, 30), _S, _A, _B), // stfsx
|
||||
BASIC_MNEMONIC(54, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfd
|
||||
BASIC_MNEMONIC(55, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfdu
|
||||
MNEMONIC(31, InsertVal(759, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfdux
|
||||
MNEMONIC(31, InsertVal(727, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfdx
|
||||
MNEMONIC(31, InsertVal(983, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfiwx
|
||||
BASIC_MNEMONIC(52, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfs
|
||||
BASIC_MNEMONIC(53, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfsu
|
||||
MNEMONIC(31, InsertVal(695, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfsux
|
||||
MNEMONIC(31, InsertVal(663, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfsx
|
||||
|
||||
// A-20
|
||||
RC_MNEMONIC(63, InsertVal(264, 21, 30), _D, _B), // fabs
|
||||
RC_MNEMONIC(63, InsertVal(72, 21, 30), _D, _B), // fmr
|
||||
RC_MNEMONIC(63, InsertVal(136, 21, 30), _D, _B), // fnabs
|
||||
RC_MNEMONIC(63, InsertVal(40, 21, 30), _D, _B), // fneg
|
||||
RC_MNEMONIC(63, InsertVal(264, 21, 30), OpDesc_D, OpDesc_B), // fabs
|
||||
RC_MNEMONIC(63, InsertVal(72, 21, 30), OpDesc_D, OpDesc_B), // fmr
|
||||
RC_MNEMONIC(63, InsertVal(136, 21, 30), OpDesc_D, OpDesc_B), // fnabs
|
||||
RC_MNEMONIC(63, InsertVal(40, 21, 30), OpDesc_D, OpDesc_B), // fneg
|
||||
|
||||
// A-21
|
||||
AALK_MNEMONIC(18, 0, _LI), // b
|
||||
AALK_MNEMONIC(16, 0, _BO, _BI, _BD), // bc
|
||||
LK_MNEMONIC(19, InsertVal(528, 21, 30), _BO, _BI), // bcctr
|
||||
LK_MNEMONIC(19, InsertVal(16, 21, 30), _BO, _BI), // bclr
|
||||
AALK_MNEMONIC(18, 0, OpDesc_LI), // b
|
||||
AALK_MNEMONIC(16, 0, OpDesc_BO, OpDesc_BI, OpDesc_BD), // bc
|
||||
LK_MNEMONIC(19, InsertVal(528, 21, 30), OpDesc_BO, OpDesc_BI), // bcctr
|
||||
LK_MNEMONIC(19, InsertVal(16, 21, 30), OpDesc_BO, OpDesc_BI), // bclr
|
||||
|
||||
// A-22
|
||||
MNEMONIC(19, InsertVal(257, 21, 30), _Crbd, _Crba, _Crbb), // crand
|
||||
MNEMONIC(19, InsertVal(129, 21, 30), _Crbd, _Crba, _Crbb), // crandc
|
||||
MNEMONIC(19, InsertVal(289, 21, 30), _Crbd, _Crba, _Crbb), // creqv
|
||||
MNEMONIC(19, InsertVal(225, 21, 30), _Crbd, _Crba, _Crbb), // crnand
|
||||
MNEMONIC(19, InsertVal(33, 21, 30), _Crbd, _Crba, _Crbb), // crnor
|
||||
MNEMONIC(19, InsertVal(449, 21, 30), _Crbd, _Crba, _Crbb), // cror
|
||||
MNEMONIC(19, InsertVal(417, 21, 30), _Crbd, _Crba, _Crbb), // crorc
|
||||
MNEMONIC(19, InsertVal(193, 21, 30), _Crbd, _Crba, _Crbb), // crxor
|
||||
MNEMONIC(19, InsertVal(0, 21, 30), _Crfd, _Crfs), // mcrf
|
||||
MNEMONIC(19, InsertVal(257, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crand
|
||||
MNEMONIC(19, InsertVal(129, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crandc
|
||||
MNEMONIC(19, InsertVal(289, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // creqv
|
||||
MNEMONIC(19, InsertVal(225, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crnand
|
||||
MNEMONIC(19, InsertVal(33, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crnor
|
||||
MNEMONIC(19, InsertVal(449, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // cror
|
||||
MNEMONIC(19, InsertVal(417, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crorc
|
||||
MNEMONIC(19, InsertVal(193, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crxor
|
||||
MNEMONIC(19, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_Crfs), // mcrf
|
||||
|
||||
// A-23
|
||||
MNEMONIC(19, InsertVal(50, 21, 30)), // rfi
|
||||
MNEMONIC(17, InsertVal(1, 30, 30)), // sc
|
||||
|
||||
// A-24
|
||||
MNEMONIC(31, InsertVal(4, 21, 30), _TO, _A, _B), // tw
|
||||
BASIC_MNEMONIC(3, _TO, _A, _SIMM), // twi
|
||||
MNEMONIC(31, InsertVal(4, 21, 30), OpDesc_TO, OpDesc_A, OpDesc_B), // tw
|
||||
BASIC_MNEMONIC(3, OpDesc_TO, OpDesc_A, OpDesc_SIMM), // twi
|
||||
|
||||
// A-25
|
||||
MNEMONIC(31, InsertVal(512, 21, 30), _Crfd), // mcrxr
|
||||
MNEMONIC(31, InsertVal(19, 21, 30), _D), // mfcr
|
||||
MNEMONIC(31, InsertVal(83, 21, 30), _D), // mfmsr
|
||||
MNEMONIC(31, InsertVal(339, 21, 30), _D, _SPR), // mfspr
|
||||
MNEMONIC(31, InsertVal(371, 21, 30), _D, _TPR), // mftb
|
||||
MNEMONIC(31, InsertVal(144, 21, 30), _CRM, _S), // mtcrf
|
||||
MNEMONIC(31, InsertVal(146, 21, 30), _S), // mtmsr
|
||||
MNEMONIC(31, InsertVal(467, 21, 30), _SPR, _D), // mtspr
|
||||
MNEMONIC(31, InsertVal(512, 21, 30), OpDesc_Crfd), // mcrxr
|
||||
MNEMONIC(31, InsertVal(19, 21, 30), OpDesc_D), // mfcr
|
||||
MNEMONIC(31, InsertVal(83, 21, 30), OpDesc_D), // mfmsr
|
||||
MNEMONIC(31, InsertVal(339, 21, 30), OpDesc_D, OpDesc_SPR), // mfspr
|
||||
MNEMONIC(31, InsertVal(371, 21, 30), OpDesc_D, OpDesc_TPR), // mftb
|
||||
MNEMONIC(31, InsertVal(144, 21, 30), OpDesc_CRM, OpDesc_S), // mtcrf
|
||||
MNEMONIC(31, InsertVal(146, 21, 30), OpDesc_S), // mtmsr
|
||||
MNEMONIC(31, InsertVal(467, 21, 30), OpDesc_SPR, OpDesc_D), // mtspr
|
||||
|
||||
// A-26
|
||||
MNEMONIC(31, InsertVal(86, 21, 30), _A, _B), // dcbf
|
||||
MNEMONIC(31, InsertVal(470, 21, 30), _A, _B), // dcbi
|
||||
MNEMONIC(31, InsertVal(54, 21, 30), _A, _B), // dcbst
|
||||
MNEMONIC(31, InsertVal(278, 21, 30), _A, _B), // dcbt
|
||||
MNEMONIC(31, InsertVal(246, 21, 30), _A, _B), // dcbtst
|
||||
MNEMONIC(31, InsertVal(1014, 21, 30), _A, _B), // dcbz
|
||||
MNEMONIC(31, InsertVal(982, 21, 30), _A, _B), // icbi
|
||||
MNEMONIC(31, InsertVal(86, 21, 30), OpDesc_A, OpDesc_B), // dcbf
|
||||
MNEMONIC(31, InsertVal(470, 21, 30), OpDesc_A, OpDesc_B), // dcbi
|
||||
MNEMONIC(31, InsertVal(54, 21, 30), OpDesc_A, OpDesc_B), // dcbst
|
||||
MNEMONIC(31, InsertVal(278, 21, 30), OpDesc_A, OpDesc_B), // dcbt
|
||||
MNEMONIC(31, InsertVal(246, 21, 30), OpDesc_A, OpDesc_B), // dcbtst
|
||||
MNEMONIC(31, InsertVal(1014, 21, 30), OpDesc_A, OpDesc_B), // dcbz
|
||||
MNEMONIC(31, InsertVal(982, 21, 30), OpDesc_A, OpDesc_B), // icbi
|
||||
|
||||
// A-27
|
||||
MNEMONIC(31, InsertVal(595, 21, 30), _D, _SR), // mfsr
|
||||
MNEMONIC(31, InsertVal(659, 21, 30), _D, _B), // mfsrin
|
||||
MNEMONIC(31, InsertVal(210, 21, 30), _SR, _S), // mtsr
|
||||
MNEMONIC(31, InsertVal(242, 21, 30), _S, _B), // mtsrin
|
||||
MNEMONIC(31, InsertVal(595, 21, 30), OpDesc_D, OpDesc_SR), // mfsr
|
||||
MNEMONIC(31, InsertVal(659, 21, 30), OpDesc_D, OpDesc_B), // mfsrin
|
||||
MNEMONIC(31, InsertVal(210, 21, 30), OpDesc_SR, OpDesc_S), // mtsr
|
||||
MNEMONIC(31, InsertVal(242, 21, 30), OpDesc_S, OpDesc_B), // mtsrin
|
||||
|
||||
// A-28
|
||||
MNEMONIC(31, InsertVal(306, 21, 30), _B), // tlbie
|
||||
MNEMONIC(31, InsertVal(566, 21, 30)), // tlbsync
|
||||
MNEMONIC(31, InsertVal(306, 21, 30), OpDesc_B), // tlbie
|
||||
MNEMONIC(31, InsertVal(566, 21, 30)), // tlbsync
|
||||
|
||||
// A-29
|
||||
MNEMONIC(31, InsertVal(310, 21, 30), _D, _A, _B), // eciwx
|
||||
MNEMONIC(31, InsertVal(438, 21, 30), _S, _A, _B), // ecowx
|
||||
MNEMONIC(31, InsertVal(310, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // eciwx
|
||||
MNEMONIC(31, InsertVal(438, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // ecowx
|
||||
|
||||
// A-30
|
||||
MNEMONIC(4, InsertVal(6, 25, 30), _D, _A, _B, _W2, _I2), // psq_lx
|
||||
MNEMONIC(4, InsertVal(7, 25, 30), _S, _A, _B, _W2, _I2), // psq_stx
|
||||
MNEMONIC(4, InsertVal(38, 25, 30), _D, _A, _B, _W2, _I2), // psq_lux
|
||||
MNEMONIC(4, InsertVal(39, 25, 30), _S, _A, _B, _W2, _I2), // psq_stux
|
||||
BASIC_MNEMONIC(56, _D, _OffdPs, _A, _W1, _I1), // psq_l
|
||||
BASIC_MNEMONIC(57, _D, _OffdPs, _A, _W1, _I1), // psq_lu
|
||||
BASIC_MNEMONIC(60, _S, _OffdPs, _A, _W1, _I1), // psq_st
|
||||
BASIC_MNEMONIC(61, _S, _OffdPs, _A, _W1, _I1), // psq_stu
|
||||
MNEMONIC(4, InsertVal(6, 25, 30), OpDesc_D, OpDesc_A, OpDesc_B, OpDesc_W2,
|
||||
OpDesc_I2), // psq_lx
|
||||
MNEMONIC(4, InsertVal(7, 25, 30), OpDesc_S, OpDesc_A, OpDesc_B, OpDesc_W2,
|
||||
OpDesc_I2), // psq_stx
|
||||
MNEMONIC(4, InsertVal(38, 25, 30), OpDesc_D, OpDesc_A, OpDesc_B, OpDesc_W2,
|
||||
OpDesc_I2), // psq_lux
|
||||
MNEMONIC(4, InsertVal(39, 25, 30), OpDesc_S, OpDesc_A, OpDesc_B, OpDesc_W2,
|
||||
OpDesc_I2), // psq_stux
|
||||
BASIC_MNEMONIC(56, OpDesc_D, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_l
|
||||
BASIC_MNEMONIC(57, OpDesc_D, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_lu
|
||||
BASIC_MNEMONIC(60, OpDesc_S, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_st
|
||||
BASIC_MNEMONIC(61, OpDesc_S, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_stu
|
||||
|
||||
// A-31
|
||||
RC_MNEMONIC(4, InsertVal(18, 26, 30), _D, _A, _B), // ps_div
|
||||
RC_MNEMONIC(4, InsertVal(20, 26, 30), _D, _A, _B), // ps_sub
|
||||
RC_MNEMONIC(4, InsertVal(21, 26, 30), _D, _A, _B), // ps_add
|
||||
RC_MNEMONIC(4, InsertVal(23, 26, 30), _D, _A, _C, _B), // ps_sel
|
||||
RC_MNEMONIC(4, InsertVal(24, 26, 30), _D, _B), // ps_res
|
||||
RC_MNEMONIC(4, InsertVal(25, 26, 30), _D, _A, _C), // ps_mul
|
||||
RC_MNEMONIC(4, InsertVal(26, 26, 30), _D, _B), // ps_rsqrte
|
||||
RC_MNEMONIC(4, InsertVal(28, 26, 30), _D, _A, _C, _B), // ps_msub
|
||||
RC_MNEMONIC(4, InsertVal(29, 26, 30), _D, _A, _C, _B), // ps_madd
|
||||
RC_MNEMONIC(4, InsertVal(30, 26, 30), _D, _A, _C, _B), // ps_nmsub
|
||||
RC_MNEMONIC(4, InsertVal(31, 26, 30), _D, _A, _C, _B), // ps_nmadd
|
||||
RC_MNEMONIC(4, InsertVal(40, 21, 30), _D, _B), // ps_neg
|
||||
RC_MNEMONIC(4, InsertVal(72, 21, 30), _D, _B), // ps_mr
|
||||
RC_MNEMONIC(4, InsertVal(136, 21, 30), _D, _B), // ps_nabs
|
||||
RC_MNEMONIC(4, InsertVal(264, 21, 30), _D, _B), // ps_abs
|
||||
RC_MNEMONIC(4, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_div
|
||||
RC_MNEMONIC(4, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_sub
|
||||
RC_MNEMONIC(4, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_add
|
||||
RC_MNEMONIC(4, InsertVal(23, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sel
|
||||
RC_MNEMONIC(4, InsertVal(24, 26, 30), OpDesc_D, OpDesc_B), // ps_res
|
||||
RC_MNEMONIC(4, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_mul
|
||||
RC_MNEMONIC(4, InsertVal(26, 26, 30), OpDesc_D, OpDesc_B), // ps_rsqrte
|
||||
RC_MNEMONIC(4, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_msub
|
||||
RC_MNEMONIC(4, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madd
|
||||
RC_MNEMONIC(4, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_nmsub
|
||||
RC_MNEMONIC(4, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_nmadd
|
||||
RC_MNEMONIC(4, InsertVal(40, 21, 30), OpDesc_D, OpDesc_B), // ps_neg
|
||||
RC_MNEMONIC(4, InsertVal(72, 21, 30), OpDesc_D, OpDesc_B), // ps_mr
|
||||
RC_MNEMONIC(4, InsertVal(136, 21, 30), OpDesc_D, OpDesc_B), // ps_nabs
|
||||
RC_MNEMONIC(4, InsertVal(264, 21, 30), OpDesc_D, OpDesc_B), // ps_abs
|
||||
|
||||
// A-32
|
||||
RC_MNEMONIC(4, InsertVal(10, 26, 30), _D, _A, _C, _B), // ps_sum0
|
||||
RC_MNEMONIC(4, InsertVal(11, 26, 30), _D, _A, _C, _B), // ps_sum1
|
||||
RC_MNEMONIC(4, InsertVal(12, 26, 30), _D, _A, _C), // ps_muls0
|
||||
RC_MNEMONIC(4, InsertVal(13, 26, 30), _D, _A, _C), // ps_muls1
|
||||
RC_MNEMONIC(4, InsertVal(14, 26, 30), _D, _A, _C, _B), // ps_madds0
|
||||
RC_MNEMONIC(4, InsertVal(15, 26, 30), _D, _A, _C, _B), // ps_madds1
|
||||
MNEMONIC(4, InsertVal(0, 21, 30), _Crfd, _A, _B), // ps_cmpu0
|
||||
MNEMONIC(4, InsertVal(32, 21, 30), _Crfd, _A, _B), // ps_cmpo0
|
||||
MNEMONIC(4, InsertVal(64, 21, 30), _Crfd, _A, _B), // ps_cmpu1
|
||||
MNEMONIC(4, InsertVal(96, 21, 30), _Crfd, _A, _B), // ps_cmpo1
|
||||
RC_MNEMONIC(4, InsertVal(528, 21, 30), _D, _A, _B), // ps_merge00
|
||||
RC_MNEMONIC(4, InsertVal(560, 21, 30), _D, _A, _B), // ps_merge01
|
||||
RC_MNEMONIC(4, InsertVal(592, 21, 30), _D, _A, _B), // ps_merge10
|
||||
RC_MNEMONIC(4, InsertVal(624, 21, 30), _D, _A, _B), // ps_merge11
|
||||
MNEMONIC(4, InsertVal(1014, 21, 30), _A, _B), // dcbz_l
|
||||
RC_MNEMONIC(4, InsertVal(10, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sum0
|
||||
RC_MNEMONIC(4, InsertVal(11, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sum1
|
||||
RC_MNEMONIC(4, InsertVal(12, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_muls0
|
||||
RC_MNEMONIC(4, InsertVal(13, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_muls1
|
||||
RC_MNEMONIC(4, InsertVal(14, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madds0
|
||||
RC_MNEMONIC(4, InsertVal(15, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madds1
|
||||
MNEMONIC(4, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpu0
|
||||
MNEMONIC(4, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpo0
|
||||
MNEMONIC(4, InsertVal(64, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpu1
|
||||
MNEMONIC(4, InsertVal(96, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpo1
|
||||
RC_MNEMONIC(4, InsertVal(528, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge00
|
||||
RC_MNEMONIC(4, InsertVal(560, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge01
|
||||
RC_MNEMONIC(4, InsertVal(592, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge10
|
||||
RC_MNEMONIC(4, InsertVal(624, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge11
|
||||
MNEMONIC(4, InsertVal(1014, 21, 30), OpDesc_A, OpDesc_B), // dcbz_l
|
||||
};
|
||||
|
||||
namespace
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Common/Assembler/GekkoLexer.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
|
@ -181,6 +182,11 @@ std::optional<T> EvalIntegral(TokenType tp, std::string_view val)
|
|||
case TokenType::BinaryLit:
|
||||
return std::accumulate(val.begin() + 2, val.end(), T{0}, bin_step);
|
||||
case TokenType::GPR:
|
||||
if (CaseInsensitiveEquals(val, "sp"))
|
||||
return T{1};
|
||||
if (CaseInsensitiveEquals(val, "rtoc"))
|
||||
return T{2};
|
||||
[[fallthrough]];
|
||||
case TokenType::FPR:
|
||||
return std::accumulate(val.begin() + 1, val.end(), T{0}, dec_step);
|
||||
case TokenType::CRField:
|
||||
|
@ -643,50 +649,43 @@ TokenType Lexer::ClassifyAlnum() const
|
|||
|
||||
if (rn[0] == '3')
|
||||
{
|
||||
return rn[1] <= '2';
|
||||
return rn[1] < '2';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
constexpr auto eq_nocase = [](std::string_view str, std::string_view lwr) {
|
||||
auto it_l = str.cbegin(), it_r = lwr.cbegin();
|
||||
for (; it_l != str.cend() && it_r != lwr.cend(); it_l++, it_r++)
|
||||
{
|
||||
if (std::tolower(*it_l) != *it_r)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return it_l == str.end() && it_r == lwr.end();
|
||||
};
|
||||
|
||||
if (std::tolower(alnum[0]) == 'r' && valid_regnum(alnum.substr(1)))
|
||||
{
|
||||
return TokenType::GPR;
|
||||
}
|
||||
else if ((CaseInsensitiveEquals(alnum, "sp")) || (CaseInsensitiveEquals(alnum, "rtoc")))
|
||||
{
|
||||
return TokenType::GPR;
|
||||
}
|
||||
else if (std::tolower(alnum[0]) == 'f' && valid_regnum(alnum.substr(1)))
|
||||
{
|
||||
return TokenType::FPR;
|
||||
}
|
||||
else if (alnum.length() == 3 && eq_nocase(alnum.substr(0, 2), "cr") && alnum[2] >= '0' &&
|
||||
alnum[2] <= '7')
|
||||
else if (alnum.length() == 3 && CaseInsensitiveEquals(alnum.substr(0, 2), "cr") &&
|
||||
alnum[2] >= '0' && alnum[2] <= '7')
|
||||
{
|
||||
return TokenType::CRField;
|
||||
}
|
||||
else if (eq_nocase(alnum, "lt"))
|
||||
else if (CaseInsensitiveEquals(alnum, "lt"))
|
||||
{
|
||||
return TokenType::Lt;
|
||||
}
|
||||
else if (eq_nocase(alnum, "gt"))
|
||||
else if (CaseInsensitiveEquals(alnum, "gt"))
|
||||
{
|
||||
return TokenType::Gt;
|
||||
}
|
||||
else if (eq_nocase(alnum, "eq"))
|
||||
else if (CaseInsensitiveEquals(alnum, "eq"))
|
||||
{
|
||||
return TokenType::Eq;
|
||||
}
|
||||
else if (eq_nocase(alnum, "so"))
|
||||
else if (CaseInsensitiveEquals(alnum, "so"))
|
||||
{
|
||||
return TokenType::So;
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ class BitFieldArrayConstRef
|
|||
friend class BitFieldArrayConstIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr T Value() const { return m_array->Value(m_index); }
|
||||
constexpr operator T() const { return Value(); }
|
||||
|
||||
private:
|
||||
|
@ -333,7 +333,7 @@ class BitFieldArrayRef
|
|||
friend class BitFieldArrayIterator<position, bits, size, T, S>;
|
||||
|
||||
public:
|
||||
constexpr T Value() const { return m_array->Value(m_index); };
|
||||
constexpr T Value() const { return m_array->Value(m_index); }
|
||||
constexpr operator T() const { return Value(); }
|
||||
T operator=(const BitFieldArrayRef<position, bits, size, T, S>& value) const
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
@ -166,50 +167,10 @@ inline auto BitCastPtr(PtrType* ptr) noexcept -> BitCastPtrType<T, PtrType>
|
|||
}
|
||||
|
||||
// Similar to BitCastPtr, but specifically for aliasing structs to arrays.
|
||||
template <typename ArrayType, typename T,
|
||||
typename Container = std::array<ArrayType, sizeof(T) / sizeof(ArrayType)>>
|
||||
inline auto BitCastToArray(const T& obj) noexcept -> Container
|
||||
template <typename ValueType, typename From>
|
||||
[[nodiscard]] constexpr auto BitCastToArray(const From& obj) noexcept
|
||||
{
|
||||
static_assert(sizeof(T) % sizeof(ArrayType) == 0,
|
||||
"Size of array type must be a factor of size of source type.");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"BitCastToArray source type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<Container>(),
|
||||
"BitCastToArray array type must be trivially copyable.");
|
||||
|
||||
Container result;
|
||||
std::memcpy(result.data(), &obj, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename ArrayType, typename T,
|
||||
typename Container = std::array<ArrayType, sizeof(T) / sizeof(ArrayType)>>
|
||||
inline void BitCastFromArray(const Container& array, T& obj) noexcept
|
||||
{
|
||||
static_assert(sizeof(T) % sizeof(ArrayType) == 0,
|
||||
"Size of array type must be a factor of size of destination type.");
|
||||
static_assert(std::is_trivially_copyable<Container>(),
|
||||
"BitCastFromArray array type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"BitCastFromArray destination type must be trivially copyable.");
|
||||
|
||||
std::memcpy(&obj, array.data(), sizeof(T));
|
||||
}
|
||||
|
||||
template <typename ArrayType, typename T,
|
||||
typename Container = std::array<ArrayType, sizeof(T) / sizeof(ArrayType)>>
|
||||
inline auto BitCastFromArray(const Container& array) noexcept -> T
|
||||
{
|
||||
static_assert(sizeof(T) % sizeof(ArrayType) == 0,
|
||||
"Size of array type must be a factor of size of destination type.");
|
||||
static_assert(std::is_trivially_copyable<Container>(),
|
||||
"BitCastFromArray array type must be trivially copyable.");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"BitCastFromArray destination type must be trivially copyable.");
|
||||
|
||||
T obj;
|
||||
std::memcpy(&obj, array.data(), sizeof(T));
|
||||
return obj;
|
||||
return std::bit_cast<std::array<ValueType, sizeof(From) / sizeof(ValueType)>>(obj);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -87,6 +87,7 @@ add_library(common
|
|||
JitRegister.cpp
|
||||
JitRegister.h
|
||||
JsonUtil.h
|
||||
JsonUtil.cpp
|
||||
Lazy.h
|
||||
LinearDiskCache.h
|
||||
Logging/ConsoleListener.h
|
||||
|
@ -143,6 +144,7 @@ add_library(common
|
|||
TraversalClient.h
|
||||
TraversalProto.h
|
||||
TypeUtils.h
|
||||
Unreachable.h
|
||||
UPnP.cpp
|
||||
UPnP.h
|
||||
VariantUtil.h
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Common
|
|||
// having to prefix them with gen-> or something similar.
|
||||
// Example implementation:
|
||||
// class JIT : public CodeBlock<ARMXEmitter> {}
|
||||
template <class T>
|
||||
template <class T, bool executable = true>
|
||||
class CodeBlock : public T
|
||||
{
|
||||
private:
|
||||
|
@ -53,7 +53,10 @@ public:
|
|||
{
|
||||
region_size = size;
|
||||
total_region_size = size;
|
||||
region = static_cast<u8*>(Common::AllocateExecutableMemory(total_region_size));
|
||||
if constexpr (executable)
|
||||
region = static_cast<u8*>(Common::AllocateExecutableMemory(total_region_size));
|
||||
else
|
||||
region = static_cast<u8*>(Common::AllocateMemoryPages(total_region_size));
|
||||
T::SetCodePtr(region, region + size);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Common/ColorUtil.h"
|
||||
|
||||
#include "Common/Swap.h"
|
||||
|
||||
namespace Common
|
||||
|
|
|
@ -37,7 +37,7 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
|
|||
{ \
|
||||
DebugBreak(); \
|
||||
}
|
||||
#endif // WIN32 ndef
|
||||
#endif // _WIN32
|
||||
|
||||
namespace Common
|
||||
{
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#define ROOT_DIR "."
|
||||
|
||||
// The normal user directory
|
||||
#ifndef STEAM
|
||||
#ifdef _WIN32
|
||||
#define NORMAL_USER_DIR "Dolphin Emulator"
|
||||
#elif defined(__APPLE__)
|
||||
|
@ -21,15 +20,6 @@
|
|||
#else
|
||||
#define NORMAL_USER_DIR "dolphin-emu"
|
||||
#endif
|
||||
#else // ifndef STEAM
|
||||
#ifdef _WIN32
|
||||
#define NORMAL_USER_DIR "Dolphin Emulator (Steam)"
|
||||
#elif defined(__APPLE__)
|
||||
#define NORMAL_USER_DIR "Library/Application Support/Dolphin (Steam)"
|
||||
#else
|
||||
#define NORMAL_USER_DIR "dolphin-emu-steam"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// The portable user directory
|
||||
#ifdef _WIN32
|
||||
|
@ -63,6 +53,7 @@
|
|||
#define COVERCACHE_DIR "GameCovers"
|
||||
#define REDUMPCACHE_DIR "Redump"
|
||||
#define SHADERCACHE_DIR "Shaders"
|
||||
#define RETROACHIEVEMENTSCACHE_DIR "RetroAchievements"
|
||||
#define STATESAVES_DIR "StateSaves"
|
||||
#define SCREENSHOTS_DIR "ScreenShots"
|
||||
#define LOAD_DIR "Load"
|
||||
|
|
|
@ -261,4 +261,4 @@ int __cdecl EnableCompatPatches()
|
|||
extern "C" {
|
||||
__declspec(allocate(".CRT$XCZ")) decltype(&EnableCompatPatches)
|
||||
enableCompatPatches = EnableCompatPatches;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Common/Crypto/AES.h"
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <memory>
|
||||
|
@ -9,7 +11,6 @@
|
|||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CPUDetect.h"
|
||||
#include "Common/Crypto/AES.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
|
|
|
@ -385,4 +385,20 @@ Digest CalculateDigest(const u8* msg, size_t len)
|
|||
ctx->Update(msg, len);
|
||||
return ctx->Finish();
|
||||
}
|
||||
|
||||
std::string DigestToString(const Digest& digest)
|
||||
{
|
||||
static constexpr std::array<char, 16> lookup = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
std::string hash;
|
||||
hash.reserve(digest.size() * 2);
|
||||
for (size_t i = 0; i < digest.size(); ++i)
|
||||
{
|
||||
const u8 upper = static_cast<u8>((digest[i] >> 4) & 0xf);
|
||||
const u8 lower = static_cast<u8>(digest[i] & 0xf);
|
||||
hash.push_back(lookup[upper]);
|
||||
hash.push_back(lookup[lower]);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
} // namespace Common::SHA1
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <array>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
@ -23,7 +24,11 @@ class Context
|
|||
public:
|
||||
virtual ~Context() = default;
|
||||
virtual void Update(const u8* msg, size_t len) = 0;
|
||||
void Update(const std::vector<u8>& msg) { return Update(msg.data(), msg.size()); }
|
||||
void Update(std::span<const u8> msg) { return Update(msg.data(), msg.size()); }
|
||||
void Update(std::string_view msg)
|
||||
{
|
||||
return Update(reinterpret_cast<const u8*>(msg.data()), msg.size());
|
||||
}
|
||||
virtual Digest Finish() = 0;
|
||||
virtual bool HwAccelerated() const = 0;
|
||||
};
|
||||
|
@ -51,4 +56,6 @@ inline Digest CalculateDigest(const std::array<T, Size>& msg)
|
|||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
return CalculateDigest(reinterpret_cast<const u8*>(msg.data()), sizeof(msg));
|
||||
}
|
||||
|
||||
std::string DigestToString(const Digest& digest);
|
||||
} // namespace Common::SHA1
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Common::Debug
|
||||
{
|
||||
|
|
|
@ -553,7 +553,7 @@ bool SyncSDFolderToSDImage(const std::function<bool()>& cancelled, bool determin
|
|||
}
|
||||
|
||||
MKFS_PARM options = {};
|
||||
options.fmt = FM_FAT32;
|
||||
options.fmt = FM_FAT32 | FM_SFD;
|
||||
options.n_fat = 0; // Number of FATs: automatic
|
||||
options.align = 1; // Alignment of the data region (in sectors)
|
||||
options.n_root = 0; // Number of root directory entries: automatic (and unused for FAT32)
|
||||
|
|
|
@ -60,6 +60,10 @@
|
|||
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace File
|
||||
|
@ -738,6 +742,15 @@ std::string GetExePath()
|
|||
return PathToString(exe_path_absolute);
|
||||
#elif defined(__APPLE__)
|
||||
return GetBundleDirectory();
|
||||
#elif defined(__FreeBSD__)
|
||||
int name[4]{CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
size_t length = 0;
|
||||
if (sysctl(name, 4, nullptr, &length, nullptr, 0) != 0 || length == 0)
|
||||
return {};
|
||||
std::string dolphin_exe_path(length, '\0');
|
||||
if (sysctl(name, 4, dolphin_exe_path.data(), &length, nullptr, 0) != 0)
|
||||
return {};
|
||||
return dolphin_exe_path;
|
||||
#else
|
||||
char dolphin_exe_path[PATH_MAX];
|
||||
ssize_t len = ::readlink("/proc/self/exe", dolphin_exe_path, sizeof(dolphin_exe_path));
|
||||
|
@ -843,6 +856,8 @@ static void RebuildUserDirectories(unsigned int dir_index)
|
|||
s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_REDUMPCACHE_IDX] = s_user_paths[D_CACHE_IDX] + REDUMPCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX] =
|
||||
s_user_paths[D_CACHE_IDX] + RETROACHIEVEMENTSCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_SHADERS_IDX] = s_user_paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
s_user_paths[D_STATESAVES_IDX] = s_user_paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
s_user_paths[D_SCREENSHOTS_IDX] = s_user_paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
|
@ -926,6 +941,8 @@ static void RebuildUserDirectories(unsigned int dir_index)
|
|||
s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_REDUMPCACHE_IDX] = s_user_paths[D_CACHE_IDX] + REDUMPCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
s_user_paths[D_RETROACHIEVEMENTSCACHE_IDX] =
|
||||
s_user_paths[D_CACHE_IDX] + RETROACHIEVEMENTSCACHE_DIR DIR_SEP;
|
||||
break;
|
||||
|
||||
case D_GCUSER_IDX:
|
||||
|
|
|
@ -40,6 +40,7 @@ enum
|
|||
D_COVERCACHE_IDX,
|
||||
D_REDUMPCACHE_IDX,
|
||||
D_SHADERCACHE_IDX,
|
||||
D_RETROACHIEVEMENTSCACHE_IDX,
|
||||
D_SHADERS_IDX,
|
||||
D_STATESAVES_IDX,
|
||||
D_SCREENSHOTS_IDX,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Common/GL/GLInterface/AGL.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
// UpdateCachedDimensions and AttachContextToView contain calls to UI APIs, so they must only be
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Common/GL/GLX11Window.h"
|
||||
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
GLX11Window::GLX11Window(Display* display, Window parent_window, Colormap color_map, Window window,
|
||||
|
|
|
@ -75,7 +75,7 @@ bool IniFile::Section::Get(std::string_view key, std::string* value,
|
|||
|
||||
bool IniFile::Section::Exists(std::string_view key) const
|
||||
{
|
||||
return values.find(key) != values.end();
|
||||
return values.contains(key);
|
||||
}
|
||||
|
||||
bool IniFile::Section::Delete(std::string_view key)
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
#include "Common/JsonUtil.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
|
||||
picojson::object ToJsonObject(const Common::Vec3& vec)
|
||||
{
|
||||
picojson::object obj;
|
||||
|
@ -38,3 +42,27 @@ std::optional<bool> ReadBoolFromJson(const picojson::object& obj, const std::str
|
|||
return std::nullopt;
|
||||
return it->second.get<bool>();
|
||||
}
|
||||
|
||||
bool JsonToFile(const std::string& filename, const picojson::value& root, bool prettify)
|
||||
{
|
||||
std::ofstream json_stream;
|
||||
File::OpenFStream(json_stream, filename, std::ios_base::out);
|
||||
if (!json_stream.is_open())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
json_stream << root.serialize(prettify);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonFromFile(const std::string& filename, picojson::value* root, std::string* error)
|
||||
{
|
||||
std::string json_data;
|
||||
if (!File::ReadFileToString(filename, json_data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*error = picojson::parse(*root, json_data);
|
||||
return error->empty();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <picojson.h>
|
||||
|
||||
#include "Common/MathUtil.h"
|
||||
#include "Common/Matrix.h"
|
||||
|
||||
// Ideally this would use a concept like, 'template <std::ranges::range Range>' to constrain it,
|
||||
|
@ -47,7 +46,7 @@ std::optional<Type> ReadNumericFromJson(const picojson::object& obj, const std::
|
|||
return std::nullopt;
|
||||
if (!it->second.is<double>())
|
||||
return std::nullopt;
|
||||
return MathUtil::SaturatingCast<Type>(it->second.get<double>());
|
||||
return static_cast<Type>(it->second.get<double>());
|
||||
}
|
||||
|
||||
std::optional<std::string> ReadStringFromJson(const picojson::object& obj, const std::string& key);
|
||||
|
@ -56,3 +55,6 @@ std::optional<bool> ReadBoolFromJson(const picojson::object& obj, const std::str
|
|||
|
||||
picojson::object ToJsonObject(const Common::Vec3& vec);
|
||||
void FromJson(const picojson::object& obj, Common::Vec3& vec);
|
||||
|
||||
bool JsonToFile(const std::string& filename, const picojson::value& root, bool prettify = false);
|
||||
bool JsonFromFile(const std::string& filename, picojson::value* root, std::string* error);
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
{
|
||||
static LdrDllNotifier notifier;
|
||||
return notifier;
|
||||
};
|
||||
}
|
||||
void Install(LdrObserver* observer);
|
||||
void Uninstall(LdrObserver* observer);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
private:
|
||||
Profiler* m_p;
|
||||
};
|
||||
}; // namespace Common
|
||||
} // namespace Common
|
||||
|
||||
// Warning: This profiler isn't thread safe. Only profile functions which doesn't run simultaneously
|
||||
#define PROFILE(name) \
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include "Common/SocketContext.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/Network.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
@ -11,7 +14,23 @@ SocketContext::SocketContext()
|
|||
std::lock_guard<std::mutex> g(s_lock);
|
||||
if (s_num_objects == 0)
|
||||
{
|
||||
static_cast<void>(WSAStartup(MAKEWORD(2, 2), &s_data));
|
||||
const int ret = WSAStartup(MAKEWORD(2, 2), &s_data);
|
||||
if (ret == 0)
|
||||
{
|
||||
INFO_LOG_FMT(COMMON, "WSAStartup succeeded, wVersion={}.{}, wHighVersion={}.{}",
|
||||
int(LOBYTE(s_data.wVersion)), int(HIBYTE(s_data.wVersion)),
|
||||
int(LOBYTE(s_data.wHighVersion)), int(HIBYTE(s_data.wHighVersion)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// The WSAStartup function directly returns the extended error code in the return value.
|
||||
// A call to the WSAGetLastError function is not needed and should not be used.
|
||||
//
|
||||
// Source:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsastartup
|
||||
ERROR_LOG_FMT(COMMON, "WSAStartup failed with error {}: {}", ret,
|
||||
Common::DecodeNetworkError(ret));
|
||||
}
|
||||
}
|
||||
s_num_objects++;
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ std::from_chars_result FromChars(std::string_view sv, T& value,
|
|||
const char* const last = first + sv.size();
|
||||
return std::from_chars(first, last, value, fmt);
|
||||
}
|
||||
}; // namespace Common
|
||||
} // namespace Common
|
||||
|
||||
std::string TabsToSpaces(int tab_size, std::string str);
|
||||
|
||||
|
|
|
@ -82,17 +82,4 @@ static_assert(!IsNOf<int, 1, int, int>::value);
|
|||
static_assert(IsNOf<int, 2, int, int>::value);
|
||||
static_assert(IsNOf<int, 2, int, short>::value); // Type conversions ARE allowed
|
||||
static_assert(!IsNOf<int, 2, int, char*>::value);
|
||||
|
||||
// TODO: This can be replaced with std::array's fill() once C++20 is fully supported.
|
||||
// Prior to C++20, std::array's fill() function is, unfortunately, not constexpr.
|
||||
// Ditto for <algorithm>'s std::fill. Although Dolphin targets C++20, Android doesn't
|
||||
// seem to properly support constexpr fill(), so we need this for now.
|
||||
template <typename T1, size_t N, typename T2>
|
||||
constexpr void Fill(std::array<T1, N>& array, const T2& value)
|
||||
{
|
||||
for (auto& entry : array)
|
||||
{
|
||||
entry = value;
|
||||
}
|
||||
}
|
||||
} // namespace Common
|
||||
|
|
21
Source/Core/Common/Unreachable.h
Normal file
21
Source/Core/Common/Unreachable.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2024 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
// TODO C++23: Replace with std::unreachable.
|
||||
[[noreturn]] inline void Unreachable()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
Crash();
|
||||
#elif defined(_MSC_VER) && !defined(__clang__)
|
||||
__assume(false);
|
||||
#else
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
}
|
||||
} // namespace Common
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
namespace Common
|
||||
{
|
||||
#define EMULATOR_NAME "Dolphin"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BUILD_TYPE_STR "Debug "
|
||||
#elif defined DEBUGFAST
|
||||
|
@ -41,6 +43,12 @@ const std::string& GetScmBranchStr()
|
|||
return scm_branch_str;
|
||||
}
|
||||
|
||||
const std::string& GetUserAgentStr()
|
||||
{
|
||||
static const std::string user_agent_str = EMULATOR_NAME "/" SCM_DESC_STR;
|
||||
return user_agent_str;
|
||||
}
|
||||
|
||||
const std::string& GetScmDistributorStr()
|
||||
{
|
||||
static const std::string scm_distributor_str = SCM_DISTRIBUTOR_STR;
|
||||
|
|
|
@ -11,6 +11,7 @@ const std::string& GetScmDescStr();
|
|||
const std::string& GetScmBranchStr();
|
||||
const std::string& GetScmRevStr();
|
||||
const std::string& GetScmRevGitStr();
|
||||
const std::string& GetUserAgentStr();
|
||||
const std::string& GetScmDistributorStr();
|
||||
const std::string& GetScmUpdateTrackStr();
|
||||
const std::string& GetNetplayDolphinVer();
|
||||
|
|
|
@ -69,4 +69,4 @@ OSVERSIONINFOW GetOSVersion()
|
|||
}
|
||||
return info;
|
||||
}
|
||||
}; // namespace WindowsRegistry
|
||||
} // namespace WindowsRegistry
|
||||
|
|
|
@ -15,4 +15,4 @@ template <>
|
|||
bool ReadValue(std::string* value, const std::string& subkey, const std::string& name);
|
||||
|
||||
OSVERSIONINFOW GetOSVersion();
|
||||
}; // namespace WindowsRegistry
|
||||
} // namespace WindowsRegistry
|
||||
|
|
|
@ -6,6 +6,7 @@ var cmd_revision = " rev-parse HEAD";
|
|||
var cmd_describe = " rev-parse --short HEAD";
|
||||
var cmd_branch = " rev-parse --abbrev-ref HEAD";
|
||||
var cmd_commits_ahead = " rev-list --count HEAD ^master";
|
||||
var cmd_get_tag = " describe --exact-match HEAD";
|
||||
|
||||
function GetGitExe()
|
||||
{
|
||||
|
@ -59,6 +60,25 @@ function GetFirstStdOutLine(cmd)
|
|||
}
|
||||
}
|
||||
|
||||
function AttemptToExecuteCommand(cmd)
|
||||
{
|
||||
try
|
||||
{
|
||||
var exec = wshShell.Exec(cmd)
|
||||
|
||||
// wait until the command has finished
|
||||
while (exec.Status == 0) {}
|
||||
|
||||
return exec.ExitCode;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// catch "the system cannot find the file specified" error
|
||||
WScript.Echo("Failed to exec " + cmd + " this should never happen");
|
||||
WScript.Quit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function GetFileContents(f)
|
||||
{
|
||||
try
|
||||
|
@ -88,6 +108,12 @@ if (default_update_track == "%DOLPHIN_DEFAULT_UPDATE_TRACK%") default_update_tra
|
|||
// remove hash (and trailing "-0" if needed) from description
|
||||
describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2');
|
||||
|
||||
// set commits ahead to zero if on a tag
|
||||
if (AttemptToExecuteCommand(gitexe + cmd_get_tag) == 0)
|
||||
{
|
||||
commits_ahead = "0";
|
||||
}
|
||||
|
||||
var out_contents =
|
||||
"#define SCM_REV_STR \"" + revision + "\"\n" +
|
||||
"#define SCM_DESC_STR \"" + describe + "\"\n" +
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
// FIXME: avoid pushing all 16 XMM registers when possible? most functions we call probably
|
||||
// don't actually clobber them.
|
||||
#define ABI_ALL_CALLER_SAVED (BitSet32{RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11} | ABI_ALL_FPRS)
|
||||
#endif // WIN32
|
||||
#endif // _WIN32
|
||||
|
||||
#define ABI_ALL_CALLEE_SAVED (~ABI_ALL_CALLER_SAVED)
|
||||
|
||||
|
|
|
@ -107,26 +107,6 @@ void XEmitter::SetCodePtr(u8* ptr, u8* end, bool write_failed)
|
|||
m_write_failed = write_failed;
|
||||
}
|
||||
|
||||
const u8* XEmitter::GetCodePtr() const
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
u8* XEmitter::GetWritableCodePtr()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
const u8* XEmitter::GetCodeEnd() const
|
||||
{
|
||||
return m_code_end;
|
||||
}
|
||||
|
||||
u8* XEmitter::GetWritableCodeEnd()
|
||||
{
|
||||
return m_code_end;
|
||||
}
|
||||
|
||||
void XEmitter::Write8(u8 value)
|
||||
{
|
||||
if (code >= m_code_end)
|
||||
|
|
|
@ -394,10 +394,10 @@ public:
|
|||
u8* AlignCode4();
|
||||
u8* AlignCode16();
|
||||
u8* AlignCodePage();
|
||||
const u8* GetCodePtr() const;
|
||||
u8* GetWritableCodePtr();
|
||||
const u8* GetCodeEnd() const;
|
||||
u8* GetWritableCodeEnd();
|
||||
const u8* GetCodePtr() const { return code; }
|
||||
u8* GetWritableCodePtr() { return code; }
|
||||
const u8* GetCodeEnd() const { return m_code_end; }
|
||||
u8* GetWritableCodeEnd() { return m_code_end; }
|
||||
|
||||
void LockFlags() { flags_locked = true; }
|
||||
void UnlockFlags() { flags_locked = false; }
|
||||
|
|
|
@ -13,20 +13,31 @@
|
|||
#include <rcheevos/include/rc_api_info.h>
|
||||
#include <rcheevos/include/rc_hash.h>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IOFile.h"
|
||||
#include "Common/Image.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "Common/Version.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
#include "Core/Config/AchievementSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/HW/VideoInterface.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/System.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "UICommon/DiscordPresence.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
static std::unique_ptr<OSD::Icon> DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge);
|
||||
static const Common::HttpRequest::Headers USER_AGENT_HEADER = {
|
||||
{"User-Agent", Common::GetUserAgentStr()}};
|
||||
|
||||
AchievementManager& AchievementManager::GetInstance()
|
||||
{
|
||||
|
@ -36,9 +47,13 @@ AchievementManager& AchievementManager::GetInstance()
|
|||
|
||||
void AchievementManager::Init()
|
||||
{
|
||||
LoadDefaultBadges();
|
||||
if (!m_client && Config::Get(Config::RA_ENABLED))
|
||||
{
|
||||
m_client = rc_client_create(MemoryPeeker, Request);
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
m_client = rc_client_create(MemoryVerifier, Request);
|
||||
}
|
||||
std::string host_url = Config::Get(Config::RA_HOST_URL);
|
||||
if (!host_url.empty())
|
||||
rc_client_set_host(m_client, host_url.c_str());
|
||||
|
@ -57,6 +72,33 @@ void AchievementManager::Init()
|
|||
}
|
||||
}
|
||||
|
||||
picojson::value AchievementManager::LoadApprovedList()
|
||||
{
|
||||
picojson::value temp;
|
||||
std::string error;
|
||||
if (!JsonFromFile(fmt::format("{}{}{}", File::GetSysDirectory(), DIR_SEP, APPROVED_LIST_FILENAME),
|
||||
&temp, &error))
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load approved game settings list {}",
|
||||
APPROVED_LIST_FILENAME);
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Error: {}", error);
|
||||
return {};
|
||||
}
|
||||
auto context = Common::SHA1::CreateContext();
|
||||
context->Update(temp.serialize());
|
||||
auto digest = context->Finish();
|
||||
if (digest != APPROVED_LIST_HASH)
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to verify approved game settings list {}",
|
||||
APPROVED_LIST_FILENAME);
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Expected hash {}, found hash {}",
|
||||
Common::SHA1::DigestToString(APPROVED_LIST_HASH),
|
||||
Common::SHA1::DigestToString(digest));
|
||||
return {};
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
void AchievementManager::SetUpdateCallback(UpdateCallback callback)
|
||||
{
|
||||
m_update_callback = std::move(callback);
|
||||
|
@ -138,6 +180,7 @@ void AchievementManager::LoadGame(const std::string& file_path, const DiscIO::Vo
|
|||
}
|
||||
else
|
||||
{
|
||||
rc_client_set_read_memory_function(m_client, MemoryVerifier);
|
||||
rc_client_begin_identify_and_load_game(m_client, RC_CONSOLE_GAMECUBE, file_path.c_str(), NULL,
|
||||
0, LoadGameCallback, NULL);
|
||||
}
|
||||
|
@ -149,6 +192,18 @@ bool AchievementManager::IsGameLoaded() const
|
|||
return game_info && game_info->id != 0;
|
||||
}
|
||||
|
||||
void AchievementManager::SetBackgroundExecutionAllowed(bool allowed)
|
||||
{
|
||||
m_background_execution_allowed = allowed;
|
||||
|
||||
Core::System* system = m_system.load(std::memory_order_acquire);
|
||||
if (!system)
|
||||
return;
|
||||
|
||||
if (allowed && Core::GetState(*system) == Core::State::Paused)
|
||||
DoIdle();
|
||||
}
|
||||
|
||||
void AchievementManager::FetchPlayerBadge()
|
||||
{
|
||||
FetchBadge(&m_player_badge, RC_IMAGE_TYPE_USER,
|
||||
|
@ -220,7 +275,8 @@ void AchievementManager::DoFrame()
|
|||
std::lock_guard lg{m_lock};
|
||||
rc_client_do_frame(m_client);
|
||||
}
|
||||
if (!m_system)
|
||||
Core::System* system = m_system.load(std::memory_order_acquire);
|
||||
if (!system)
|
||||
return;
|
||||
auto current_time = std::chrono::steady_clock::now();
|
||||
if (current_time - m_last_rp_time > std::chrono::seconds{10})
|
||||
|
@ -233,6 +289,54 @@ void AchievementManager::DoFrame()
|
|||
}
|
||||
}
|
||||
|
||||
bool AchievementManager::CanPause()
|
||||
{
|
||||
u32 frames_to_next_pause = 0;
|
||||
bool can_pause = rc_client_can_pause(m_client, &frames_to_next_pause);
|
||||
if (!can_pause)
|
||||
{
|
||||
OSD::AddMessage(
|
||||
fmt::format("RetroAchievements Hardcore Mode:\n"
|
||||
"Cannot pause until another {:.2f} seconds have passed.",
|
||||
static_cast<float>(frames_to_next_pause) /
|
||||
Core::System::GetInstance().GetVideoInterface().GetTargetRefreshRate()),
|
||||
OSD::Duration::VERY_LONG, OSD::Color::RED);
|
||||
}
|
||||
return can_pause;
|
||||
}
|
||||
|
||||
void AchievementManager::DoIdle()
|
||||
{
|
||||
std::thread([this]() {
|
||||
while (true)
|
||||
{
|
||||
Common::SleepCurrentThread(1000);
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
Core::System* system = m_system.load(std::memory_order_acquire);
|
||||
if (!system || Core::GetState(*system) != Core::State::Paused)
|
||||
return;
|
||||
if (!m_background_execution_allowed)
|
||||
return;
|
||||
if (!m_client || !IsGameLoaded())
|
||||
return;
|
||||
}
|
||||
// rc_client_idle peeks at memory to recalculate rich presence and therefore
|
||||
// needs to be on host or CPU thread to access memory.
|
||||
Core::QueueHostJob([this](Core::System& system) {
|
||||
std::lock_guard lg{m_lock};
|
||||
if (Core::GetState(system) != Core::State::Paused)
|
||||
return;
|
||||
if (!m_background_execution_allowed)
|
||||
return;
|
||||
if (!m_client || !IsGameLoaded())
|
||||
return;
|
||||
rc_client_idle(m_client);
|
||||
});
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
|
||||
std::recursive_mutex& AchievementManager::GetLock()
|
||||
{
|
||||
return m_lock;
|
||||
|
@ -253,6 +357,62 @@ bool AchievementManager::IsHardcoreModeActive() const
|
|||
return rc_client_is_processing_required(m_client);
|
||||
}
|
||||
|
||||
void AchievementManager::FilterApprovedPatches(std::vector<PatchEngine::Patch>& patches,
|
||||
const std::string& game_ini_id) const
|
||||
{
|
||||
if (patches.empty())
|
||||
{
|
||||
// There's nothing to verify, so let's save ourselves some work
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lg{m_lock};
|
||||
|
||||
if (!IsHardcoreModeActive())
|
||||
return;
|
||||
|
||||
const bool known_id = m_ini_root->contains(game_ini_id);
|
||||
|
||||
auto patch_itr = patches.begin();
|
||||
while (patch_itr != patches.end())
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Verifying patch {}", patch_itr->name);
|
||||
|
||||
bool verified = false;
|
||||
|
||||
if (known_id)
|
||||
{
|
||||
auto context = Common::SHA1::CreateContext();
|
||||
context->Update(Common::BitCastToArray<u8>(static_cast<u64>(patch_itr->entries.size())));
|
||||
for (const auto& entry : patch_itr->entries)
|
||||
{
|
||||
context->Update(Common::BitCastToArray<u8>(entry.type));
|
||||
context->Update(Common::BitCastToArray<u8>(entry.address));
|
||||
context->Update(Common::BitCastToArray<u8>(entry.value));
|
||||
context->Update(Common::BitCastToArray<u8>(entry.comparand));
|
||||
context->Update(Common::BitCastToArray<u8>(entry.conditional));
|
||||
}
|
||||
auto digest = context->Finish();
|
||||
|
||||
verified = m_ini_root->get(game_ini_id).contains(Common::SHA1::DigestToString(digest));
|
||||
}
|
||||
|
||||
if (!verified)
|
||||
{
|
||||
patch_itr = patches.erase(patch_itr);
|
||||
OSD::AddMessage(
|
||||
fmt::format("Failed to verify patch {} from file {}.", patch_itr->name, game_ini_id),
|
||||
OSD::Duration::VERY_LONG, OSD::Color::RED);
|
||||
OSD::AddMessage("Disable hardcore mode to enable this patch.", OSD::Duration::VERY_LONG,
|
||||
OSD::Color::RED);
|
||||
}
|
||||
else
|
||||
{
|
||||
patch_itr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementManager::SetSpectatorMode()
|
||||
{
|
||||
rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED));
|
||||
|
@ -278,9 +438,9 @@ u32 AchievementManager::GetPlayerScore() const
|
|||
return user->score;
|
||||
}
|
||||
|
||||
const AchievementManager::BadgeStatus& AchievementManager::GetPlayerBadge() const
|
||||
const AchievementManager::Badge& AchievementManager::GetPlayerBadge() const
|
||||
{
|
||||
return m_player_badge;
|
||||
return m_player_badge.data.empty() ? m_default_player_badge : m_player_badge;
|
||||
}
|
||||
|
||||
std::string_view AchievementManager::GetGameDisplayName() const
|
||||
|
@ -298,17 +458,19 @@ rc_api_fetch_game_data_response_t* AchievementManager::GetGameData()
|
|||
return &m_game_data;
|
||||
}
|
||||
|
||||
const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const
|
||||
const AchievementManager::Badge& AchievementManager::GetGameBadge() const
|
||||
{
|
||||
return m_game_badge;
|
||||
return m_game_badge.data.empty() ? m_default_game_badge : m_game_badge;
|
||||
}
|
||||
|
||||
const AchievementManager::BadgeStatus& AchievementManager::GetAchievementBadge(AchievementId id,
|
||||
bool locked) const
|
||||
const AchievementManager::Badge& AchievementManager::GetAchievementBadge(AchievementId id,
|
||||
bool locked) const
|
||||
{
|
||||
auto& badge_list = locked ? m_locked_badges : m_locked_badges;
|
||||
auto& badge_list = locked ? m_locked_badges : m_unlocked_badges;
|
||||
auto itr = badge_list.find(id);
|
||||
return (itr == badge_list.end()) ? m_default_badge : itr->second;
|
||||
return (itr != badge_list.end() && itr->second.data.size() > 0) ?
|
||||
itr->second :
|
||||
(locked ? m_default_locked_badge : m_default_unlocked_badge);
|
||||
}
|
||||
|
||||
const AchievementManager::LeaderboardStatus*
|
||||
|
@ -317,8 +479,6 @@ AchievementManager::GetLeaderboardInfo(AchievementManager::AchievementId leaderb
|
|||
if (const auto leaderboard_iter = m_leaderboard_map.find(leaderboard_id);
|
||||
leaderboard_iter != m_leaderboard_map.end())
|
||||
{
|
||||
if (leaderboard_iter->second.entries.size() == 0)
|
||||
FetchBoardInfo(leaderboard_id);
|
||||
return &leaderboard_iter->second;
|
||||
}
|
||||
|
||||
|
@ -330,7 +490,18 @@ AchievementManager::RichPresence AchievementManager::GetRichPresence() const
|
|||
return m_rich_presence;
|
||||
}
|
||||
|
||||
const AchievementManager::NamedIconMap& AchievementManager::GetChallengeIcons() const
|
||||
bool AchievementManager::AreChallengesUpdated() const
|
||||
{
|
||||
return m_challenges_updated;
|
||||
}
|
||||
|
||||
void AchievementManager::ResetChallengesUpdated()
|
||||
{
|
||||
m_challenges_updated = false;
|
||||
}
|
||||
|
||||
const std::unordered_set<AchievementManager::AchievementId>&
|
||||
AchievementManager::GetActiveChallenges() const
|
||||
{
|
||||
return m_active_challenges;
|
||||
}
|
||||
|
@ -393,29 +564,36 @@ void AchievementManager::CloseGame()
|
|||
{
|
||||
m_active_challenges.clear();
|
||||
m_active_leaderboards.clear();
|
||||
m_game_badge.name.clear();
|
||||
m_game_badge.width = 0;
|
||||
m_game_badge.height = 0;
|
||||
m_game_badge.data.clear();
|
||||
m_unlocked_badges.clear();
|
||||
m_locked_badges.clear();
|
||||
m_leaderboard_map.clear();
|
||||
m_rich_presence.fill('\0');
|
||||
rc_api_destroy_fetch_game_data_response(&m_game_data);
|
||||
m_game_data = {};
|
||||
m_queue.Cancel();
|
||||
m_image_queue.Cancel();
|
||||
rc_client_unload_game(m_client);
|
||||
m_system = nullptr;
|
||||
m_system.store(nullptr, std::memory_order_release);
|
||||
if (Config::Get(Config::RA_DISCORD_PRESENCE_ENABLED))
|
||||
Discord::UpdateDiscordPresence();
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Game closed.");
|
||||
}
|
||||
}
|
||||
|
||||
m_update_callback(UpdatedItems{.all = true});
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Game closed.");
|
||||
}
|
||||
|
||||
void AchievementManager::Logout()
|
||||
{
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
CloseGame();
|
||||
m_player_badge.name.clear();
|
||||
std::lock_guard lg{m_lock};
|
||||
m_player_badge.width = 0;
|
||||
m_player_badge.height = 0;
|
||||
m_player_badge.data.clear();
|
||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
||||
}
|
||||
|
||||
|
@ -429,6 +607,7 @@ void AchievementManager::Shutdown()
|
|||
{
|
||||
CloseGame();
|
||||
m_queue.Shutdown();
|
||||
std::lock_guard lg{m_lock};
|
||||
// DON'T log out - keep those credentials for next run.
|
||||
rc_client_destroy(m_client);
|
||||
m_client = nullptr;
|
||||
|
@ -500,6 +679,53 @@ void AchievementManager::FilereaderClose(void* file_handle)
|
|||
delete static_cast<FilereaderState*>(file_handle);
|
||||
}
|
||||
|
||||
void AchievementManager::LoadDefaultBadges()
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
|
||||
std::string directory = File::GetSysDirectory() + DIR_SEP + RESOURCES_DIR + DIR_SEP;
|
||||
|
||||
if (m_default_player_badge.data.empty())
|
||||
{
|
||||
if (!LoadPNGTexture(&m_default_player_badge,
|
||||
fmt::format("{}{}", directory, DEFAULT_PLAYER_BADGE_FILENAME)))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Default player badge '{}' failed to load",
|
||||
DEFAULT_PLAYER_BADGE_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_default_game_badge.data.empty())
|
||||
{
|
||||
if (!LoadPNGTexture(&m_default_game_badge,
|
||||
fmt::format("{}{}", directory, DEFAULT_GAME_BADGE_FILENAME)))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load",
|
||||
DEFAULT_GAME_BADGE_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_default_unlocked_badge.data.empty())
|
||||
{
|
||||
if (!LoadPNGTexture(&m_default_unlocked_badge,
|
||||
fmt::format("{}{}", directory, DEFAULT_UNLOCKED_BADGE_FILENAME)))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Default unlocked achievement badge '{}' failed to load",
|
||||
DEFAULT_UNLOCKED_BADGE_FILENAME);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_default_locked_badge.data.empty())
|
||||
{
|
||||
if (!LoadPNGTexture(&m_default_locked_badge,
|
||||
fmt::format("{}{}", directory, DEFAULT_LOCKED_BADGE_FILENAME)))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Default locked achievement badge '{}' failed to load",
|
||||
DEFAULT_LOCKED_BADGE_FILENAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementManager::LoginCallback(int result, const char* error_message, rc_client_t* client,
|
||||
void* userdata)
|
||||
{
|
||||
|
@ -578,6 +804,8 @@ void AchievementManager::LeaderboardEntriesCallback(int result, const char* erro
|
|||
map_entry.username.assign(response_entry.user);
|
||||
memcpy(map_entry.score.data(), response_entry.display, FORMAT_SIZE);
|
||||
map_entry.rank = response_entry.rank;
|
||||
if (ix == list->user_index)
|
||||
leaderboard.player_index = response_entry.rank;
|
||||
}
|
||||
AchievementManager::GetInstance().m_update_callback({.leaderboards = {*leaderboard_id}});
|
||||
}
|
||||
|
@ -585,6 +813,7 @@ void AchievementManager::LeaderboardEntriesCallback(int result, const char* erro
|
|||
void AchievementManager::LoadGameCallback(int result, const char* error_message,
|
||||
rc_client_t* client, void* userdata)
|
||||
{
|
||||
AchievementManager::GetInstance().m_loading_volume.reset(nullptr);
|
||||
if (result != RC_OK)
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to load data for current game.");
|
||||
|
@ -603,20 +832,40 @@ void AchievementManager::LoadGameCallback(int result, const char* error_message,
|
|||
}
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Loaded data for game ID {}.", game->id);
|
||||
|
||||
AchievementManager::GetInstance().m_display_welcome_message = true;
|
||||
AchievementManager::GetInstance().FetchGameBadges();
|
||||
AchievementManager::GetInstance().m_system = &Core::System::GetInstance();
|
||||
AchievementManager::GetInstance().m_update_callback({.all = true});
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
rc_client_set_read_memory_function(instance.m_client, MemoryPeeker);
|
||||
instance.m_display_welcome_message = true;
|
||||
instance.FetchGameBadges();
|
||||
instance.m_system.store(&Core::System::GetInstance(), std::memory_order_release);
|
||||
instance.m_update_callback({.all = true});
|
||||
// Set this to a value that will immediately trigger RP
|
||||
AchievementManager::GetInstance().m_last_rp_time =
|
||||
std::chrono::steady_clock::now() - std::chrono::minutes{2};
|
||||
instance.m_last_rp_time = std::chrono::steady_clock::now() - std::chrono::minutes{2};
|
||||
|
||||
std::lock_guard lg{instance.GetLock()};
|
||||
auto* leaderboard_list =
|
||||
rc_client_create_leaderboard_list(client, RC_CLIENT_LEADERBOARD_LIST_GROUPING_NONE);
|
||||
for (u32 bucket = 0; bucket < leaderboard_list->num_buckets; bucket++)
|
||||
{
|
||||
const auto& leaderboard_bucket = leaderboard_list->buckets[bucket];
|
||||
for (u32 board = 0; board < leaderboard_bucket.num_leaderboards; board++)
|
||||
{
|
||||
const auto& leaderboard = leaderboard_bucket.leaderboards[board];
|
||||
instance.m_leaderboard_map.insert(
|
||||
std::pair(leaderboard->id, LeaderboardStatus{.name = leaderboard->title,
|
||||
.description = leaderboard->description}));
|
||||
}
|
||||
}
|
||||
rc_client_destroy_leaderboard_list(leaderboard_list);
|
||||
}
|
||||
|
||||
void AchievementManager::ChangeMediaCallback(int result, const char* error_message,
|
||||
rc_client_t* client, void* userdata)
|
||||
{
|
||||
AchievementManager::GetInstance().m_loading_volume.reset(nullptr);
|
||||
if (result == RC_OK)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == RC_HARDCORE_DISABLED)
|
||||
{
|
||||
|
@ -637,11 +886,8 @@ void AchievementManager::DisplayWelcomeMessage()
|
|||
m_display_welcome_message = false;
|
||||
const u32 color =
|
||||
rc_client_get_hardcore_enabled(m_client) ? OSD::Color::YELLOW : OSD::Color::CYAN;
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED) && !m_game_badge.name.empty())
|
||||
{
|
||||
OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN,
|
||||
DecodeBadgeToOSDIcon(m_game_badge.badge));
|
||||
}
|
||||
|
||||
OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, &GetGameBadge());
|
||||
auto info = rc_client_get_game_info(m_client);
|
||||
if (!info)
|
||||
{
|
||||
|
@ -671,17 +917,15 @@ void AchievementManager::DisplayWelcomeMessage()
|
|||
|
||||
void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t* client_event)
|
||||
{
|
||||
const auto& instance = AchievementManager::GetInstance();
|
||||
OSD::AddMessage(fmt::format("Unlocked: {} ({})", client_event->achievement->title,
|
||||
client_event->achievement->points),
|
||||
OSD::Duration::VERY_LONG,
|
||||
(rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ?
|
||||
OSD::Color::YELLOW :
|
||||
OSD::Color::CYAN,
|
||||
(Config::Get(Config::RA_BADGES_ENABLED)) ?
|
||||
DecodeBadgeToOSDIcon(AchievementManager::GetInstance()
|
||||
.m_unlocked_badges[client_event->achievement->id]
|
||||
.badge) :
|
||||
nullptr);
|
||||
(rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW :
|
||||
OSD::Color::CYAN,
|
||||
&instance.GetAchievementBadge(client_event->achievement->id, false));
|
||||
AchievementManager::GetInstance().m_update_callback(
|
||||
UpdatedItems{.achievements = {client_event->achievement->id}});
|
||||
}
|
||||
|
||||
void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event)
|
||||
|
@ -706,6 +950,8 @@ void AchievementManager::HandleLeaderboardSubmittedEvent(const rc_client_event_t
|
|||
client_event->leaderboard->title),
|
||||
OSD::Duration::VERY_LONG, OSD::Color::YELLOW);
|
||||
AchievementManager::GetInstance().FetchBoardInfo(client_event->leaderboard->id);
|
||||
AchievementManager::GetInstance().m_update_callback(
|
||||
UpdatedItems{.leaderboards = {client_event->leaderboard->id}});
|
||||
}
|
||||
|
||||
void AchievementManager::HandleLeaderboardTrackerUpdateEvent(const rc_client_event_t* client_event)
|
||||
|
@ -738,36 +984,38 @@ void AchievementManager::HandleLeaderboardTrackerHideEvent(const rc_client_event
|
|||
void AchievementManager::HandleAchievementChallengeIndicatorShowEvent(
|
||||
const rc_client_event_t* client_event)
|
||||
{
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED))
|
||||
{
|
||||
auto& unlocked_badges = AchievementManager::GetInstance().m_unlocked_badges;
|
||||
if (const auto unlocked_iter = unlocked_badges.find(client_event->achievement->id);
|
||||
unlocked_iter != unlocked_badges.end())
|
||||
{
|
||||
AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] =
|
||||
DecodeBadgeToOSDIcon(unlocked_iter->second.badge);
|
||||
}
|
||||
}
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
const auto [iter, inserted] = instance.m_active_challenges.insert(client_event->achievement->id);
|
||||
if (inserted)
|
||||
instance.m_challenges_updated = true;
|
||||
AchievementManager::GetInstance().m_update_callback(UpdatedItems{.rich_presence = true});
|
||||
}
|
||||
|
||||
void AchievementManager::HandleAchievementChallengeIndicatorHideEvent(
|
||||
const rc_client_event_t* client_event)
|
||||
{
|
||||
AchievementManager::GetInstance().m_active_challenges.erase(
|
||||
client_event->achievement->badge_name);
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
const auto removed = instance.m_active_challenges.erase(client_event->achievement->id);
|
||||
if (removed > 0)
|
||||
instance.m_challenges_updated = true;
|
||||
AchievementManager::GetInstance().m_update_callback(UpdatedItems{.rich_presence = true});
|
||||
}
|
||||
|
||||
void AchievementManager::HandleAchievementProgressIndicatorShowEvent(
|
||||
const rc_client_event_t* client_event)
|
||||
{
|
||||
auto& instance = AchievementManager::GetInstance();
|
||||
auto current_time = std::chrono::steady_clock::now();
|
||||
const auto message_wait_time = std::chrono::milliseconds{OSD::Duration::SHORT};
|
||||
if (current_time - instance.m_last_progress_message < message_wait_time)
|
||||
return;
|
||||
OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title,
|
||||
client_event->achievement->measured_progress),
|
||||
OSD::Duration::SHORT, OSD::Color::GREEN,
|
||||
(Config::Get(Config::RA_BADGES_ENABLED)) ?
|
||||
DecodeBadgeToOSDIcon(AchievementManager::GetInstance()
|
||||
.m_unlocked_badges[client_event->achievement->id]
|
||||
.badge) :
|
||||
nullptr);
|
||||
&instance.GetAchievementBadge(client_event->achievement->id, false));
|
||||
instance.m_last_progress_message = current_time;
|
||||
AchievementManager::GetInstance().m_update_callback(
|
||||
UpdatedItems{.achievements = {client_event->achievement->id}});
|
||||
}
|
||||
|
||||
void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event,
|
||||
|
@ -784,9 +1032,7 @@ void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* clien
|
|||
OSD::AddMessage(fmt::format("Congratulations! {} has {} {}", user_info->display_name,
|
||||
hardcore ? "mastered" : "completed", game_info->title),
|
||||
OSD::Duration::VERY_LONG, hardcore ? OSD::Color::YELLOW : OSD::Color::CYAN,
|
||||
(Config::Get(Config::RA_BADGES_ENABLED)) ?
|
||||
DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge) :
|
||||
nullptr);
|
||||
&AchievementManager::GetInstance().GetGameBadge());
|
||||
}
|
||||
|
||||
void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event)
|
||||
|
@ -801,62 +1047,65 @@ void AchievementManager::HandleServerErrorEvent(const rc_client_event_t* client_
|
|||
client_event->server_error->api, client_event->server_error->error_message);
|
||||
}
|
||||
|
||||
static std::unique_ptr<OSD::Icon> DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge)
|
||||
{
|
||||
if (badge.empty())
|
||||
return nullptr;
|
||||
|
||||
auto icon = std::make_unique<OSD::Icon>();
|
||||
if (!Common::LoadPNG(badge, &icon->rgba_data, &icon->width, &icon->height))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Error decoding badge.");
|
||||
return nullptr;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
void AchievementManager::Request(const rc_api_request_t* request,
|
||||
rc_client_server_callback_t callback, void* callback_data,
|
||||
rc_client_t* client)
|
||||
{
|
||||
std::string url = request->url;
|
||||
std::string post_data = request->post_data;
|
||||
AchievementManager::GetInstance().m_queue.EmplaceItem([url = std::move(url),
|
||||
post_data = std::move(post_data),
|
||||
callback = std::move(callback),
|
||||
callback_data = std::move(callback_data)] {
|
||||
const Common::HttpRequest::Headers USER_AGENT_HEADER = {{"User-Agent", "Dolphin/Placeholder"}};
|
||||
AchievementManager::GetInstance().m_queue.EmplaceItem(
|
||||
[url = std::move(url), post_data = std::move(post_data), callback = std::move(callback),
|
||||
callback_data = std::move(callback_data)] {
|
||||
Common::HttpRequest http_request;
|
||||
Common::HttpRequest::Response http_response;
|
||||
if (!post_data.empty())
|
||||
{
|
||||
http_response = http_request.Post(url, post_data, USER_AGENT_HEADER,
|
||||
Common::HttpRequest::AllowedReturnCodes::All);
|
||||
}
|
||||
else
|
||||
{
|
||||
http_response = http_request.Get(url, USER_AGENT_HEADER,
|
||||
Common::HttpRequest::AllowedReturnCodes::All);
|
||||
}
|
||||
|
||||
Common::HttpRequest http_request;
|
||||
Common::HttpRequest::Response http_response;
|
||||
if (!post_data.empty())
|
||||
{
|
||||
http_response = http_request.Post(url, post_data, USER_AGENT_HEADER,
|
||||
Common::HttpRequest::AllowedReturnCodes::All);
|
||||
}
|
||||
else
|
||||
{
|
||||
http_response =
|
||||
http_request.Get(url, USER_AGENT_HEADER, Common::HttpRequest::AllowedReturnCodes::All);
|
||||
}
|
||||
rc_api_server_response_t server_response;
|
||||
if (http_response.has_value() && http_response->size() > 0)
|
||||
{
|
||||
server_response.body = reinterpret_cast<const char*>(http_response->data());
|
||||
server_response.body_length = http_response->size();
|
||||
server_response.http_status_code = http_request.GetLastResponseCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr char error_message[] = "Failed HTTP request.";
|
||||
server_response.body = error_message;
|
||||
server_response.body_length = sizeof(error_message);
|
||||
server_response.http_status_code = RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR;
|
||||
}
|
||||
|
||||
rc_api_server_response_t server_response;
|
||||
if (http_response.has_value() && http_response->size() > 0)
|
||||
{
|
||||
server_response.body = reinterpret_cast<const char*>(http_response->data());
|
||||
server_response.body_length = http_response->size();
|
||||
server_response.http_status_code = http_request.GetLastResponseCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr char error_message[] = "Failed HTTP request.";
|
||||
server_response.body = error_message;
|
||||
server_response.body_length = sizeof(error_message);
|
||||
server_response.http_status_code = RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR;
|
||||
}
|
||||
callback(&server_response, callback_data);
|
||||
});
|
||||
}
|
||||
|
||||
callback(&server_response, callback_data);
|
||||
});
|
||||
// Currently, when rc_client calls the memory peek method provided in its constructor (or in
|
||||
// rc_client_set_read_memory_function) it will do so on the thread that calls DoFrame, which is
|
||||
// currently the host thread, with one exception: an asynchronous callback in the load game process.
|
||||
// This is done to validate/invalidate each memory reference in the downloaded assets, mark assets
|
||||
// as unsupported, and notify the player upon startup that there are unsupported assets and how
|
||||
// many. As such, all that call needs to do is return the number of bytes that can be read with this
|
||||
// call. As only the CPU and host threads are allowed to read from memory, I provide a separate
|
||||
// method for this verification. In lieu of a more convenient set of steps, I provide MemoryVerifier
|
||||
// to rc_client at construction, and in the Load Game callback, after the verification has been
|
||||
// complete, I call rc_client_set_read_memory_function to switch to the usual MemoryPeeker for all
|
||||
// future synchronous calls.
|
||||
u32 AchievementManager::MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
u32 ram_size = system.GetMemory().GetRamSizeReal();
|
||||
if (address >= ram_size)
|
||||
return 0;
|
||||
return std::min(ram_size - address, num_bytes);
|
||||
}
|
||||
|
||||
u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client)
|
||||
|
@ -864,6 +1113,11 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_
|
|||
if (buffer == nullptr)
|
||||
return 0u;
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (!(Core::IsHostThread() || Core::IsCPUThread()))
|
||||
{
|
||||
ASSERT_MSG(ACHIEVEMENTS, false, "MemoryPeeker called from wrong thread");
|
||||
return 0;
|
||||
}
|
||||
Core::CPUThreadGuard threadguard(system);
|
||||
for (u32 num_read = 0; num_read < num_bytes; num_read++)
|
||||
{
|
||||
|
@ -876,11 +1130,11 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_
|
|||
return num_bytes;
|
||||
}
|
||||
|
||||
void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge_type,
|
||||
void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_type,
|
||||
const AchievementManager::BadgeNameFunction function,
|
||||
const UpdatedItems callback_data)
|
||||
{
|
||||
if (!m_client || !HasAPIToken() || !Config::Get(Config::RA_BADGES_ENABLED))
|
||||
if (!m_client || !HasAPIToken())
|
||||
{
|
||||
m_update_callback(callback_data);
|
||||
if (m_display_welcome_message && badge_type == RC_IMAGE_TYPE_GAME)
|
||||
|
@ -902,40 +1156,71 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32
|
|||
if (name_to_fetch.empty())
|
||||
return;
|
||||
}
|
||||
rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
|
||||
.image_type = badge_type};
|
||||
Badge fetched_badge;
|
||||
rc_api_request_t api_request;
|
||||
Common::HttpRequest http_request;
|
||||
if (rc_api_init_fetch_image_request(&api_request, &icon_request) != RC_OK)
|
||||
|
||||
const std::string cache_path = fmt::format(
|
||||
"{}/badge-{}-{}.png", File::GetUserPath(D_RETROACHIEVEMENTSCACHE_IDX), badge_type,
|
||||
Common::SHA1::DigestToString(Common::SHA1::CalculateDigest(name_to_fetch)));
|
||||
|
||||
AchievementManager::Badge tmp_badge;
|
||||
if (!LoadPNGTexture(&tmp_badge, cache_path))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid request for image {}.", name_to_fetch);
|
||||
return;
|
||||
}
|
||||
auto http_response = http_request.Get(api_request.url);
|
||||
if (http_response.has_value() && http_response->size() <= 0)
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "RetroAchievements connection failed on image request.\n URL: {}",
|
||||
api_request.url);
|
||||
rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
|
||||
.image_type = badge_type};
|
||||
Badge fetched_badge;
|
||||
rc_api_request_t api_request;
|
||||
Common::HttpRequest http_request;
|
||||
if (rc_api_init_fetch_image_request(&api_request, &icon_request) != RC_OK)
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid request for image {}.", name_to_fetch);
|
||||
return;
|
||||
}
|
||||
auto http_response = http_request.Get(api_request.url, USER_AGENT_HEADER,
|
||||
Common::HttpRequest::AllowedReturnCodes::All);
|
||||
if (!http_response.has_value() || http_response->empty())
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS,
|
||||
"RetroAchievements connection failed on image request.\n URL: {}",
|
||||
api_request.url);
|
||||
rc_api_destroy_request(&api_request);
|
||||
m_update_callback(callback_data);
|
||||
return;
|
||||
}
|
||||
|
||||
rc_api_destroy_request(&api_request);
|
||||
m_update_callback(callback_data);
|
||||
return;
|
||||
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded badge id {}.", name_to_fetch);
|
||||
|
||||
if (!LoadPNGTexture(&tmp_badge, *http_response))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Badge '{}' failed to load", name_to_fetch);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string temp_path = fmt::format("{}.tmp", cache_path);
|
||||
File::IOFile temp_file(temp_path, "wb");
|
||||
if (!temp_file.IsOpen() ||
|
||||
!temp_file.WriteBytes(http_response->data(), http_response->size()) ||
|
||||
!temp_file.Close() || !File::Rename(temp_path, cache_path))
|
||||
{
|
||||
File::Delete(temp_path);
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to store badge '{}' to cache", name_to_fetch);
|
||||
}
|
||||
}
|
||||
|
||||
rc_api_destroy_request(&api_request);
|
||||
fetched_badge = std::move(*http_response);
|
||||
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded badge id {}.", name_to_fetch);
|
||||
std::lock_guard lg{m_lock};
|
||||
if (function(*this).empty() || name_to_fetch != function(*this))
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {}.", name_to_fetch);
|
||||
return;
|
||||
}
|
||||
badge->badge = std::move(fetched_badge);
|
||||
badge->name = std::move(name_to_fetch);
|
||||
|
||||
*badge = std::move(tmp_badge);
|
||||
m_update_callback(callback_data);
|
||||
if (badge_type == RC_IMAGE_TYPE_ACHIEVEMENT &&
|
||||
m_active_challenges.contains(*callback_data.achievements.begin()))
|
||||
{
|
||||
m_challenges_updated = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,23 +5,34 @@
|
|||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <rcheevos/include/rc_api_runtime.h>
|
||||
#include <rcheevos/include/rc_api_user.h>
|
||||
#include <rcheevos/include/rc_client.h>
|
||||
#include <rcheevos/include/rc_runtime.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/HttpRequest.h"
|
||||
#include "Common/JsonUtil.h"
|
||||
#include "Common/Lazy.h"
|
||||
#include "Common/WorkQueueThread.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
@ -29,10 +40,10 @@ class CPUThreadGuard;
|
|||
class System;
|
||||
} // namespace Core
|
||||
|
||||
namespace OSD
|
||||
namespace PatchEngine
|
||||
{
|
||||
struct Icon;
|
||||
}
|
||||
struct Patch;
|
||||
} // namespace PatchEngine
|
||||
|
||||
class AchievementManager
|
||||
{
|
||||
|
@ -47,19 +58,20 @@ public:
|
|||
using LeaderboardRank = u32;
|
||||
static constexpr size_t RP_SIZE = 256;
|
||||
using RichPresence = std::array<char, RP_SIZE>;
|
||||
using Badge = std::vector<u8>;
|
||||
using NamedIconMap = std::map<std::string, std::unique_ptr<OSD::Icon>, std::less<>>;
|
||||
using Badge = VideoCommon::CustomTextureData::ArraySlice::Level;
|
||||
static constexpr size_t MAX_DISPLAYED_LBOARDS = 4;
|
||||
|
||||
struct BadgeStatus
|
||||
{
|
||||
std::string name = "";
|
||||
Badge badge{};
|
||||
};
|
||||
|
||||
static constexpr std::string_view DEFAULT_PLAYER_BADGE_FILENAME = "achievements_player.png";
|
||||
static constexpr std::string_view DEFAULT_GAME_BADGE_FILENAME = "achievements_game.png";
|
||||
static constexpr std::string_view DEFAULT_LOCKED_BADGE_FILENAME = "achievements_locked.png";
|
||||
static constexpr std::string_view DEFAULT_UNLOCKED_BADGE_FILENAME = "achievements_unlocked.png";
|
||||
static constexpr std::string_view GRAY = "transparent";
|
||||
static constexpr std::string_view GOLD = "#FFD700";
|
||||
static constexpr std::string_view BLUE = "#0B71C1";
|
||||
static constexpr std::string_view APPROVED_LIST_FILENAME = "ApprovedInis.json";
|
||||
static const inline Common::SHA1::Digest APPROVED_LIST_HASH = {
|
||||
0x50, 0x2F, 0x58, 0x02, 0x94, 0x60, 0x1B, 0x9F, 0x92, 0xC7,
|
||||
0x04, 0x17, 0x50, 0x2E, 0xF3, 0x09, 0x8C, 0x8C, 0xD6, 0xC0};
|
||||
|
||||
struct LeaderboardEntry
|
||||
{
|
||||
|
@ -96,27 +108,36 @@ public:
|
|||
bool HasAPIToken() const;
|
||||
void LoadGame(const std::string& file_path, const DiscIO::Volume* volume);
|
||||
bool IsGameLoaded() const;
|
||||
void SetBackgroundExecutionAllowed(bool allowed);
|
||||
|
||||
void FetchPlayerBadge();
|
||||
void FetchGameBadges();
|
||||
|
||||
void DoFrame();
|
||||
|
||||
bool CanPause();
|
||||
void DoIdle();
|
||||
|
||||
std::recursive_mutex& GetLock();
|
||||
void SetHardcoreMode();
|
||||
bool IsHardcoreModeActive() const;
|
||||
void SetGameIniId(const std::string& game_ini_id) { m_game_ini_id = game_ini_id; }
|
||||
void FilterApprovedPatches(std::vector<PatchEngine::Patch>& patches,
|
||||
const std::string& game_ini_id) const;
|
||||
void SetSpectatorMode();
|
||||
std::string_view GetPlayerDisplayName() const;
|
||||
u32 GetPlayerScore() const;
|
||||
const BadgeStatus& GetPlayerBadge() const;
|
||||
const Badge& GetPlayerBadge() const;
|
||||
std::string_view GetGameDisplayName() const;
|
||||
rc_client_t* GetClient();
|
||||
rc_api_fetch_game_data_response_t* GetGameData();
|
||||
const BadgeStatus& GetGameBadge() const;
|
||||
const BadgeStatus& GetAchievementBadge(AchievementId id, bool locked) const;
|
||||
const Badge& GetGameBadge() const;
|
||||
const Badge& GetAchievementBadge(AchievementId id, bool locked) const;
|
||||
const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id);
|
||||
RichPresence GetRichPresence() const;
|
||||
const NamedIconMap& GetChallengeIcons() const;
|
||||
bool AreChallengesUpdated() const;
|
||||
void ResetChallengesUpdated();
|
||||
const std::unordered_set<AchievementId>& GetActiveChallenges() const;
|
||||
std::vector<std::string> GetActiveLeaderboards() const;
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
|
@ -134,7 +155,7 @@ private:
|
|||
std::unique_ptr<DiscIO::Volume> volume;
|
||||
};
|
||||
|
||||
const BadgeStatus m_default_badge;
|
||||
static picojson::value LoadApprovedList();
|
||||
|
||||
static void* FilereaderOpenByFilepath(const char* path_utf8);
|
||||
static void* FilereaderOpenByVolume(const char* path_utf8);
|
||||
|
@ -143,12 +164,13 @@ private:
|
|||
static size_t FilereaderRead(void* file_handle, void* buffer, size_t requested_bytes);
|
||||
static void FilereaderClose(void* file_handle);
|
||||
|
||||
void LoadDefaultBadges();
|
||||
static void LoginCallback(int result, const char* error_message, rc_client_t* client,
|
||||
void* userdata);
|
||||
|
||||
void FetchBoardInfo(AchievementId leaderboard_id);
|
||||
|
||||
std::unique_ptr<DiscIO::Volume>& GetLoadingVolume() { return m_loading_volume; };
|
||||
std::unique_ptr<DiscIO::Volume>& GetLoadingVolume() { return m_loading_volume; }
|
||||
|
||||
static void LoadGameCallback(int result, const char* error_message, rc_client_t* client,
|
||||
void* userdata);
|
||||
|
@ -176,31 +198,42 @@ private:
|
|||
|
||||
static void Request(const rc_api_request_t* request, rc_client_server_callback_t callback,
|
||||
void* callback_data, rc_client_t* client);
|
||||
static u32 MemoryVerifier(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
|
||||
static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client);
|
||||
void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function,
|
||||
void FetchBadge(Badge* badge, u32 badge_type, const BadgeNameFunction function,
|
||||
const UpdatedItems callback_data);
|
||||
static void EventHandler(const rc_client_event_t* event, rc_client_t* client);
|
||||
|
||||
rc_runtime_t m_runtime{};
|
||||
rc_client_t* m_client{};
|
||||
Core::System* m_system{};
|
||||
std::atomic<Core::System*> m_system{};
|
||||
bool m_is_runtime_initialized = false;
|
||||
UpdateCallback m_update_callback = [](const UpdatedItems&) {};
|
||||
std::unique_ptr<DiscIO::Volume> m_loading_volume;
|
||||
BadgeStatus m_player_badge;
|
||||
Badge m_default_player_badge;
|
||||
Badge m_default_game_badge;
|
||||
Badge m_default_unlocked_badge;
|
||||
Badge m_default_locked_badge;
|
||||
std::atomic_bool m_background_execution_allowed = true;
|
||||
Badge m_player_badge;
|
||||
Hash m_game_hash{};
|
||||
u32 m_game_id = 0;
|
||||
rc_api_fetch_game_data_response_t m_game_data{};
|
||||
bool m_is_game_loaded = false;
|
||||
BadgeStatus m_game_badge;
|
||||
Badge m_game_badge;
|
||||
bool m_display_welcome_message = false;
|
||||
std::unordered_map<AchievementId, BadgeStatus> m_unlocked_badges;
|
||||
std::unordered_map<AchievementId, BadgeStatus> m_locked_badges;
|
||||
std::unordered_map<AchievementId, Badge> m_unlocked_badges;
|
||||
std::unordered_map<AchievementId, Badge> m_locked_badges;
|
||||
RichPresence m_rich_presence;
|
||||
std::chrono::steady_clock::time_point m_last_rp_time = std::chrono::steady_clock::now();
|
||||
std::chrono::steady_clock::time_point m_last_progress_message = std::chrono::steady_clock::now();
|
||||
|
||||
Common::Lazy<picojson::value> m_ini_root{LoadApprovedList};
|
||||
std::string m_game_ini_id;
|
||||
|
||||
std::unordered_map<AchievementId, LeaderboardStatus> m_leaderboard_map;
|
||||
NamedIconMap m_active_challenges;
|
||||
bool m_challenges_updated = false;
|
||||
std::unordered_set<AchievementId> m_active_challenges;
|
||||
std::vector<rc_client_leaderboard_tracker_t> m_active_leaderboards;
|
||||
|
||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||
|
@ -209,4 +242,33 @@ private:
|
|||
std::recursive_mutex m_filereader_lock;
|
||||
}; // class AchievementManager
|
||||
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class Volume;
|
||||
}
|
||||
|
||||
class AchievementManager
|
||||
{
|
||||
public:
|
||||
static AchievementManager& GetInstance()
|
||||
{
|
||||
static AchievementManager s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
constexpr bool IsHardcoreModeActive() { return false; }
|
||||
|
||||
constexpr void LoadGame(const std::string&, const DiscIO::Volume*) {}
|
||||
|
||||
constexpr void SetBackgroundExecutionAllowed(bool allowed) {}
|
||||
|
||||
constexpr void DoFrame() {}
|
||||
|
||||
constexpr void CloseGame() {}
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -18,7 +18,7 @@ class IniFile;
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace ActionReplay
|
||||
{
|
||||
|
|
|
@ -235,7 +235,7 @@ std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(std::vector<std
|
|||
|
||||
static const std::unordered_set<std::string> disc_image_extensions = {
|
||||
{".gcm", ".iso", ".tgc", ".wbfs", ".ciso", ".gcz", ".wia", ".rvz", ".nfs", ".dol", ".elf"}};
|
||||
if (disc_image_extensions.find(extension) != disc_image_extensions.end())
|
||||
if (disc_image_extensions.contains(extension))
|
||||
{
|
||||
std::unique_ptr<DiscIO::VolumeDisc> disc = DiscIO::CreateDisc(path);
|
||||
if (disc)
|
||||
|
@ -575,9 +575,7 @@ bool CBoot::BootUp(Core::System& system, const Core::CPUThreadGuard& guard,
|
|||
SetupGCMemory(system, guard);
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().LoadGame(executable.path, nullptr);
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
if (!executable.reader->LoadIntoMemory(system))
|
||||
{
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
bool IsValid() const override { return m_is_valid; }
|
||||
bool IsWii() const override { return m_is_wii; }
|
||||
bool IsAncast() const { return m_is_ancast; };
|
||||
bool IsAncast() const { return m_is_ancast; }
|
||||
u32 GetEntryPoint() const override { return m_dolheader.entryPoint; }
|
||||
bool LoadIntoMemory(Core::System& system, bool only_in_mem1 = false) const override;
|
||||
bool LoadSymbols(const Core::CPUThreadGuard& guard, PPCSymbolDB& ppc_symbol_db) const override
|
||||
|
|
|
@ -166,9 +166,7 @@ bool BootCore(Core::System& system, std::unique_ptr<BootParameters> boot,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().CloseGame();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
const bool load_ipl = !system.IsWii() && !Config::Get(Config::MAIN_SKIP_IPL) &&
|
||||
std::holds_alternative<BootParameters::Disc>(boot->parameters);
|
||||
|
@ -211,8 +209,7 @@ static void RestoreSYSCONF()
|
|||
},
|
||||
setting.config_info);
|
||||
}
|
||||
// Save the SYSCONF.
|
||||
Config::GetLayer(Config::LayerType::Base)->Save();
|
||||
ConfigLoaders::SaveToSYSCONF(Config::LayerType::Base);
|
||||
}
|
||||
|
||||
void RestoreConfig()
|
||||
|
|
|
@ -485,8 +485,10 @@ add_library(core
|
|||
PowerPC/BreakPoints.h
|
||||
PowerPC/CachedInterpreter/CachedInterpreter.cpp
|
||||
PowerPC/CachedInterpreter/CachedInterpreter.h
|
||||
PowerPC/CachedInterpreter/InterpreterBlockCache.cpp
|
||||
PowerPC/CachedInterpreter/InterpreterBlockCache.h
|
||||
PowerPC/CachedInterpreter/CachedInterpreterBlockCache.cpp
|
||||
PowerPC/CachedInterpreter/CachedInterpreterBlockCache.h
|
||||
PowerPC/CachedInterpreter/CachedInterpreterEmitter.cpp
|
||||
PowerPC/CachedInterpreter/CachedInterpreterEmitter.h
|
||||
PowerPC/ConditionRegister.cpp
|
||||
PowerPC/ConditionRegister.h
|
||||
PowerPC/Expression.cpp
|
||||
|
@ -783,7 +785,7 @@ if(MSVC)
|
|||
endif()
|
||||
|
||||
if(USE_RETRO_ACHIEVEMENTS)
|
||||
target_link_libraries(core PRIVATE rcheevos)
|
||||
target_compile_definitions(core PRIVATE -DUSE_RETRO_ACHIEVEMENTS)
|
||||
target_compile_definitions(core PRIVATE -DRC_CLIENT_SUPPORTS_HASH)
|
||||
target_link_libraries(core PUBLIC rcheevos)
|
||||
target_compile_definitions(core PUBLIC -DUSE_RETRO_ACHIEVEMENTS)
|
||||
target_compile_definitions(core PUBLIC -DRC_CLIENT_SUPPORTS_HASH)
|
||||
endif()
|
||||
|
|
|
@ -38,7 +38,7 @@ void OnConfigChanged()
|
|||
}
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
} // namespace
|
||||
|
||||
namespace CPUThreadConfigCallback
|
||||
{
|
||||
|
@ -73,4 +73,4 @@ void CheckForConfigChanges()
|
|||
RunCallbacks();
|
||||
}
|
||||
|
||||
}; // namespace CPUThreadConfigCallback
|
||||
} // namespace CPUThreadConfigCallback
|
||||
|
|
|
@ -27,4 +27,4 @@ void RemoveConfigChangedCallback(ConfigChangedCallbackID callback_id);
|
|||
// Should be called regularly from the CPU thread
|
||||
void CheckForConfigChanges();
|
||||
|
||||
}; // namespace CPUThreadConfigCallback
|
||||
} // namespace CPUThreadConfigCallback
|
||||
|
|
|
@ -207,10 +207,8 @@ Cheats::NewSearch(const Core::CPUThreadGuard& guard,
|
|||
PowerPC::RequestedAddressSpace address_space, bool aligned,
|
||||
const std::function<bool(const T& value)>& validator)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
return Cheats::SearchErrorCode::DisabledInHardcoreMode;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
auto& system = guard.GetSystem();
|
||||
std::vector<Cheats::SearchResult<T>> results;
|
||||
const Core::State core_state = Core::GetState(system);
|
||||
|
@ -262,10 +260,8 @@ Cheats::NextSearch(const Core::CPUThreadGuard& guard,
|
|||
PowerPC::RequestedAddressSpace address_space,
|
||||
const std::function<bool(const T& new_value, const T& old_value)>& validator)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
return Cheats::SearchErrorCode::DisabledInHardcoreMode;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
auto& system = guard.GetSystem();
|
||||
std::vector<Cheats::SearchResult<T>> results;
|
||||
const Core::State core_state = Core::GetState(system);
|
||||
|
@ -429,10 +425,8 @@ MakeCompareFunctionForLastValue(Cheats::CompareType op)
|
|||
template <typename T>
|
||||
Cheats::SearchErrorCode Cheats::CheatSearchSession<T>::RunSearch(const Core::CPUThreadGuard& guard)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
return Cheats::SearchErrorCode::DisabledInHardcoreMode;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
Common::Result<SearchErrorCode, std::vector<SearchResult<T>>> result =
|
||||
Cheats::SearchErrorCode::InvalidParameters;
|
||||
if (m_filter_type == FilterType::CompareAgainstSpecificValue)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Cheats
|
||||
{
|
||||
|
@ -100,10 +100,8 @@ enum class SearchErrorCode
|
|||
// currently off in the emulated game.
|
||||
VirtualAddressesCurrentlyNotAccessible,
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
// Cheats and memory reading are disabled in RetroAchievements hardcore mode.
|
||||
DisabledInHardcoreMode,
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
};
|
||||
|
||||
// Returns the corresponding DataType enum for the value currently held by the given SearchValue.
|
||||
|
|
|
@ -26,7 +26,6 @@ const Info<bool> RA_DISCORD_PRESENCE_ENABLED{
|
|||
{System::Achievements, "Achievements", "DiscordPresenceEnabled"}, false};
|
||||
const Info<bool> RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"},
|
||||
false};
|
||||
const Info<bool> RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false};
|
||||
} // namespace Config
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -20,7 +20,6 @@ extern const Info<bool> RA_ENCORE_ENABLED;
|
|||
extern const Info<bool> RA_SPECTATOR_ENABLED;
|
||||
extern const Info<bool> RA_DISCORD_PRESENCE_ENABLED;
|
||||
extern const Info<bool> RA_PROGRESS_ENABLED;
|
||||
extern const Info<bool> RA_BADGES_ENABLED;
|
||||
} // namespace Config
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -749,22 +749,14 @@ bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot)
|
|||
|
||||
bool AreCheatsEnabled()
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
return Config::Get(::Config::MAIN_ENABLE_CHEATS) &&
|
||||
!AchievementManager::GetInstance().IsHardcoreModeActive();
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
return Config::Get(::Config::MAIN_ENABLE_CHEATS);
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
}
|
||||
|
||||
bool IsDebuggingEnabled()
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
return Config::Get(::Config::MAIN_ENABLE_DEBUGGING) &&
|
||||
!AchievementManager::GetInstance().IsHardcoreModeActive();
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
return Config::Get(::Config::MAIN_ENABLE_DEBUGGING);
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
|
|
|
@ -15,7 +15,7 @@ const Info<u32> SYSCONF_LANGUAGE{{System::SYSCONF, "IPL", "LNG"},
|
|||
const Info<u32> SYSCONF_COUNTRY{{System::SYSCONF, "IPL", "SADR"}, GetDefaultCountry()};
|
||||
const Info<bool> SYSCONF_WIDESCREEN{{System::SYSCONF, "IPL", "AR"}, true};
|
||||
const Info<bool> SYSCONF_PROGRESSIVE_SCAN{{System::SYSCONF, "IPL", "PGS"}, true};
|
||||
const Info<bool> SYSCONF_PAL60{{System::SYSCONF, "IPL", "E60"}, 0x01};
|
||||
const Info<bool> SYSCONF_PAL60{{System::SYSCONF, "IPL", "E60"}, true};
|
||||
const Info<u32> SYSCONF_SOUND_MODE{{System::SYSCONF, "IPL", "SND"}, 0x01};
|
||||
|
||||
// SYSCONF.BT
|
||||
|
|
|
@ -175,11 +175,6 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
|
|||
if (!was_changed)
|
||||
return;
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (game_id != "00000000")
|
||||
AchievementManager::GetInstance().CloseGame();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
if (game_id == "00000000")
|
||||
{
|
||||
m_title_name.clear();
|
||||
|
@ -187,6 +182,8 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
|
|||
return;
|
||||
}
|
||||
|
||||
AchievementManager::GetInstance().CloseGame();
|
||||
|
||||
const Core::TitleDatabase title_database;
|
||||
auto& system = Core::System::GetInstance();
|
||||
const DiscIO::Language language = GetLanguageAdjustedForRegion(system.IsWii(), region);
|
||||
|
@ -194,22 +191,22 @@ void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::stri
|
|||
m_title_description = title_database.Describe(m_gametdb_id, language);
|
||||
NOTICE_LOG_FMT(CORE, "Active title: {}", m_title_description);
|
||||
Host_TitleChanged();
|
||||
if (Core::IsRunning(system))
|
||||
{
|
||||
|
||||
const bool is_running_or_starting = Core::IsRunningOrStarting(system);
|
||||
if (is_running_or_starting)
|
||||
Core::UpdateTitle(system);
|
||||
}
|
||||
|
||||
Config::AddLayer(ConfigLoaders::GenerateGlobalGameConfigLoader(game_id, revision));
|
||||
Config::AddLayer(ConfigLoaders::GenerateLocalGameConfigLoader(game_id, revision));
|
||||
|
||||
if (Core::IsRunning(system))
|
||||
if (is_running_or_starting)
|
||||
DolphinAnalytics::Instance().ReportGameStart();
|
||||
}
|
||||
|
||||
void SConfig::OnNewTitleLoad(const Core::CPUThreadGuard& guard)
|
||||
{
|
||||
auto& system = guard.GetSystem();
|
||||
if (!Core::IsRunning(system))
|
||||
if (!Core::IsRunningOrStarting(system))
|
||||
return;
|
||||
|
||||
auto& ppc_symbol_db = system.GetPPCSymbolDB();
|
||||
|
@ -460,7 +457,14 @@ std::string SConfig::GetGameTDBImageRegionCode(bool wii, DiscIO::Region region)
|
|||
switch (region)
|
||||
{
|
||||
case DiscIO::Region::NTSC_J:
|
||||
{
|
||||
// Taiwanese games share the Japanese region code however their title ID ends with 'W'.
|
||||
// GameTDB differentiates the covers using the code "ZH".
|
||||
if (m_game_id.size() >= 4 && m_game_id.at(3) == 'W')
|
||||
return "ZH";
|
||||
|
||||
return "JA";
|
||||
}
|
||||
case DiscIO::Region::NTSC_U:
|
||||
return "US";
|
||||
case DiscIO::Region::NTSC_K:
|
||||
|
|
|
@ -101,10 +101,6 @@ namespace Core
|
|||
static bool s_wants_determinism;
|
||||
|
||||
// Declarations and definitions
|
||||
static bool s_is_stopping = false;
|
||||
static bool s_hardware_initialized = false;
|
||||
static bool s_is_started = false;
|
||||
static Common::Flag s_is_booting;
|
||||
static std::thread s_emu_thread;
|
||||
static std::vector<StateChangedCallbackFunc> s_on_state_changed_callbacks;
|
||||
|
||||
|
@ -114,6 +110,10 @@ static std::atomic<double> s_last_actual_emulation_speed{1.0};
|
|||
static bool s_frame_step = false;
|
||||
static std::atomic<bool> s_stop_frame_step;
|
||||
|
||||
// The value Paused is never stored in this variable. The core is considered to be in
|
||||
// the Paused state if this variable is Running and the CPU reports that it's stepping.
|
||||
static std::atomic<State> s_state = State::Uninitialized;
|
||||
|
||||
#ifdef USE_MEMORYWATCHER
|
||||
static std::unique_ptr<MemoryWatcher> s_memory_watcher;
|
||||
#endif
|
||||
|
@ -190,7 +190,7 @@ std::string StopMessage(bool main_thread, std::string_view message)
|
|||
|
||||
void DisplayMessage(std::string message, int time_in_ms)
|
||||
{
|
||||
if (!IsRunning(Core::System::GetInstance()))
|
||||
if (!IsRunningOrStarting(Core::System::GetInstance()))
|
||||
return;
|
||||
|
||||
// Actually displaying non-ASCII could cause things to go pear-shaped
|
||||
|
@ -202,12 +202,13 @@ void DisplayMessage(std::string message, int time_in_ms)
|
|||
|
||||
bool IsRunning(Core::System& system)
|
||||
{
|
||||
return (GetState(system) != State::Uninitialized || s_hardware_initialized) && !s_is_stopping;
|
||||
return s_state.load() == State::Running;
|
||||
}
|
||||
|
||||
bool IsRunningAndStarted()
|
||||
bool IsRunningOrStarting(Core::System& system)
|
||||
{
|
||||
return s_is_started && !s_is_stopping;
|
||||
const State state = s_state.load();
|
||||
return state == State::Running || state == State::Starting;
|
||||
}
|
||||
|
||||
bool IsCPUThread()
|
||||
|
@ -262,7 +263,7 @@ bool Init(Core::System& system, std::unique_ptr<BootParameters> boot, const Wind
|
|||
g_video_backend->PrepareWindow(prepared_wsi);
|
||||
|
||||
// Start the emu thread
|
||||
s_is_booting.Set();
|
||||
s_state.store(State::Starting);
|
||||
s_emu_thread = std::thread(EmuThread, std::ref(system), std::move(boot), prepared_wsi);
|
||||
return true;
|
||||
}
|
||||
|
@ -281,17 +282,13 @@ static void ResetRumble()
|
|||
// Called from GUI thread
|
||||
void Stop(Core::System& system) // - Hammertime!
|
||||
{
|
||||
if (const State state = GetState(system);
|
||||
state == State::Stopping || state == State::Uninitialized)
|
||||
{
|
||||
const State state = s_state.load();
|
||||
if (state == State::Stopping || state == State::Uninitialized)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().CloseGame();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
s_is_stopping = true;
|
||||
s_state.store(State::Stopping);
|
||||
|
||||
CallOnStateChangedCallbacks(State::Stopping);
|
||||
|
||||
|
@ -356,7 +353,7 @@ static void CPUSetInitialExecutionState(bool force_paused = false)
|
|||
// SetState must be called on the host thread, so we defer it for later.
|
||||
QueueHostJob([force_paused](Core::System& system) {
|
||||
bool paused = SConfig::GetInstance().bBootToPause || force_paused;
|
||||
SetState(system, paused ? State::Paused : State::Running);
|
||||
SetState(system, paused ? State::Paused : State::Running, true, true);
|
||||
Host_UpdateDisasmDialog();
|
||||
Host_UpdateMainFrame();
|
||||
Host_Message(HostMessageID::WMUserCreate);
|
||||
|
@ -396,11 +393,15 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
|
|||
File::Delete(*savestate_path);
|
||||
}
|
||||
|
||||
s_is_started = true;
|
||||
// If s_state is Starting, change it to Running. But if it's already been set to Stopping
|
||||
// by the host thread, don't change it.
|
||||
State expected = State::Starting;
|
||||
s_state.compare_exchange_strong(expected, State::Running);
|
||||
|
||||
{
|
||||
#ifndef _WIN32
|
||||
std::string gdb_socket = Config::Get(Config::MAIN_GDB_SOCKET);
|
||||
if (!gdb_socket.empty())
|
||||
if (!gdb_socket.empty() && !AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
{
|
||||
GDBStub::InitLocal(gdb_socket.data());
|
||||
CPUSetInitialExecutionState(true);
|
||||
|
@ -409,7 +410,7 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
|
|||
#endif
|
||||
{
|
||||
int gdb_port = Config::Get(Config::MAIN_GDB_PORT);
|
||||
if (gdb_port > 0)
|
||||
if (gdb_port > 0 && !AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
{
|
||||
GDBStub::Init(gdb_port);
|
||||
CPUSetInitialExecutionState(true);
|
||||
|
@ -428,8 +429,6 @@ static void CpuThread(Core::System& system, const std::optional<std::string>& sa
|
|||
s_memory_watcher.reset();
|
||||
#endif
|
||||
|
||||
s_is_started = false;
|
||||
|
||||
if (exception_handler)
|
||||
EMM::UninstallExceptionHandler();
|
||||
|
||||
|
@ -455,12 +454,15 @@ static void FifoPlayerThread(Core::System& system, const std::optional<std::stri
|
|||
if (auto cpu_core = system.GetFifoPlayer().GetCPUCore())
|
||||
{
|
||||
system.GetPowerPC().InjectExternalCPUCore(cpu_core.get());
|
||||
s_is_started = true;
|
||||
|
||||
// If s_state is Starting, change it to Running. But if it's already been set to Stopping
|
||||
// by the host thread, don't change it.
|
||||
State expected = State::Starting;
|
||||
s_state.compare_exchange_strong(expected, State::Running);
|
||||
|
||||
CPUSetInitialExecutionState();
|
||||
system.GetCPU().Run();
|
||||
|
||||
s_is_started = false;
|
||||
system.GetPowerPC().InjectExternalCPUCore(nullptr);
|
||||
system.GetFifoPlayer().Close();
|
||||
}
|
||||
|
@ -481,10 +483,7 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
|||
{
|
||||
CallOnStateChangedCallbacks(State::Starting);
|
||||
Common::ScopeGuard flag_guard{[] {
|
||||
s_is_booting.Clear();
|
||||
s_is_started = false;
|
||||
s_is_stopping = false;
|
||||
s_wants_determinism = false;
|
||||
s_state.store(State::Uninitialized);
|
||||
|
||||
CallOnStateChangedCallbacks(State::Uninitialized);
|
||||
|
||||
|
@ -562,8 +561,6 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
|||
NetPlay::NetPlay_RegisterEvents();
|
||||
|
||||
Common::ScopeGuard hw_guard{[&system] {
|
||||
// We must set up this flag before executing HW::Shutdown()
|
||||
s_hardware_initialized = false;
|
||||
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "Shutting down HW"));
|
||||
HW::Shutdown(system);
|
||||
INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "HW shutdown"));
|
||||
|
@ -607,10 +604,6 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
|||
|
||||
AudioCommon::PostInitSoundStream(system);
|
||||
|
||||
// The hardware is initialized.
|
||||
s_hardware_initialized = true;
|
||||
s_is_booting.Clear();
|
||||
|
||||
// Set execution state to known values (CPU/FIFO/Audio Paused)
|
||||
system.GetCPU().Break();
|
||||
|
||||
|
@ -703,24 +696,32 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> boot
|
|||
|
||||
// Set or get the running state
|
||||
|
||||
void SetState(Core::System& system, State state, bool report_state_change)
|
||||
void SetState(Core::System& system, State state, bool report_state_change,
|
||||
bool initial_execution_state)
|
||||
{
|
||||
// State cannot be controlled until the CPU Thread is operational
|
||||
if (!IsRunningAndStarted())
|
||||
if (s_state.load() != State::Running)
|
||||
return;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case State::Paused:
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (!initial_execution_state && !AchievementManager::GetInstance().CanPause())
|
||||
return;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
// NOTE: GetState() will return State::Paused immediately, even before anything has
|
||||
// stopped (including the CPU).
|
||||
system.GetCPU().EnableStepping(true); // Break
|
||||
system.GetCPU().SetStepping(true); // Break
|
||||
Wiimote::Pause();
|
||||
ResetRumble();
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().DoIdle();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
break;
|
||||
case State::Running:
|
||||
{
|
||||
system.GetCPU().EnableStepping(false);
|
||||
system.GetCPU().SetStepping(false);
|
||||
Wiimote::Resume();
|
||||
break;
|
||||
}
|
||||
|
@ -737,21 +738,11 @@ void SetState(Core::System& system, State state, bool report_state_change)
|
|||
|
||||
State GetState(Core::System& system)
|
||||
{
|
||||
if (s_is_stopping)
|
||||
return State::Stopping;
|
||||
|
||||
if (s_hardware_initialized)
|
||||
{
|
||||
if (system.GetCPU().IsStepping())
|
||||
return State::Paused;
|
||||
|
||||
return State::Running;
|
||||
}
|
||||
|
||||
if (s_is_booting.IsSet())
|
||||
return State::Starting;
|
||||
|
||||
return State::Uninitialized;
|
||||
const State state = s_state.load();
|
||||
if (state == State::Running && system.GetCPU().IsStepping())
|
||||
return State::Paused;
|
||||
else
|
||||
return state;
|
||||
}
|
||||
|
||||
static std::string GenerateScreenshotFolderPath()
|
||||
|
@ -805,7 +796,7 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl
|
|||
{
|
||||
// WARNING: PauseAndLock is not fully threadsafe so is only valid on the Host Thread
|
||||
|
||||
if (!IsRunningAndStarted())
|
||||
if (!IsRunning(system))
|
||||
return true;
|
||||
|
||||
bool was_unpaused = true;
|
||||
|
@ -833,7 +824,7 @@ static bool PauseAndLock(Core::System& system, bool do_lock, bool unpause_on_unl
|
|||
// The CPU is responsible for managing the Audio and FIFO state so we use its
|
||||
// mechanism to unpause them. If we unpaused the systems above when releasing
|
||||
// the locks then they could call CPU::Break which would require detecting it
|
||||
// and re-pausing with CPU::EnableStepping.
|
||||
// and re-pausing with CPU::SetStepping.
|
||||
was_unpaused = system.GetCPU().PauseAndLock(false, unpause_on_unlock, true);
|
||||
}
|
||||
|
||||
|
@ -911,9 +902,7 @@ void Callback_NewField(Core::System& system)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().DoFrame();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
}
|
||||
|
||||
void UpdateTitle(Core::System& system)
|
||||
|
@ -1034,13 +1023,12 @@ void HostDispatchJobs(Core::System& system)
|
|||
HostJob job = std::move(s_host_jobs_queue.front());
|
||||
s_host_jobs_queue.pop();
|
||||
|
||||
// NOTE: Memory ordering is important. The booting flag needs to be
|
||||
// checked first because the state transition is:
|
||||
// Core::State::Uninitialized: s_is_booting -> s_hardware_initialized
|
||||
// We need to check variables in the same order as the state
|
||||
// transition, otherwise we race and get transient failures.
|
||||
if (!job.run_after_stop && !s_is_booting.IsSet() && !IsRunning(system))
|
||||
continue;
|
||||
if (!job.run_after_stop)
|
||||
{
|
||||
const State state = s_state.load();
|
||||
if (state == State::Stopping || state == State::Uninitialized)
|
||||
continue;
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
job.job(system);
|
||||
|
@ -1051,13 +1039,11 @@ void HostDispatchJobs(Core::System& system)
|
|||
// NOTE: Host Thread
|
||||
void DoFrameStep(Core::System& system)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
{
|
||||
OSD::AddMessage("Frame stepping is disabled in RetroAchievements hardcore mode");
|
||||
return;
|
||||
}
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
if (GetState(system) == State::Paused)
|
||||
{
|
||||
// if already paused, frame advance for 1 frame
|
||||
|
@ -1076,7 +1062,8 @@ void UpdateInputGate(bool require_focus, bool require_full_focus)
|
|||
{
|
||||
// If the user accepts background input, controls should pass even if an on screen interface is on
|
||||
const bool focus_passes =
|
||||
!require_focus || (Host_RendererHasFocus() && !Host_UIBlocksControllerState());
|
||||
!require_focus ||
|
||||
((Host_RendererHasFocus() || Host_TASInputHasFocus()) && !Host_UIBlocksControllerState());
|
||||
// Ignore full focus if we don't require basic focus
|
||||
const bool full_focus_passes =
|
||||
!require_focus || !require_full_focus || (focus_passes && Host_RendererHasFullFocus());
|
||||
|
|
|
@ -135,15 +135,16 @@ void UndeclareAsHostThread();
|
|||
std::string StopMessage(bool main_thread, std::string_view message);
|
||||
|
||||
bool IsRunning(Core::System& system);
|
||||
bool IsRunningAndStarted(); // is running and the CPU loop has been entered
|
||||
bool IsCPUThread(); // this tells us whether we are the CPU thread.
|
||||
bool IsRunningOrStarting(Core::System& system);
|
||||
bool IsCPUThread(); // this tells us whether we are the CPU thread.
|
||||
bool IsGPUThread();
|
||||
bool IsHostThread();
|
||||
|
||||
bool WantsDeterminism();
|
||||
|
||||
// [NOT THREADSAFE] For use by Host only
|
||||
void SetState(Core::System& system, State state, bool report_state_change = true);
|
||||
void SetState(Core::System& system, State state, bool report_state_change = true,
|
||||
bool initial_execution_state = false);
|
||||
State GetState(Core::System& system);
|
||||
|
||||
void SaveScreenShot();
|
||||
|
|
|
@ -73,7 +73,7 @@ EventType* CoreTimingManager::RegisterEvent(const std::string& name, TimedCallba
|
|||
{
|
||||
// check for existing type with same name.
|
||||
// we want event type names to remain unique so that we can use them for serialization.
|
||||
ASSERT_MSG(POWERPC, m_event_types.find(name) == m_event_types.end(),
|
||||
ASSERT_MSG(POWERPC, !m_event_types.contains(name),
|
||||
"CoreTiming Event \"{}\" is already registered. Events should only be registered "
|
||||
"during Init to avoid breaking save states.",
|
||||
name);
|
||||
|
@ -138,7 +138,6 @@ void CoreTimingManager::RefreshConfig()
|
|||
|
||||
m_max_variance = std::chrono::duration_cast<DT>(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE)));
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive() &&
|
||||
Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f &&
|
||||
Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f)
|
||||
|
@ -147,7 +146,6 @@ void CoreTimingManager::RefreshConfig()
|
|||
m_emulation_speed = 1.0f;
|
||||
OSD::AddMessage("Minimum speed is 100% in Hardcore Mode");
|
||||
}
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
m_emulation_speed = Config::Get(Config::MAIN_EMULATION_SPEED);
|
||||
}
|
||||
|
@ -305,13 +303,12 @@ void CoreTimingManager::ScheduleExternalEvent(u64 timepoint, EventType* event_ty
|
|||
|
||||
void CoreTimingManager::RemoveEvent(EventType* event_type)
|
||||
{
|
||||
auto itr = std::remove_if(m_event_queue.begin(), m_event_queue.end(),
|
||||
[&](const Event& e) { return e.type == event_type; });
|
||||
const size_t erased =
|
||||
std::erase_if(m_event_queue, [&](const Event& e) { return e.type == event_type; });
|
||||
|
||||
// Removing random items breaks the invariant so we have to re-establish it.
|
||||
if (itr != m_event_queue.end())
|
||||
if (erased != 0)
|
||||
{
|
||||
m_event_queue.erase(itr, m_event_queue.end());
|
||||
std::make_heap(m_event_queue.begin(), m_event_queue.end(), std::greater<Event>());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,7 +142,7 @@ public:
|
|||
m_collection_pf.size();
|
||||
}
|
||||
std::size_t GetBlacklistSize() const { return m_blacklist_size; }
|
||||
Phase GetRecordingPhase() const { return m_recording_phase; };
|
||||
Phase GetRecordingPhase() const { return m_recording_phase; }
|
||||
|
||||
// An empty selection in reduction mode can't be reconstructed when loading from a file.
|
||||
bool CanSave() const { return !(m_recording_phase == Phase::Reduction && m_selection.empty()); }
|
||||
|
|
|
@ -189,7 +189,6 @@ AutoStepResults CodeTrace::AutoStepping(const Core::CPUThreadGuard& guard, bool
|
|||
stop_condition = HitType::ACTIVE;
|
||||
|
||||
auto& power_pc = guard.GetSystem().GetPowerPC();
|
||||
power_pc.GetBreakPoints().ClearAllTemporary();
|
||||
using clock = std::chrono::steady_clock;
|
||||
clock::time_point timeout = clock::now() + std::chrono::seconds(4);
|
||||
|
||||
|
|
|
@ -73,8 +73,8 @@ public:
|
|||
}
|
||||
virtual bool IsAlive() const { return true; }
|
||||
virtual bool IsBreakpoint(u32 /*address*/) const { return false; }
|
||||
virtual void SetBreakpoint(u32 /*address*/) {}
|
||||
virtual void ClearBreakpoint(u32 /*address*/) {}
|
||||
virtual void AddBreakpoint(u32 /*address*/) {}
|
||||
virtual void RemoveBreakpoint(u32 /*address*/) {}
|
||||
virtual void ClearAllBreakpoints() {}
|
||||
virtual void ToggleBreakpoint(u32 /*address*/) {}
|
||||
virtual void ClearAllMemChecks() {}
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
virtual u32 GetPC() const { return 0; }
|
||||
virtual void SetPC(u32 /*address*/) {}
|
||||
virtual void Step() {}
|
||||
virtual void RunToBreakpoint() {}
|
||||
virtual void RunTo(u32 /*address*/) {}
|
||||
virtual u32 GetColor(const CPUThreadGuard* /*guard*/, u32 /*address*/) const
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Core::Debug
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Debugger/OSThread.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
|
@ -30,10 +31,9 @@
|
|||
void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPatch& patch,
|
||||
bool store_existing_value)
|
||||
{
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
if (AchievementManager::GetInstance().IsHardcoreModeActive())
|
||||
return;
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
if (patch.value.empty())
|
||||
return;
|
||||
|
||||
|
@ -350,7 +350,7 @@ u32 PPCDebugInterface::ReadInstruction(const Core::CPUThreadGuard& guard, u32 ad
|
|||
|
||||
bool PPCDebugInterface::IsAlive() const
|
||||
{
|
||||
return Core::IsRunningAndStarted();
|
||||
return Core::IsRunning(m_system);
|
||||
}
|
||||
|
||||
bool PPCDebugInterface::IsBreakpoint(u32 address) const
|
||||
|
@ -358,12 +358,12 @@ bool PPCDebugInterface::IsBreakpoint(u32 address) const
|
|||
return m_system.GetPowerPC().GetBreakPoints().IsAddressBreakPoint(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::SetBreakpoint(u32 address)
|
||||
void PPCDebugInterface::AddBreakpoint(u32 address)
|
||||
{
|
||||
m_system.GetPowerPC().GetBreakPoints().Add(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::ClearBreakpoint(u32 address)
|
||||
void PPCDebugInterface::RemoveBreakpoint(u32 address)
|
||||
{
|
||||
m_system.GetPowerPC().GetBreakPoints().Remove(address);
|
||||
}
|
||||
|
@ -375,11 +375,7 @@ void PPCDebugInterface::ClearAllBreakpoints()
|
|||
|
||||
void PPCDebugInterface::ToggleBreakpoint(u32 address)
|
||||
{
|
||||
auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
|
||||
if (breakpoints.IsAddressBreakPoint(address))
|
||||
breakpoints.Remove(address);
|
||||
else
|
||||
breakpoints.Add(address);
|
||||
m_system.GetPowerPC().GetBreakPoints().ToggleBreakPoint(address);
|
||||
}
|
||||
|
||||
void PPCDebugInterface::ClearAllMemChecks()
|
||||
|
@ -507,8 +503,11 @@ void PPCDebugInterface::SetPC(u32 address)
|
|||
m_system.GetPPCState().pc = address;
|
||||
}
|
||||
|
||||
void PPCDebugInterface::RunToBreakpoint()
|
||||
void PPCDebugInterface::RunTo(u32 address)
|
||||
{
|
||||
auto& breakpoints = m_system.GetPowerPC().GetBreakPoints();
|
||||
breakpoints.SetTemporary(address);
|
||||
m_system.GetCPU().SetStepping(false);
|
||||
}
|
||||
|
||||
std::shared_ptr<Core::NetworkCaptureLogger> PPCDebugInterface::NetworkLogger()
|
||||
|
|
|
@ -80,8 +80,8 @@ public:
|
|||
u32 address) const override;
|
||||
bool IsAlive() const override;
|
||||
bool IsBreakpoint(u32 address) const override;
|
||||
void SetBreakpoint(u32 address) override;
|
||||
void ClearBreakpoint(u32 address) override;
|
||||
void AddBreakpoint(u32 address) override;
|
||||
void RemoveBreakpoint(u32 address) override;
|
||||
void ClearAllBreakpoints() override;
|
||||
void ToggleBreakpoint(u32 address) override;
|
||||
void ClearAllMemChecks() override;
|
||||
|
@ -100,7 +100,7 @@ public:
|
|||
u32 GetPC() const override;
|
||||
void SetPC(u32 address) override;
|
||||
void Step() override {}
|
||||
void RunToBreakpoint() override;
|
||||
void RunTo(u32 address) override;
|
||||
u32 GetColor(const Core::CPUThreadGuard* guard, u32 address) const override;
|
||||
std::string_view GetDescription(u32 address) const override;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class PPCSymbolDB;
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
struct RSOEntry
|
||||
{
|
||||
|
|
|
@ -228,7 +228,7 @@ public:
|
|||
IsPlayingBackFifologWithBrokenEFBCopies = m_parent->m_File->HasBrokenEFBCopies();
|
||||
// Without this call, we deadlock in initialization in dual core, as the FIFO is disabled and
|
||||
// thus ClearEfb()'s call to WaitForGPUInactive() never returns
|
||||
m_parent->m_system.GetCPU().EnableStepping(false);
|
||||
m_parent->m_system.GetCPU().SetStepping(false);
|
||||
|
||||
m_parent->m_CurrentFrame = m_parent->m_FrameRangeStart;
|
||||
m_parent->LoadMemory();
|
||||
|
@ -243,7 +243,7 @@ public:
|
|||
void SingleStep() override
|
||||
{
|
||||
// NOTE: AdvanceFrame() will get stuck forever in Dual Core because the FIFO
|
||||
// is disabled by CPU::EnableStepping(true) so the frame never gets displayed.
|
||||
// is disabled by CPU::SetStepping(true) so the frame never gets displayed.
|
||||
PanicAlertFmtT("Cannot SingleStep the FIFO. Use Frame Advance instead.");
|
||||
}
|
||||
|
||||
|
|
|
@ -46,11 +46,7 @@ void Config::Refresh()
|
|||
}
|
||||
|
||||
camera_config.control_type = ::Config::Get(::Config::FL1_CONTROL_TYPE);
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
enabled = ::Config::Get(::Config::FREE_LOOK_ENABLED) &&
|
||||
!AchievementManager::GetInstance().IsHardcoreModeActive();
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
enabled = ::Config::Get(::Config::FREE_LOOK_ENABLED);
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
}
|
||||
} // namespace FreeLook
|
||||
|
|
|
@ -14,7 +14,7 @@ class PointerWrap;
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
namespace Core
|
||||
{
|
||||
class CPUThreadGuard;
|
||||
};
|
||||
}
|
||||
|
||||
namespace HLE_OS
|
||||
{
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HLE/HLE_VarArgs.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
HLE::SystemVABI::VAList::~VAList() = default;
|
||||
|
||||
u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const
|
||||
|
|
|
@ -120,7 +120,7 @@ struct EffectiveAddressSpaceAccessors : Accessors
|
|||
float ReadF32(const Core::CPUThreadGuard& guard, u32 address) const override
|
||||
{
|
||||
return PowerPC::MMU::HostRead_F32(guard, address);
|
||||
};
|
||||
}
|
||||
|
||||
bool Matches(const Core::CPUThreadGuard& guard, u32 haystack_start, const u8* needle_start,
|
||||
std::size_t needle_size) const
|
||||
|
|
|
@ -85,22 +85,20 @@ void CPUManager::Run()
|
|||
m_state_cpu_thread_active = true;
|
||||
state_lock.unlock();
|
||||
|
||||
// Adjust PC for JIT when debugging
|
||||
// Adjust PC when debugging
|
||||
// SingleStep so that the "continue", "step over" and "step out" debugger functions
|
||||
// work when the PC is at a breakpoint at the beginning of the block
|
||||
// Don't use PowerPCManager::CheckBreakPoints, otherwise you get double logging
|
||||
// If watchpoints are enabled, any instruction could be a breakpoint.
|
||||
if (power_pc.GetMode() != PowerPC::CoreMode::Interpreter)
|
||||
if (power_pc.GetBreakPoints().IsAddressBreakPoint(power_pc.GetPPCState().pc) ||
|
||||
power_pc.GetMemChecks().HasAny())
|
||||
{
|
||||
if (power_pc.GetBreakPoints().IsAddressBreakPoint(power_pc.GetPPCState().pc) ||
|
||||
power_pc.GetMemChecks().HasAny())
|
||||
{
|
||||
m_state = State::Stepping;
|
||||
PowerPC::CoreMode old_mode = power_pc.GetMode();
|
||||
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
|
||||
power_pc.SingleStep();
|
||||
power_pc.SetMode(old_mode);
|
||||
m_state = State::Running;
|
||||
}
|
||||
m_state = State::Stepping;
|
||||
PowerPC::CoreMode old_mode = power_pc.GetMode();
|
||||
power_pc.SetMode(PowerPC::CoreMode::Interpreter);
|
||||
power_pc.SingleStep();
|
||||
power_pc.SetMode(old_mode);
|
||||
m_state = State::Running;
|
||||
}
|
||||
|
||||
// Enter a fast runloop
|
||||
|
@ -174,7 +172,7 @@ void CPUManager::Run()
|
|||
// Requires holding m_state_change_lock
|
||||
void CPUManager::RunAdjacentSystems(bool running)
|
||||
{
|
||||
// NOTE: We're assuming these will not try to call Break or EnableStepping.
|
||||
// NOTE: We're assuming these will not try to call Break or SetStepping.
|
||||
m_system.GetFifo().EmulatorState(running);
|
||||
// Core is responsible for shutting down the sound stream.
|
||||
if (m_state != State::PowerDown)
|
||||
|
@ -243,11 +241,13 @@ bool CPUManager::SetStateLocked(State s)
|
|||
{
|
||||
if (m_state == State::PowerDown)
|
||||
return false;
|
||||
if (s == State::Stepping)
|
||||
m_system.GetPowerPC().GetBreakPoints().ClearTemporary();
|
||||
m_state = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPUManager::EnableStepping(bool stepping)
|
||||
void CPUManager::SetStepping(bool stepping)
|
||||
{
|
||||
std::lock_guard stepping_lock(m_stepping_lock);
|
||||
std::unique_lock state_lock(m_state_change_lock);
|
||||
|
@ -290,7 +290,7 @@ void CPUManager::Break()
|
|||
|
||||
void CPUManager::Continue()
|
||||
{
|
||||
EnableStepping(false);
|
||||
SetStepping(false);
|
||||
Core::CallOnStateChangedCallbacks(Core::State::Running);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,10 +62,10 @@ public:
|
|||
void StepOpcode(Common::Event* event = nullptr);
|
||||
|
||||
// Enable or Disable Stepping. [Will deadlock if called from a system thread]
|
||||
void EnableStepping(bool stepping);
|
||||
void SetStepping(bool stepping);
|
||||
|
||||
// Breakpoint activation for system threads. Similar to EnableStepping(true).
|
||||
// NOTE: Unlike EnableStepping, this does NOT synchronize with the CPU Thread
|
||||
// Breakpoint activation for system threads. Similar to SetStepping(true).
|
||||
// NOTE: Unlike SetStepping, this does NOT synchronize with the CPU Thread
|
||||
// which enables it to avoid deadlocks but also makes it less safe so it
|
||||
// should not be used by the Host.
|
||||
void Break();
|
||||
|
@ -91,7 +91,7 @@ public:
|
|||
// Return value for do_lock == true is whether the state was State::Running or not.
|
||||
// Return value for do_lock == false is whether the state was changed *to* State::Running or not.
|
||||
// Cannot be used by System threads as it will deadlock. It is threadsafe otherwise.
|
||||
// "control_adjacent" causes PauseAndLock to behave like EnableStepping by modifying the
|
||||
// "control_adjacent" causes PauseAndLock to behave like SetStepping by modifying the
|
||||
// state of the Audio and FIFO subsystems as well.
|
||||
bool PauseAndLock(bool do_lock, bool unpause_on_unlock = true, bool control_adjacent = false);
|
||||
|
||||
|
@ -110,9 +110,9 @@ private:
|
|||
// Read access is unsynchronized.
|
||||
State m_state = State::PowerDown;
|
||||
|
||||
// Synchronizes EnableStepping and PauseAndLock so only one instance can be
|
||||
// Synchronizes SetStepping and PauseAndLock so only one instance can be
|
||||
// active at a time. Simplifies code by eliminating several edge cases where
|
||||
// the EnableStepping(true)/PauseAndLock(true) case must release the state lock
|
||||
// the SetStepping(true)/PauseAndLock(true) case must release the state lock
|
||||
// and wait for the CPU Thread which would otherwise require additional flags.
|
||||
// NOTE: When using the stepping lock, it must always be acquired first. If
|
||||
// the lock is acquired after the state lock then that is guaranteed to
|
||||
|
|
|
@ -143,7 +143,7 @@ protected:
|
|||
pb_mem[update_off] = update_val;
|
||||
}
|
||||
|
||||
Common::BitCastFromArray<u16>(pb_mem, pb);
|
||||
pb = std::bit_cast<PBType>(pb_mem);
|
||||
}
|
||||
|
||||
virtual void HandleCommandList();
|
||||
|
|
|
@ -397,7 +397,7 @@ bool AXWiiUCode::ExtractUpdatesFields(AXPBWii& pb, u16* num_updates, u16* update
|
|||
// Remove the updates data from the PB
|
||||
memmove(&pb_mem[41], &pb_mem[46], sizeof(pb) - 2 * 46);
|
||||
|
||||
Common::BitCastFromArray<u16>(pb_mem, pb);
|
||||
pb = std::bit_cast<AXPBWii>(pb_mem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ void AXWiiUCode::ReinjectUpdatesFields(AXPBWii& pb, u16* num_updates, u32 update
|
|||
pb_mem[44] = updates_addr >> 16;
|
||||
pb_mem[45] = updates_addr & 0xFFFF;
|
||||
|
||||
Common::BitCastFromArray<u16>(pb_mem, pb);
|
||||
pb = std::bit_cast<AXPBWii>(pb_mem);
|
||||
}
|
||||
|
||||
void AXWiiUCode::ProcessPBList(u32 pb_addr)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "Common/BitField.h"
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
@ -803,8 +804,13 @@ struct ZeldaAudioRenderer::VPB
|
|||
// can be used for future linear interpolation.
|
||||
s16 resample_buffer[4];
|
||||
|
||||
// TODO: document and implement.
|
||||
s16 prev_input_samples[0x18];
|
||||
s16 variable_fir_history[20];
|
||||
|
||||
// Biquad filter history.
|
||||
s16 biquad_xn1;
|
||||
s16 biquad_xn2;
|
||||
s16 biquad_yn1;
|
||||
s16 biquad_yn2;
|
||||
|
||||
// Values from the last decoded AFC block. The last two values are
|
||||
// especially important since AFC decoding - as a variant of ADPCM -
|
||||
|
@ -813,7 +819,12 @@ struct ZeldaAudioRenderer::VPB
|
|||
s16 afc_remaining_samples[0x10];
|
||||
s16* AFCYN2() { return &afc_remaining_samples[0xE]; }
|
||||
s16* AFCYN1() { return &afc_remaining_samples[0xF]; }
|
||||
u16 unk_68_80[0x80 - 0x68];
|
||||
|
||||
// Low-pass filter history.
|
||||
s16 low_pass_yn1;
|
||||
s16 low_pass_xn1;
|
||||
|
||||
u16 unk_6A_80[0x80 - 0x6A];
|
||||
|
||||
enum SamplesSourceType
|
||||
{
|
||||
|
@ -861,7 +872,11 @@ struct ZeldaAudioRenderer::VPB
|
|||
s16 loop_yn1;
|
||||
s16 loop_yn2;
|
||||
|
||||
u16 unk_84;
|
||||
union
|
||||
{
|
||||
BitField<0, 5, u16> variable_fir_filter_size;
|
||||
BitField<5, 1, u16> enable_biquad_filter;
|
||||
};
|
||||
|
||||
// If true, ramp down quickly to a volume of zero, and end the voice (by
|
||||
// setting VPB[1] done) when it reaches zero.
|
||||
|
@ -890,6 +905,20 @@ struct ZeldaAudioRenderer::VPB
|
|||
u16 base_address_l;
|
||||
DEFINE_32BIT_ACCESSOR(base_address, BaseAddress)
|
||||
|
||||
u16 unk_8E;
|
||||
u16 unk_8F;
|
||||
|
||||
u16 variable_fir_coeffs[20];
|
||||
|
||||
// Biquad filter coefficients.
|
||||
s16 biquad_bn1;
|
||||
s16 biquad_bn2;
|
||||
s16 biquad_an1;
|
||||
s16 biquad_an2;
|
||||
|
||||
// Low-pass filter coefficient.
|
||||
u16 low_pass_coeff;
|
||||
|
||||
u16 padding[0xC0];
|
||||
|
||||
// These next two functions are terrible hacks used in order to support two
|
||||
|
@ -1173,6 +1202,62 @@ ZeldaAudioRenderer::MixingBuffer* ZeldaAudioRenderer::BufferForID(u16 buffer_id)
|
|||
}
|
||||
}
|
||||
|
||||
void ZeldaAudioRenderer::ApplyLowPassFilter(MixingBuffer* buf, VPB* vpb)
|
||||
{
|
||||
s32 yn1 = vpb->reset_vpb ? 0 : vpb->low_pass_yn1;
|
||||
s32 xn1 = vpb->reset_vpb ? 0 : vpb->low_pass_xn1;
|
||||
|
||||
// 9.7 format I think.
|
||||
s32 coeff = vpb->low_pass_coeff;
|
||||
|
||||
for (int i = 0; i < 0x50; ++i)
|
||||
{
|
||||
s32 xn0 = (*buf)[i];
|
||||
s64 tmp = xn0 - xn1;
|
||||
tmp *= coeff;
|
||||
tmp >>= 7;
|
||||
tmp += yn1;
|
||||
s16 yn0 = std::clamp<s64>(tmp, -0x8000, 0x7FFF);
|
||||
(*buf)[i] = yn0;
|
||||
|
||||
yn1 = yn0;
|
||||
xn1 = xn0;
|
||||
}
|
||||
|
||||
vpb->low_pass_yn1 = yn1;
|
||||
vpb->low_pass_xn1 = xn1;
|
||||
}
|
||||
|
||||
void ZeldaAudioRenderer::ApplyBiquadFilter(MixingBuffer* buf, VPB* vpb)
|
||||
{
|
||||
s32 xn1 = vpb->biquad_xn1;
|
||||
s32 xn2 = vpb->biquad_xn2;
|
||||
s32 yn1 = vpb->biquad_yn1;
|
||||
s32 yn2 = vpb->biquad_yn2;
|
||||
|
||||
for (int i = 0; i < 0x50; ++i)
|
||||
{
|
||||
s32 xn0 = (*buf)[i];
|
||||
s64 tmp = 0;
|
||||
tmp += vpb->biquad_bn1 * xn1;
|
||||
tmp += vpb->biquad_bn2 * xn2;
|
||||
tmp += vpb->biquad_an1 * yn1;
|
||||
tmp += vpb->biquad_an2 * yn2;
|
||||
s16 yn0 = std::clamp<s64>(tmp >> 15, -0x8000, 0x7FFF);
|
||||
(*buf)[i] = yn0;
|
||||
|
||||
xn2 = xn1;
|
||||
xn1 = xn0;
|
||||
yn2 = yn1;
|
||||
yn1 = yn0;
|
||||
}
|
||||
|
||||
vpb->biquad_xn1 = xn1;
|
||||
vpb->biquad_xn2 = xn2;
|
||||
vpb->biquad_yn1 = yn1;
|
||||
vpb->biquad_yn2 = yn2;
|
||||
}
|
||||
|
||||
void ZeldaAudioRenderer::AddVoice(u16 voice_id)
|
||||
{
|
||||
VPB vpb;
|
||||
|
@ -1184,9 +1269,23 @@ void ZeldaAudioRenderer::AddVoice(u16 voice_id)
|
|||
MixingBuffer input_samples;
|
||||
LoadInputSamples(&input_samples, &vpb);
|
||||
|
||||
// TODO: In place effects.
|
||||
if (vpb.low_pass_coeff != 0)
|
||||
{
|
||||
ApplyLowPassFilter(&input_samples, &vpb);
|
||||
}
|
||||
|
||||
// TODO: IIR filter.
|
||||
#ifdef STRICT_ZELDA_HLE
|
||||
if (vpb.variable_fir_filter_size != 0)
|
||||
{
|
||||
ERROR_LOG_FMT(DSPHLE, "TODO: variable FIR filter of size {}", vpb.variable_fir_filter_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vpb.enable_biquad_filter && (vpb.biquad_an2 != 0 || vpb.biquad_an1 != 0 ||
|
||||
vpb.biquad_bn2 != 0 || vpb.biquad_bn1 != 0x7FFF))
|
||||
{
|
||||
ApplyBiquadFilter(&input_samples, &vpb);
|
||||
}
|
||||
|
||||
if (vpb.use_dolby_volume)
|
||||
{
|
||||
|
@ -1407,12 +1506,13 @@ void ZeldaAudioRenderer::LoadInputSamples(MixingBuffer* buffer, VPB* vpb)
|
|||
else
|
||||
shift = 2;
|
||||
u32 mask = (1 << shift) - 1;
|
||||
u32 ratio = vpb->resampling_ratio << (shift - 1);
|
||||
|
||||
u32 pos = vpb->current_pos_frac << shift;
|
||||
for (s16& sample : *buffer)
|
||||
{
|
||||
sample = ((pos >> 16) & mask) ? 0xC000 : 0x4000;
|
||||
pos += vpb->resampling_ratio;
|
||||
pos += ratio;
|
||||
}
|
||||
vpb->current_pos_frac = (pos >> shift) & 0xFFFF;
|
||||
break;
|
||||
|
|
|
@ -185,6 +185,9 @@ private:
|
|||
// behavior.
|
||||
void DownloadRawSamplesFromMRAM(s16* dst, VPB* vpb, u16 requested_samples_count);
|
||||
|
||||
void ApplyLowPassFilter(MixingBuffer* buf, VPB* vpb);
|
||||
void ApplyBiquadFilter(MixingBuffer* buf, VPB* vpb);
|
||||
|
||||
// Applies the reverb effect to Dolby mixed voices based on a set of
|
||||
// per-buffer parameters. Is called twice: once before frame rendering and
|
||||
// once after.
|
||||
|
|
|
@ -391,16 +391,14 @@ void DVDInterface::SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
|
|||
|
||||
if (auto_disc_change_paths)
|
||||
{
|
||||
ASSERT_MSG(DISCIO, (*auto_disc_change_paths).size() != 1,
|
||||
ASSERT_MSG(DISCIO, auto_disc_change_paths->size() != 1,
|
||||
"Cannot automatically change between one disc");
|
||||
|
||||
m_auto_disc_change_paths = *auto_disc_change_paths;
|
||||
m_auto_disc_change_index = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
AchievementManager::GetInstance().LoadGame("", disc.get());
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
// Assume that inserting a disc requires having an empty disc before
|
||||
if (had_disc != has_disc)
|
||||
|
|
|
@ -43,7 +43,7 @@ static bool IsSoundFile(const std::string& filename)
|
|||
".str", // Harry Potter & the Sorcerer's Stone
|
||||
};
|
||||
|
||||
return extensions.find(extension) != extensions.end();
|
||||
return extensions.contains(extension);
|
||||
}
|
||||
|
||||
FileLogger::FileLogger() = default;
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HW/EXI/BBA/TAP_Win32.h"
|
||||
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/EXI/EXI_Device.h"
|
||||
#include "Core/HW/EXI/EXI_DeviceEthernet.h"
|
||||
|
||||
namespace Win32TAPHelper
|
||||
{
|
||||
|
|
|
@ -42,7 +42,7 @@ distribution.
|
|||
namespace ExpansionInterface
|
||||
{
|
||||
enum class Slot : int;
|
||||
};
|
||||
}
|
||||
|
||||
using CardFlashId = std::array<u8, 12>;
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright 2022 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
@ -9,7 +11,6 @@
|
|||
#include "Common/BitUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/DrawsomeTablet.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Drums.h"
|
||||
|
|
|
@ -72,7 +72,7 @@ public:
|
|||
using TriggerRawValue = ControllerEmu::RawValue<TriggerType, TRIGGER_BITS>;
|
||||
|
||||
// 6-bit X and Y values (0-63)
|
||||
auto GetLeftStick() const { return LeftStickRawValue{StickType(lx, ly)}; };
|
||||
auto GetLeftStick() const { return LeftStickRawValue{StickType(lx, ly)}; }
|
||||
void SetLeftStick(const StickType& value)
|
||||
{
|
||||
lx = value.x;
|
||||
|
@ -82,7 +82,7 @@ public:
|
|||
auto GetRightStick() const
|
||||
{
|
||||
return RightStickRawValue{StickType(rx1 | rx2 << 1 | rx3 << 3, ry)};
|
||||
};
|
||||
}
|
||||
void SetRightStick(const StickType& value)
|
||||
{
|
||||
rx1 = value.x & 0b1;
|
||||
|
|
|
@ -30,7 +30,7 @@ struct MPI : mbedtls_mpi
|
|||
MPI() { mbedtls_mpi_init(this); }
|
||||
~MPI() { mbedtls_mpi_free(this); }
|
||||
|
||||
mbedtls_mpi* Data() { return this; };
|
||||
mbedtls_mpi* Data() { return this; }
|
||||
|
||||
template <std::size_t N>
|
||||
bool ReadBinary(const u8 (&in_data)[N])
|
||||
|
@ -719,7 +719,7 @@ void MotionPlus::ReversePassthroughModifications(PassthroughMode mode, u8* data)
|
|||
|
||||
// This is an overwritten unused button bit on the Classic Controller.
|
||||
// Note it's a significant bit on the DJ Hero Turntable. (passthrough not feasible)
|
||||
Common::SetBit<0>(data[4], 1);
|
||||
Common::SetBit<0>(data[4], true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1000,7 +1000,7 @@ bool IsBalanceBoardName(const std::string& name)
|
|||
bool IsNewWiimote(const std::string& identifier)
|
||||
{
|
||||
std::lock_guard lk(s_known_ids_mutex);
|
||||
return s_known_ids.count(identifier) == 0;
|
||||
return !s_known_ids.contains(identifier);
|
||||
}
|
||||
|
||||
void HandleWiimoteSourceChange(unsigned int index)
|
||||
|
|
|
@ -53,6 +53,7 @@ bool Host_UIBlocksControllerState();
|
|||
bool Host_RendererHasFocus();
|
||||
bool Host_RendererHasFullFocus();
|
||||
bool Host_RendererIsFullscreen();
|
||||
bool Host_TASInputHasFocus();
|
||||
|
||||
void Host_Message(HostMessageID id);
|
||||
void Host_PPCSymbolsChanged();
|
||||
|
|
|
@ -38,6 +38,9 @@ constexpr std::array<const char*, NUM_HOTKEYS> s_hotkey_labels{{
|
|||
_trans("Center Mouse"),
|
||||
_trans("Activate NetPlay Chat"),
|
||||
_trans("Control NetPlay Golf Mode"),
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
_trans("Open Achievements"),
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
_trans("Volume Down"),
|
||||
_trans("Volume Up"),
|
||||
|
@ -330,7 +333,11 @@ struct HotkeyGroupInfo
|
|||
};
|
||||
|
||||
constexpr std::array<HotkeyGroupInfo, NUM_HOTKEY_GROUPS> s_groups_info = {
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
{{_trans("General"), HK_OPEN, HK_OPEN_ACHIEVEMENTS},
|
||||
#else // USE_RETRO_ACHIEVEMENTS
|
||||
{{_trans("General"), HK_OPEN, HK_REQUEST_GOLF_CONTROL},
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
{_trans("Volume"), HK_VOLUME_DOWN, HK_VOLUME_TOGGLE_MUTE},
|
||||
{_trans("Emulation Speed"), HK_DECREASE_EMULATION_SPEED, HK_TOGGLE_THROTTLE},
|
||||
{_trans("Frame Advance"), HK_FRAME_ADVANCE, HK_FRAME_ADVANCE_RESET_SPEED},
|
||||
|
@ -448,6 +455,9 @@ void HotkeyManager::LoadDefaults(const ControllerInterface& ciface)
|
|||
set_key_expression(HK_STOP, "Escape");
|
||||
set_key_expression(HK_FULLSCREEN, hotkey_string({"Alt", "Return"}));
|
||||
#endif
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
set_key_expression(HK_OPEN_ACHIEVEMENTS, hotkey_string({"Alt", "A"}));
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
set_key_expression(HK_STEP, "F11");
|
||||
set_key_expression(HK_STEP_OVER, hotkey_string({"Shift", "F10"}));
|
||||
set_key_expression(HK_STEP_OUT, hotkey_string({"Shift", "F11"}));
|
||||
|
|
|
@ -32,6 +32,9 @@ enum Hotkey
|
|||
HK_CENTER_MOUSE,
|
||||
HK_ACTIVATE_CHAT,
|
||||
HK_REQUEST_GOLF_CONTROL,
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
HK_OPEN_ACHIEVEMENTS,
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
HK_VOLUME_DOWN,
|
||||
HK_VOLUME_UP,
|
||||
|
|
|
@ -29,6 +29,7 @@ enum ReturnCode : s32
|
|||
IPC_EMAX = -5, // Too many file descriptors open
|
||||
IPC_ENOENT = -6, // File not found
|
||||
IPC_EQUEUEFULL = -8, // Queue full
|
||||
IPC_UNKNOWN = -9, // Unknown
|
||||
IPC_EIO = -12, // ECC error
|
||||
IPC_ENOMEM = -22, // Alloc failed during request
|
||||
FS_EINVAL = -101, // Invalid path
|
||||
|
|
|
@ -112,9 +112,9 @@ ESCore::~ESCore() = default;
|
|||
ESDevice::ESDevice(EmulationKernel& ios, ESCore& core, const std::string& device_name)
|
||||
: EmulationDevice(ios, device_name), m_core(core)
|
||||
{
|
||||
if (Core::IsRunningAndStarted())
|
||||
auto& system = ios.GetSystem();
|
||||
if (Core::IsRunning(system))
|
||||
{
|
||||
auto& system = ios.GetSystem();
|
||||
auto& core_timing = system.GetCoreTiming();
|
||||
core_timing.RemoveEvent(s_finish_init_event);
|
||||
core_timing.ScheduleEvent(GetESBootTicks(ios.GetVersion()), s_finish_init_event);
|
||||
|
@ -446,7 +446,7 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
|
|||
}
|
||||
|
||||
const u64 required_ios = tmd.GetIOSId();
|
||||
if (!Core::IsRunningAndStarted())
|
||||
if (!Core::IsRunning(system))
|
||||
return LaunchTitle(required_ios, HangPPC::Yes);
|
||||
core_timing.RemoveEvent(s_reload_ios_for_ppc_launch_event);
|
||||
core_timing.ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios);
|
||||
|
@ -475,14 +475,12 @@ bool ESDevice::LaunchPPCTitle(u64 title_id)
|
|||
return false;
|
||||
|
||||
m_pending_ppc_boot_content_path = m_core.GetContentPath(tmd.GetTitleId(), content);
|
||||
if (!Core::IsRunningAndStarted())
|
||||
if (!Core::IsRunning(system))
|
||||
return BootstrapPPC();
|
||||
|
||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||
INFO_LOG_FMT(ACHIEVEMENTS,
|
||||
"WAD and NAND formats not currently supported by Achievement Manager.");
|
||||
AchievementManager::GetInstance().CloseGame();
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
||||
core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event);
|
||||
core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event);
|
||||
|
@ -1051,7 +1049,7 @@ ReturnCode ESCore::WriteNewCertToStore(const ES::CertReader& cert)
|
|||
{
|
||||
const std::map<std::string, ES::CertReader> certs = ES::ParseCertChain(current_store);
|
||||
// The cert is already present in the store. Nothing to do.
|
||||
if (certs.find(cert.GetName()) != certs.end())
|
||||
if (certs.contains(cert.GetName()))
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -340,7 +340,7 @@ bool ESCore::FinishImport(const ES::TMDReader& tmd)
|
|||
// There should not be any directory in there. Remove it.
|
||||
if (fs->ReadDirectory(PID_KERNEL, PID_KERNEL, absolute_path))
|
||||
fs->Delete(PID_KERNEL, PID_KERNEL, absolute_path);
|
||||
else if (expected_entries.find(name) == expected_entries.end())
|
||||
else if (!expected_entries.contains(name))
|
||||
fs->Delete(PID_KERNEL, PID_KERNEL, absolute_path);
|
||||
}
|
||||
|
||||
|
|
|
@ -290,7 +290,7 @@ void HostFileSystem::DoStateRead(PointerWrap& p, std::string start_directory_pat
|
|||
File::CreateDir(path);
|
||||
|
||||
// now restore from the stream
|
||||
while (1)
|
||||
while (true)
|
||||
{
|
||||
char type = 0;
|
||||
p.Do(type);
|
||||
|
|
|
@ -81,6 +81,12 @@ Result<FileHandle> HostFileSystem::OpenFile(Uid, Gid, const std::string& path, M
|
|||
return ResultCode::NoFreeHandle;
|
||||
|
||||
const std::string host_path = BuildFilename(path).host_path;
|
||||
if (File::IsDirectory(host_path))
|
||||
{
|
||||
*handle = Handle{};
|
||||
return ResultCode::Invalid;
|
||||
}
|
||||
|
||||
if (!File::IsFile(host_path))
|
||||
{
|
||||
*handle = Handle{};
|
||||
|
|
|
@ -518,7 +518,7 @@ bool EmulationKernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc,
|
|||
if (hang_ppc == HangPPC::Yes)
|
||||
ResetAndPausePPC(m_system);
|
||||
|
||||
if (Core::IsRunningAndStarted())
|
||||
if (Core::IsRunning(m_system))
|
||||
{
|
||||
m_system.GetCoreTiming().ScheduleEvent(GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot,
|
||||
ios_title_id);
|
||||
|
@ -533,7 +533,7 @@ bool EmulationKernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc,
|
|||
|
||||
void EmulationKernel::InitIPC()
|
||||
{
|
||||
if (!Core::IsRunning(m_system))
|
||||
if (Core::GetState(m_system) == Core::State::Uninitialized)
|
||||
return;
|
||||
|
||||
INFO_LOG_FMT(IOS, "IPC initialised.");
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue