diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 68e033b129..0b82d3e727 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -349,8 +349,35 @@ struct Impl { // Well, I mean it's the default constructor! explicit Impl() noexcept : filter(Level::Trace) {} - template - void ForEachBackend(F&& lambda) noexcept { + void StartBackendThread() noexcept { + backend_thread = std::jthread([this](std::stop_token stop_token) { + Common::SetCurrentThreadName("Logger"); + Entry entry; + const auto write_logs = [this, &entry]() { + ForEachBackend([&entry](Backend& backend) { + backend.Write(entry); + }); + }; + do { + message_queue.PopWait(entry, stop_token); + write_logs(); + } while (!stop_token.stop_requested()); + // Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a + // case where a system is repeatedly spamming logs even on close. + int max_logs_to_write = filter.IsDebug() ? INT_MAX : 100; + while (max_logs_to_write-- && message_queue.TryPop(entry)) + write_logs(); + }); + } + + void StopBackendThread() noexcept { + backend_thread.request_stop(); + if (backend_thread.joinable()) + backend_thread.join(); + ForEachBackend([](Backend& backend) { backend.Flush(); }); + } + + void ForEachBackend(auto lambda) noexcept { lambda(static_cast(color_console_backend)); #ifndef __OPENORBIS__ if (file_backend) @@ -375,7 +402,9 @@ struct Impl { #ifdef ANDROID LogcatBackend lc_backend{}; #endif + MPSCQueue message_queue{}; std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; + std::jthread backend_thread; }; } // namespace @@ -399,11 +428,13 @@ void Initialize() { } void Start() { + if (logging_instance) + logging_instance->StartBackendThread(); } void Stop() { if (logging_instance) - logging_instance->ForEachBackend([](Backend& backend) { backend.Flush(); }); + logging_instance->StopBackendThread(); } void SetGlobalFilter(const Filter& filter) { @@ -418,19 +449,14 @@ void SetColorConsoleBackendEnabled(bool enabled) { void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, unsigned int line_num, const char* function, fmt::string_view format, const fmt::format_args& args) { if (logging_instance && logging_instance->filter.CheckMessage(log_class, log_level)) { - auto const flush = ::Settings::values.log_flush_line.GetValue(); - logging_instance->ForEachBackend([=](Backend& backend) { - backend.Write(Entry{ - .message = fmt::vformat(format, args), - .timestamp = std::chrono::duration_cast(std::chrono::steady_clock::now() - logging_instance->time_origin), - .log_class = log_class, - .log_level = log_level, - .filename = TrimSourcePath(filename), - .function = function, - .line_num = line_num, - }); - if (flush) - backend.Flush(); + logging_instance->message_queue.EmplaceWait(Entry{ + .message = fmt::vformat(format, args), + .timestamp = std::chrono::duration_cast(std::chrono::steady_clock::now() - logging_instance->time_origin), + .log_class = log_class, + .log_level = log_level, + .filename = TrimSourcePath(filename), + .function = function, + .line_num = line_num, }); } } diff --git a/src/core/arm/nce/interpreter_visitor.cpp b/src/core/arm/nce/interpreter_visitor.cpp index ec2b155fe4..077a696cc8 100644 --- a/src/core/arm/nce/interpreter_visitor.cpp +++ b/src/core/arm/nce/interpreter_visitor.cpp @@ -761,7 +761,8 @@ bool InterpreterVisitor::LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3 return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt); } -std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, fpsimd_context* fpsimd_context) { +std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, + fpsimd_context* fpsimd_context) { std::span regs(reinterpret_cast(context->regs), 31); std::span vregs(reinterpret_cast(fpsimd_context->vregs), 32); u64& sp = *reinterpret_cast(&context->sp); @@ -771,9 +772,9 @@ std::optional MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m u32 instruction = memory.Read32(pc); bool was_executed = false; - auto decoder = Dynarmic::A64::Decode(visitor, instruction); + auto decoder = Dynarmic::A64::Decode(instruction); if (decoder) { - was_executed = *decoder; + was_executed = decoder->get().call(visitor, instruction); } else { was_executed = false; } diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index a2903dbacf..f3e2e21f4c 100644 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp @@ -1,12 +1,7 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include -#include "common/alignment.h" -#include "common/literals.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/sdmc_factory.h" #include "core/file_sys/vfs/vfs.h" @@ -14,6 +9,8 @@ namespace FileSys { +constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB + SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_) : sd_dir(std::move(sd_dir_)), sd_mod_dir(std::move(sd_mod_dir_)), contents(std::make_unique( @@ -59,11 +56,7 @@ u64 SDMCFactory::GetSDMCFreeSpace() const { } u64 SDMCFactory::GetSDMCTotalSpace() const { - // Resize the SD space automatically, always leaving around 4GiB last from next chunk block - using namespace Common::Literals; - auto const bytes_per_sector = 512; - auto const size_block = (sd_dir->GetSize() + 4_GiB) / 4_GiB; - return Common::AlignUp(size_block * 4_GiB, bytes_per_sector); + return SDMC_TOTAL_SIZE; } } // namespace FileSys diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp index bbdf27039b..cb68d5b55e 100644 --- a/src/core/file_sys/system_archive/system_archive.cpp +++ b/src/core/file_sys/system_archive/system_archive.cpp @@ -15,76 +15,86 @@ namespace FileSys::SystemArchive { +constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800; +constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28; + +using SystemArchiveSupplier = VirtualDir (*)(); + struct SystemArchiveDescriptor { + u64 title_id; const char* name; - VirtualDir (*supplier)(); + SystemArchiveSupplier supplier; }; -constexpr inline SystemArchiveDescriptor GetSystemArchive(u64 title_id) { - switch (title_id) { - case 0x0100000000000800: return {"CertStore", nullptr}; - case 0x0100000000000801: return {"ErrorMessage", nullptr}; - case 0x0100000000000802: return {"MiiModel", &MiiModel}; - case 0x0100000000000803: return {"BrowserDll", nullptr}; - case 0x0100000000000804: return {"Help", nullptr}; - case 0x0100000000000805: return {"SharedFont", nullptr}; - case 0x0100000000000806: return {"NgWord", &NgWord1}; - case 0x0100000000000807: return {"SsidList", nullptr}; - case 0x0100000000000808: return {"Dictionary", nullptr}; - case 0x0100000000000809: return {"SystemVersion", &SystemVersion}; - case 0x010000000000080A: return {"AvatarImage", nullptr}; - case 0x010000000000080B: return {"LocalNews", nullptr}; - case 0x010000000000080C: return {"Eula", nullptr}; - case 0x010000000000080D: return {"UrlBlackList", nullptr}; - case 0x010000000000080E: return {"TimeZoneBinary", &TimeZoneBinary}; - case 0x010000000000080F: return {"CertStoreCruiser", nullptr}; - case 0x0100000000000810: return {"FontNintendoExtension", &FontNintendoExtension}; - case 0x0100000000000811: return {"FontStandard", &FontStandard}; - case 0x0100000000000812: return {"FontKorean", &FontKorean}; - case 0x0100000000000813: return {"FontChineseTraditional", &FontChineseTraditional}; - case 0x0100000000000814: return {"FontChineseSimple", &FontChineseSimple}; - case 0x0100000000000815: return {"FontBfcpx", nullptr}; - case 0x0100000000000816: return {"SystemUpdate", nullptr}; - case 0x0100000000000817: return {"0100000000000817", nullptr}; - case 0x0100000000000818: return {"FirmwareDebugSettings", nullptr}; - case 0x0100000000000819: return {"BootImagePackage", nullptr}; - case 0x010000000000081A: return {"BootImagePackageSafe", nullptr}; - case 0x010000000000081B: return {"BootImagePackageExFat", nullptr}; - case 0x010000000000081C: return {"BootImagePackageExFatSafe", nullptr}; - case 0x010000000000081D: return {"FatalMessage", nullptr}; - case 0x010000000000081E: return {"ControllerIcon", nullptr}; - case 0x010000000000081F: return {"PlatformConfigIcosa", nullptr}; - case 0x0100000000000820: return {"PlatformConfigCopper", nullptr}; - case 0x0100000000000821: return {"PlatformConfigHoag", nullptr}; - case 0x0100000000000822: return {"ControllerFirmware", nullptr}; - case 0x0100000000000823: return {"NgWord2", &NgWord2}; - case 0x0100000000000824: return {"PlatformConfigIcosaMariko", nullptr}; - case 0x0100000000000825: return {"ApplicationBlackList", nullptr}; - case 0x0100000000000826: return {"RebootlessSystemUpdateVersion", nullptr}; - case 0x0100000000000827: return {"ContentActionTable", nullptr}; - case 0x0100000000000828: return {"FunctionBlackList", nullptr}; - case 0x0100000000000829: return {"PlatformConfigCalcio", nullptr}; - case 0x0100000000000830: return {"NgWordT", nullptr}; - case 0x0100000000000831: return {"PlatformConfigAula", nullptr}; - case 0x0100000000000832: return {"CradleFirmware", nullptr}; - case 0x0100000000000835: return {"ErrorMessageUtf8", nullptr}; - case 0x0100000000000859: return {"ClientCertData", nullptr}; - case 0x010000000000085C: return {"GameCardConfigurationData", nullptr}; - default: return {nullptr, nullptr}; - } -} +constexpr std::array SYSTEM_ARCHIVES{{ + {0x0100000000000800, "CertStore", nullptr}, + {0x0100000000000801, "ErrorMessage", nullptr}, + {0x0100000000000802, "MiiModel", &MiiModel}, + {0x0100000000000803, "BrowserDll", nullptr}, + {0x0100000000000804, "Help", nullptr}, + {0x0100000000000805, "SharedFont", nullptr}, + {0x0100000000000806, "NgWord", &NgWord1}, + {0x0100000000000807, "SsidList", nullptr}, + {0x0100000000000808, "Dictionary", nullptr}, + {0x0100000000000809, "SystemVersion", &SystemVersion}, + {0x010000000000080A, "AvatarImage", nullptr}, + {0x010000000000080B, "LocalNews", nullptr}, + {0x010000000000080C, "Eula", nullptr}, + {0x010000000000080D, "UrlBlackList", nullptr}, + {0x010000000000080E, "TimeZoneBinary", &TimeZoneBinary}, + {0x010000000000080F, "CertStoreCruiser", nullptr}, + {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension}, + {0x0100000000000811, "FontStandard", &FontStandard}, + {0x0100000000000812, "FontKorean", &FontKorean}, + {0x0100000000000813, "FontChineseTraditional", &FontChineseTraditional}, + {0x0100000000000814, "FontChineseSimple", &FontChineseSimple}, + {0x0100000000000815, "FontBfcpx", nullptr}, + {0x0100000000000816, "SystemUpdate", nullptr}, + {0x0100000000000817, "0100000000000817", nullptr}, + {0x0100000000000818, "FirmwareDebugSettings", nullptr}, + {0x0100000000000819, "BootImagePackage", nullptr}, + {0x010000000000081A, "BootImagePackageSafe", nullptr}, + {0x010000000000081B, "BootImagePackageExFat", nullptr}, + {0x010000000000081C, "BootImagePackageExFatSafe", nullptr}, + {0x010000000000081D, "FatalMessage", nullptr}, + {0x010000000000081E, "ControllerIcon", nullptr}, + {0x010000000000081F, "PlatformConfigIcosa", nullptr}, + {0x0100000000000820, "PlatformConfigCopper", nullptr}, + {0x0100000000000821, "PlatformConfigHoag", nullptr}, + {0x0100000000000822, "ControllerFirmware", nullptr}, + {0x0100000000000823, "NgWord2", &NgWord2}, + {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr}, + {0x0100000000000825, "ApplicationBlackList", nullptr}, + {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr}, + {0x0100000000000827, "ContentActionTable", nullptr}, +}}; VirtualFile SynthesizeSystemArchive(const u64 title_id) { - auto const desc = GetSystemArchive(title_id); - LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, title_id); - if (desc.supplier != nullptr) { - if (auto const dir = desc.supplier(); dir != nullptr) { - if (auto const romfs = CreateRomFS(dir); romfs != nullptr) { - LOG_INFO(Service_FS, " - System archive generation successful!"); - return romfs; - } - } + if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) { + return nullptr; } - return nullptr; + + const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID]; + + LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id); + + if (desc.supplier == nullptr) { + return nullptr; + } + + const auto dir = desc.supplier(); + + if (dir == nullptr) { + return nullptr; + } + + const auto romfs = CreateRomFS(dir); + + if (romfs == nullptr) { + return nullptr; + } + + LOG_INFO(Service_FS, " - System archive generation successful!"); + return romfs; } } // namespace FileSys::SystemArchive diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5f88fa498f..129bda194a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -372,17 +372,17 @@ struct KernelCore::Impl { } // Gets the dummy KThread for the caller, allocating a new one if this is the first time - KThread* GetHostDummyThread(ThreadLocalData& t, KThread* existing_thread) { - if (t.thread == nullptr) { + KThread* GetHostDummyThread(KThread* existing_thread) { + if (tls_data.thread == nullptr) { auto const initialize{[](KThread* thread) { ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess()); return thread; }}; - t.raw_thread.emplace(system.Kernel()); - t.thread = existing_thread ? existing_thread : initialize(&*t.raw_thread); - ASSERT(t.thread != nullptr); + tls_data.raw_thread.emplace(system.Kernel()); + tls_data.thread = existing_thread ? existing_thread : initialize(&*tls_data.raw_thread); + ASSERT(tls_data.thread != nullptr); } - return t.thread; + return tls_data.thread; } /// Registers a CPU core thread by allocating a host thread ID for it @@ -395,7 +395,7 @@ struct KernelCore::Impl { /// Registers a new host thread by allocating a host thread ID for it void RegisterHostThread(KThread* existing_thread) { - (void)GetHostDummyThread(tls_data, existing_thread); + (void)GetHostDummyThread(existing_thread); } [[nodiscard]] u32 GetCurrentHostThreadID() { @@ -419,8 +419,9 @@ struct KernelCore::Impl { } KThread* GetCurrentEmuThread() { - auto& t = tls_data; - return t.current_thread ? t.current_thread : (t.current_thread = GetHostDummyThread(t, nullptr)); + if (!tls_data.current_thread) + tls_data.current_thread = GetHostDummyThread(nullptr); + return tls_data.current_thread; } void SetCurrentEmuThread(KThread* thread) { diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h index a9309ef5a8..d1cd9a923d 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h @@ -26,41 +26,48 @@ namespace Dynarmic::A32 { template using ArmMatcher = Decoder::Matcher; -template -static std::optional DecodeArm(V& visitor, u32 instruction) noexcept { - auto const make_fast_index = [](u32 a) { - return ((a >> 4) & 0x00F) | ((a >> 16) & 0xFF0); - }; - struct Handler { - bool (*fn)(V&, u32); - u32 mask; - u32 expect; - }; - alignas(64) static const std::array, 0x1000> table = [&] { - std::array, 0x1000> t{}; - for (size_t i = 0; i < t.size(); ++i) { -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - if ((i & make_fast_index(mask)) == make_fast_index(expect)) { \ - t[i].emplace_back([](V& visitor, u32 instruction) -> bool { \ - return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - }, mask, expect); \ - } \ - } while (0); +template +using ArmDecodeTable = std::array>, 0x1000>; + +namespace detail { +inline size_t ToFastLookupIndexArm(u32 instruction) noexcept { + return ((instruction >> 4) & 0x00F) | ((instruction >> 16) & 0xFF0); +} +} // namespace detail + +template +static ArmDecodeTable GetArmDecodeTable() noexcept { + ArmDecodeTable table{}; + for (size_t i = 0; i < table.size(); ++i) { + // PLEASE HEAP ELLIDE + for (auto const& e : std::vector>{ +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./arm.inc" #undef INST + }) { + auto const expect = detail::ToFastLookupIndexArm(e.GetExpected()); + auto const mask = detail::ToFastLookupIndexArm(e.GetMask()); + if ((i & mask) == expect) { + table[i].push_back(e); + } } - return t; - }(); - for (auto const& e : table[make_fast_index(instruction)]) - if ((instruction & e.mask) == e.expect) - return e.fn(visitor, instruction); - return std::nullopt; + } + return table; } template -static std::optional GetNameArm(u32 inst) noexcept { +static std::optional>> DecodeArm(u32 instruction) noexcept { + alignas(64) static const auto table = GetArmDecodeTable(); + const auto matches_instruction = [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }; + const auto& subtable = table[detail::ToFastLookupIndexArm(instruction)]; + auto iter = std::find_if(subtable.begin(), subtable.end(), matches_instruction); + return iter != subtable.end() ? std::optional>>(*iter) : std::nullopt; +} + +template +static std::optional GetNameARM(u32 inst) noexcept { std::vector>> list = { #define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) }, #include "./arm.inc" diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h index 4feae6f478..5b0336e59f 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/asimd.h @@ -26,16 +26,17 @@ namespace Dynarmic::A32 { template using ASIMDMatcher = Decoder::Matcher; -template -static std::optional DecodeASIMD(V& visitor, u32 instruction) noexcept { -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - if ((instruction & mask) == expect) return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - } while (0); +template +static std::optional>> DecodeASIMD(u32 instruction) noexcept { + alignas(64) static const auto table = std::array{ +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./asimd.inc" #undef INST - return std::nullopt; + }; + auto iter = std::find_if(table.begin(), table.end(), [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }); + return iter != table.end() ? std::optional>>(*iter) : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb16.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb16.h index 465159a00d..590878a6de 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb16.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb16.h @@ -23,16 +23,17 @@ namespace Dynarmic::A32 { template using Thumb16Matcher = Decoder::Matcher; -template -static std::optional DecodeThumb16(V& visitor, u16 instruction) { -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)); \ - if ((instruction & mask) == expect) return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)); \ - } while (0); +template +static std::optional>> DecodeThumb16(u16 instruction) { + alignas(64) static const auto table = std::array{ +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(bitstring)), #include "./thumb16.inc" #undef INST - return std::nullopt; + }; + auto iter = std::find_if(table.begin(), table.end(), [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }); + return iter != table.end() ? std::optional>>(*iter) : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb32.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb32.h index b3588c7a1d..6a09c66afb 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb32.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/thumb32.h @@ -22,16 +22,17 @@ namespace Dynarmic::A32 { template using Thumb32Matcher = Decoder::Matcher; -template -static std::optional DecodeThumb32(V& visitor, u32 instruction) { -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - if ((instruction & mask) == expect) return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - } while (0); +template +static std::optional>> DecodeThumb32(u32 instruction) { + alignas(64) static const auto table = std::array{ +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./thumb32.inc" #undef INST - return std::nullopt; + }; + auto iter = std::find_if(table.begin(), table.end(), [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }); + return iter != table.end() ? std::optional>>(*iter) : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A32/decoder/vfp.h b/src/dynarmic/src/dynarmic/frontend/A32/decoder/vfp.h index 8703aa24b4..e02cc03a6b 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/decoder/vfp.h +++ b/src/dynarmic/src/dynarmic/frontend/A32/decoder/vfp.h @@ -23,18 +23,32 @@ namespace Dynarmic::A32 { template using VFPMatcher = Decoder::Matcher; -template -static std::optional DecodeVFP(V& visitor, u32 instruction) { - bool const i_uncond = (instruction & 0xF0000000) == 0xF0000000; -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - bool const m_uncond = (mask & 0xF0000000) == 0xF0000000; \ - if ((instruction & mask) == expect && m_uncond == i_uncond) return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - } while (0); +template +static std::optional>> DecodeVFP(u32 instruction) { + using Table = std::vector>; + alignas(64) static const struct Tables { + Table unconditional; + Table conditional; + } tables = []() { + Table list = { +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./vfp.inc" #undef INST - return std::nullopt; + }; + auto const it = std::stable_partition(list.begin(), list.end(), [&](const auto& matcher) { + return (matcher.GetMask() & 0xF0000000) == 0xF0000000; + }); + return Tables{ + Table{list.begin(), it}, + Table{it, list.end()}, + }; + }(); + const bool is_unconditional = (instruction & 0xF0000000) == 0xF0000000; + const Table& table = is_unconditional ? tables.unconditional : tables.conditional; + auto iter = std::find_if(table.begin(), table.end(), [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }); + return iter != table.end() ? std::optional>>(*iter) : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp index 6c89a4af36..3fd475d074 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_arm.cpp @@ -41,12 +41,12 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir); ticks_for_instruction = tcb->GetTicksForCode(false, arm_pc, *arm_instruction); - if (const auto vfp_decoder = DecodeVFP(visitor, *arm_instruction)) { - should_continue = *vfp_decoder; - } else if (const auto asimd_decoder = DecodeASIMD(visitor, *arm_instruction)) { - should_continue = *asimd_decoder; - } else if (const auto decoder = DecodeArm(visitor, *arm_instruction)) { - should_continue = *decoder; + if (const auto vfp_decoder = DecodeVFP(*arm_instruction)) { + should_continue = vfp_decoder->get().call(visitor, *arm_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(*arm_instruction)) { + should_continue = asimd_decoder->get().call(visitor, *arm_instruction); + } else if (const auto decoder = DecodeArm(*arm_instruction)) { + should_continue = decoder->get().call(visitor, *arm_instruction); } else { should_continue = visitor.arm_UDF(); } @@ -88,12 +88,12 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript const u64 ticks_for_instruction = 1; - if (const auto vfp_decoder = DecodeVFP(visitor, arm_instruction)) { - should_continue = *vfp_decoder; - } else if (const auto asimd_decoder = DecodeASIMD(visitor, arm_instruction)) { - should_continue = *asimd_decoder; - } else if (const auto decoder = DecodeArm(visitor, arm_instruction)) { - should_continue = *decoder; + if (const auto vfp_decoder = DecodeVFP(arm_instruction)) { + should_continue = vfp_decoder->get().call(visitor, arm_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(arm_instruction)) { + should_continue = asimd_decoder->get().call(visitor, arm_instruction); + } else if (const auto decoder = DecodeArm(arm_instruction)) { + should_continue = decoder->get().call(visitor, arm_instruction); } else { should_continue = visitor.arm_UDF(); } diff --git a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp index 2a2fbea63f..332860a95c 100644 --- a/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A32/translate/translate_thumb.cpp @@ -126,24 +126,24 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) { if (is_thumb_16) { - if (const auto decoder = DecodeThumb16(visitor, u16(thumb_instruction))) { - should_continue = *decoder; + if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { + should_continue = decoder->get().call(visitor, static_cast(thumb_instruction)); } else { should_continue = visitor.thumb16_UDF(); } } else { if (MaybeVFPOrASIMDInstruction(thumb_instruction)) { - if (const auto vfp_decoder = DecodeVFP(visitor, thumb_instruction)) { - should_continue = *vfp_decoder; - } else if (const auto asimd_decoder = DecodeASIMD(visitor, ConvertASIMDInstruction(thumb_instruction))) { - should_continue = *asimd_decoder; - } else if (const auto decoder = DecodeThumb32(visitor, thumb_instruction)) { - should_continue = *decoder; + if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { + should_continue = vfp_decoder->get().call(visitor, thumb_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { + should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); + } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->get().call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } - } else if (const auto decoder = DecodeThumb32(visitor, thumb_instruction)) { - should_continue = *decoder; + } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->get().call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } @@ -187,25 +187,25 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri const u64 ticks_for_instruction = 1; if (is_thumb_16) { - if (const auto decoder = DecodeThumb16(visitor, u16(thumb_instruction))) { - should_continue = *decoder; + if (const auto decoder = DecodeThumb16(static_cast(thumb_instruction))) { + should_continue = decoder->get().call(visitor, static_cast(thumb_instruction)); } else { should_continue = visitor.thumb16_UDF(); } } else { thumb_instruction = mcl::bit::swap_halves_32(thumb_instruction); if (MaybeVFPOrASIMDInstruction(thumb_instruction)) { - if (const auto vfp_decoder = DecodeVFP(visitor, thumb_instruction)) { - should_continue = *vfp_decoder; - } else if (const auto asimd_decoder = DecodeASIMD(visitor, ConvertASIMDInstruction(thumb_instruction))) { - should_continue = *asimd_decoder; - } else if (const auto decoder = DecodeThumb32(visitor, thumb_instruction)) { - should_continue = *decoder; + if (const auto vfp_decoder = DecodeVFP(thumb_instruction)) { + should_continue = vfp_decoder->get().call(visitor, thumb_instruction); + } else if (const auto asimd_decoder = DecodeASIMD(ConvertASIMDInstruction(thumb_instruction))) { + should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction)); + } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->get().call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } - } else if (const auto decoder = DecodeThumb32(visitor, thumb_instruction)) { - should_continue = *decoder; + } else if (const auto decoder = DecodeThumb32(thumb_instruction)) { + should_continue = decoder->get().call(visitor, thumb_instruction); } else { should_continue = visitor.thumb32_UDF(); } diff --git a/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h b/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h index f0b7baba7b..ccf890cbcd 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h +++ b/src/dynarmic/src/dynarmic/frontend/A64/decoder/a64.h @@ -26,37 +26,45 @@ namespace Dynarmic::A64 { template using Matcher = Decoder::Matcher; -template -static std::optional Decode(V& visitor, u32 instruction) noexcept { - auto const make_fast_index = [](u32 a) { - return ((a >> 10) & 0x00F) | ((a >> 18) & 0xFF0); - }; - struct Handler { - bool (*fn)(V&, u32); - u32 mask; - u32 expect; - }; - alignas(64) static const std::array, 0x1000> table = [&] { - std::array, 0x1000> t{}; - for (size_t i = 0; i < t.size(); ++i) { -#define INST(fn, name, bitstring) \ - do { \ - auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - if ((i & make_fast_index(mask)) == make_fast_index(expect)) { \ - t[i].emplace_back([](V& visitor, u32 instruction) -> bool { \ - return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \ - }, mask, expect); \ - } \ - } while (0); +template +using DecodeTable = std::array>, 0x1000>; + +namespace detail { +inline size_t ToFastLookupIndex(u32 instruction) { + return ((instruction >> 10) & 0x00F) | ((instruction >> 18) & 0xFF0); +} +} // namespace detail + +template +inline DecodeTable GetDecodeTable() { + DecodeTable table{}; + for (size_t i = 0; i < table.size(); ++i) { + // PLEASE HEAP ELLIDE + for (auto const& e : std::vector>{ +#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)), #include "./a64.inc" #undef INST + }) { + const auto expect = detail::ToFastLookupIndex(e.GetExpected()); + const auto mask = detail::ToFastLookupIndex(e.GetMask()); + if ((i & mask) == expect) + table[i].push_back(e); } - return t; - }(); - for (auto const& e : table[make_fast_index(instruction)]) - if ((instruction & e.mask) == e.expect) - return e.fn(visitor, instruction); - return std::nullopt; + } + return table; +} + +/// In practice it must always suceed, otherwise something else unrelated would have gone awry +template +inline std::optional>> Decode(u32 instruction) { + alignas(64) static const auto table = GetDecodeTable(); + const auto& subtable = table[detail::ToFastLookupIndex(instruction)]; + auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) { + return matcher.Matches(instruction); + }); + return iter != subtable.end() + ? std::optional{ std::reference_wrapper>(*iter) } + : std::nullopt; } template diff --git a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp index 7840c63d79..4afce6bd29 100644 --- a/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp +++ b/src/dynarmic/src/dynarmic/frontend/A64/translate/a64_translate.cpp @@ -24,8 +24,9 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu do { const u64 pc = visitor.ir.current_location->PC(); if (const auto instruction = memory_read_code(pc)) { - if (auto decoder = Decode(visitor, *instruction)) { - should_continue = *decoder; + auto decoder = Decode(*instruction); + if (decoder) { + should_continue = decoder->get().call(visitor, *instruction); } else { should_continue = visitor.RaiseException(Exception::UnallocatedEncoding); } @@ -46,9 +47,13 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) { TranslatorVisitor visitor{block, descriptor, {}}; - bool should_continue = false; - if (auto const decoder = Decode(visitor, instruction)) - should_continue = *decoder; + bool should_continue = true; + auto const decoder = Decode(instruction); + if (decoder) { + should_continue = decoder->get().call(visitor, instruction); + } else { + should_continue = false; + } visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4); block.CycleCount()++; diff --git a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h index e383fb0262..c22e585c26 100644 --- a/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h +++ b/src/dynarmic/src/dynarmic/frontend/decoder/decoder_detail.h @@ -8,25 +8,31 @@ #pragma once +#include #include #include -#include + #include "common/assert.h" #include "dynarmic/mcl/bit.hpp" +#include "dynarmic/mcl/function_info.hpp" namespace Dynarmic::Decoder { namespace detail { template -inline consteval std::array StringToArray(const char (&s)[N + 1]) { - std::array r{}; - for (size_t i = 0; i < N; i++) - r[i] = s[i]; - return r; +inline consteval std::array StringToArray(const char (&str)[N + 1]) { + std::array result{}; + for (size_t i = 0; i < N; i++) { + result[i] = str[i]; + } + return result; } -/// @brief Helper functions for the decoders. -/// @tparam MatcherT The type of the Matcher to use. +/** + * Helper functions for the decoders. + * + * @tparam MatcherT The type of the Matcher to use. + */ template struct detail { using opcode_type = typename MatcherT::opcode_type; @@ -34,15 +40,17 @@ struct detail { static constexpr size_t opcode_bitsize = mcl::bitsizeof; - /// @brief Generates the mask and the expected value after masking from a given bitstring. - /// A '0' in a bitstring indicates that a zero must be present at that bit position. - /// A '1' in a bitstring indicates that a one must be present at that bit position. + /** + * Generates the mask and the expected value after masking from a given bitstring. + * A '0' in a bitstring indicates that a zero must be present at that bit position. + * A '1' in a bitstring indicates that a one must be present at that bit position. + */ #ifdef __clang__ static constexpr auto GetMaskAndExpect(std::array bitstring) { #else static consteval auto GetMaskAndExpect(std::array bitstring) { #endif - const auto one = opcode_type(1); + const auto one = static_cast(1); opcode_type mask = 0, expect = 0; for (size_t i = 0; i < opcode_bitsize; i++) { const size_t bit_position = opcode_bitsize - i - 1; @@ -93,7 +101,7 @@ struct detail { } #if !defined(DYNARMIC_IGNORE_ASSERTS) && !defined(__ANDROID__) // Avoids a MSVC ICE, and avoids Android NDK issue. - DEBUG_ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m) { return m != 0; })); + ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m) { return m != 0; })); #endif return std::make_tuple(masks, shifts); } @@ -101,32 +109,65 @@ struct detail { /// @brief This struct's Make member function generates a lambda which decodes an instruction /// based on the provided arg_masks and arg_shifts. The Visitor member function to call is /// provided as a template argument. + template + struct VisitorCaller; + #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning) #endif - template - struct VisitorCaller { - template - static inline constexpr auto Invoke(std::index_sequence, V& visitor, [[maybe_unused]] opcode_type instruction, ReturnType (V::*const fn)(Args...), [[maybe_unused]] const std::array arg_masks, [[maybe_unused]] const std::array arg_shifts) { - return (visitor.*fn)(Args((instruction & arg_masks[iota]) >> arg_shifts[iota])...); + template + struct VisitorCaller { + template + static constexpr auto Make(std::integer_sequence, + ReturnType (V::*const fn)(Args...), + const std::array arg_masks, + const std::array arg_shifts) { + static_assert(std::is_same_v, "Member function is not from Matcher's Visitor"); + return [fn, arg_masks, arg_shifts](V& v, opcode_type instruction) { + (void)instruction; + (void)arg_masks; + (void)arg_shifts; + return (v.*fn)(Args((instruction & arg_masks[iota]) >> arg_shifts[iota])...); + }; + } + }; + + template + struct VisitorCaller { + template + static constexpr auto Make(std::integer_sequence, + ReturnType (V::*const fn)(Args...) const, + const std::array arg_masks, + const std::array arg_shifts) { + static_assert(std::is_same_v, "Member function is not from Matcher's Visitor"); + return [fn, arg_masks, arg_shifts](const V& v, opcode_type instruction) { + (void)instruction; + (void)arg_masks; + (void)arg_shifts; + return (v.*fn)(Args((instruction & arg_masks[iota]) >> arg_shifts[iota])...); + }; } }; #ifdef _MSC_VER # pragma warning(pop) #endif - template - static inline constexpr auto GetMatcherFunction(V& visitor, [[maybe_unused]] opcode_type instruction, ReturnType (V::*const fn)(Args...)) { - constexpr auto arg_masks = std::get<0>(GetArgInfo(bitstring)); - constexpr auto arg_shifts = std::get<1>(GetArgInfo(bitstring)); - return VisitorCaller::Invoke(std::index_sequence_for(), visitor, instruction, fn, arg_masks, arg_shifts); + /// @brief Creates a matcher that can match and parse instructions based on bitstring. + /// See also: GetMaskAndExpect and GetArgInfo for format of bitstring. + template + static constexpr auto GetMatcher(F fn) { + constexpr size_t args_count = mcl::parameter_count_v; + constexpr auto mask = std::get<0>(GetMaskAndExpect(bitstring)); + constexpr auto expect = std::get<1>(GetMaskAndExpect(bitstring)); + constexpr auto arg_masks = std::get<0>(GetArgInfo(bitstring)); + constexpr auto arg_shifts = std::get<1>(GetArgInfo(bitstring)); + const auto proxy_fn = VisitorCaller::Make(std::make_index_sequence(), fn, arg_masks, arg_shifts); + return MatcherT(mask, expect, proxy_fn); } }; -#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail>::GetMaskAndExpect(bitstring) - -#define DYNARMIC_DECODER_GET_MATCHER_FUNCTION(MatcherT, fn, name, bitstring) Decoder::detail::detail>::template GetMatcherFunction(visitor, instruction, &V::fn) +#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail>::template GetMatcher(&V::fn) } // namespace detail } // namespace Dynarmic::Decoder diff --git a/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h b/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h index 49095f67e3..194f646ed2 100644 --- a/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h +++ b/src/dynarmic/src/dynarmic/frontend/decoder/matcher.h @@ -15,41 +15,50 @@ namespace Dynarmic::Decoder { /// Generic instruction handling construct. -/// @tparam V An arbitrary visitor type that will be passed through -/// to the function being handled. This type must be the -/// type of the first parameter in a handler function. -/// @tparam T Type representing an opcode. This must be the -/// type of the second parameter in a handler function. -template +/// @tparam Visitor An arbitrary visitor type that will be passed through +/// to the function being handled. This type must be the +/// type of the first parameter in a handler function. +/// @tparam OpcodeType Type representing an opcode. This must be the +/// type of the second parameter in a handler function. +template class Matcher { public: - using opcode_type = T; - using visitor_type = V; + using opcode_type = OpcodeType; + using visitor_type = Visitor; + using handler_return_type = typename Visitor::instruction_return_type; + using handler_function = std::function; + Matcher(opcode_type mask, opcode_type expected, handler_function func) + : mask{mask}, expected{expected}, fn{std::move(func)} {} - constexpr Matcher(T mask, T expected) noexcept - : mask{mask} - , expected{expected} - {} - - /// @brief Gets the mask for this instruction. - constexpr inline T GetMask() const noexcept { + /// Gets the mask for this instruction. + inline opcode_type GetMask() const noexcept { return mask; } - /// @brief Gets the expected value after masking for this instruction. - constexpr inline T GetExpected() const noexcept { + /// Gets the expected value after masking for this instruction. + inline opcode_type GetExpected() const noexcept { return expected; } - /// @brief Tests to see if the given instruction is the instruction this matcher represents. + /// Tests to see if the given instruction is the instruction this matcher represents. /// @param instruction The instruction to test /// @returns true if the given instruction matches. - constexpr inline bool Matches(T instruction) const noexcept { + inline bool Matches(opcode_type instruction) const noexcept { return (instruction & mask) == expected; } - T mask; - T expected; + /// Calls the corresponding instruction handler on visitor for this type of instruction. + /// @param v The visitor to use + /// @param instruction The instruction to decode. + inline handler_return_type call(Visitor& v, opcode_type instruction) const noexcept { + ASSERT(Matches(instruction)); + return fn(v, instruction); + } + +private: + opcode_type mask; + opcode_type expected; + handler_function fn; }; } // namespace Dynarmic::Decoder diff --git a/src/dynarmic/src/dynarmic/frontend/imm.h b/src/dynarmic/src/dynarmic/frontend/imm.h index f305b5bfc8..56fbcbda0e 100644 --- a/src/dynarmic/src/dynarmic/frontend/imm.h +++ b/src/dynarmic/src/dynarmic/frontend/imm.h @@ -27,8 +27,9 @@ class Imm { public: static constexpr size_t bit_size = bit_size_; - explicit Imm(u32 value) : value(value) { - DEBUG_ASSERT((mcl::bit::get_bits<0, bit_size - 1>(value) == value) && "More bits in value than expected"); + explicit Imm(u32 value) + : value(value) { + ASSERT((mcl::bit::get_bits<0, bit_size - 1>(value) == value) && "More bits in value than expected"); } template diff --git a/src/dynarmic/tests/decoder_tests.cpp b/src/dynarmic/tests/decoder_tests.cpp index 17ed2c0ce5..2a6c0f6a4f 100644 --- a/src/dynarmic/tests/decoder_tests.cpp +++ b/src/dynarmic/tests/decoder_tests.cpp @@ -51,7 +51,7 @@ TEST_CASE("ASIMD Decoder: Ensure table order correctness", "[decode][a32][.]") { const bool iserr = is_decode_error(*iter, instruction); const auto alternative = std::find_if(table.cbegin(), iter, [instruction](const auto& m) { - return (instruction & mask) == expect; + return m.Matches(instruction); }); const bool altiserr = is_decode_error(*alternative, instruction); diff --git a/src/dynarmic/tests/print_info.cpp b/src/dynarmic/tests/print_info.cpp index 988a8d294e..6d6109d849 100644 --- a/src/dynarmic/tests/print_info.cpp +++ b/src/dynarmic/tests/print_info.cpp @@ -43,12 +43,12 @@ using namespace Dynarmic; std::string_view GetNameOfA32Instruction(u32 instruction) { - if (auto const vfp_decoder = A32::GetNameVFP(instruction)) - return *vfp_decoder; - else if (auto const asimd_decoder = A32::GetNameASIMD(instruction)) - return *asimd_decoder; - else if (auto const decoder = A32::GetNameArm(instruction)) - return *decoder; + if (auto const vfp_decoder = A32::DecodeVFP(instruction)) + return *A32::GetNameVFP(instruction); + else if (auto const asimd_decoder = A32::DecodeASIMD(instruction)) + return *A32::GetNameASIMD(instruction); + else if (auto const decoder = A32::DecodeArm(instruction)) + return *A32::GetNameARM(instruction); return ""; }