mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-05-13 21:47:02 +02:00
[dynarmic] remove decode matcher function handlers using std::function<>, use raw function pointers (#3920)
issues: - std::function<> is used, which is famously bad - storage of tehse in tables makes big fucking tables for no good reason - lets just store a normal pointer and stuff! :) this pr attempts to address that Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3920 Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
This commit is contained in:
parent
a6423a88cc
commit
eec460ec2e
15 changed files with 187 additions and 276 deletions
|
|
@ -761,8 +761,7 @@ 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);
|
return this->SIMDOffset(scale, shift, opc_0, Rm, option, Rn, Vt);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context,
|
std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, mcontext_t* context, fpsimd_context* fpsimd_context) {
|
||||||
fpsimd_context* fpsimd_context) {
|
|
||||||
std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31);
|
std::span<u64, 31> regs(reinterpret_cast<u64*>(context->regs), 31);
|
||||||
std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpsimd_context->vregs), 32);
|
std::span<u128, 32> vregs(reinterpret_cast<u128*>(fpsimd_context->vregs), 32);
|
||||||
u64& sp = *reinterpret_cast<u64*>(&context->sp);
|
u64& sp = *reinterpret_cast<u64*>(&context->sp);
|
||||||
|
|
@ -772,9 +771,9 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
|
||||||
u32 instruction = memory.Read32(pc);
|
u32 instruction = memory.Read32(pc);
|
||||||
bool was_executed = false;
|
bool was_executed = false;
|
||||||
|
|
||||||
auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction);
|
auto decoder = Dynarmic::A64::Decode<VisitorBase, bool>(visitor, instruction);
|
||||||
if (decoder) {
|
if (decoder) {
|
||||||
was_executed = decoder->get().call(visitor, instruction);
|
was_executed = *decoder;
|
||||||
} else {
|
} else {
|
||||||
was_executed = false;
|
was_executed = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,48 +26,41 @@ namespace Dynarmic::A32 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using ArmMatcher = Decoder::Matcher<Visitor, u32>;
|
using ArmMatcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename Visitor>
|
template<typename V, typename ReturnType>
|
||||||
using ArmDecodeTable = std::array<std::vector<ArmMatcher<Visitor>>, 0x1000>;
|
static std::optional<ReturnType> DecodeArm(V& visitor, u32 instruction) noexcept {
|
||||||
|
auto const make_fast_index = [](u32 a) {
|
||||||
namespace detail {
|
return ((a >> 4) & 0x00F) | ((a >> 16) & 0xFF0);
|
||||||
inline size_t ToFastLookupIndexArm(u32 instruction) noexcept {
|
};
|
||||||
return ((instruction >> 4) & 0x00F) | ((instruction >> 16) & 0xFF0);
|
struct Handler {
|
||||||
}
|
bool (*fn)(V&, u32);
|
||||||
} // namespace detail
|
u32 mask;
|
||||||
|
u32 expect;
|
||||||
template<typename V>
|
};
|
||||||
static ArmDecodeTable<V> GetArmDecodeTable() noexcept {
|
alignas(64) static const std::array<std::vector<Handler>, 0x1000> table = [&] {
|
||||||
ArmDecodeTable<V> table{};
|
std::array<std::vector<Handler>, 0x1000> t{};
|
||||||
for (size_t i = 0; i < table.size(); ++i) {
|
for (size_t i = 0; i < t.size(); ++i) {
|
||||||
// PLEASE HEAP ELLIDE
|
#define INST(fn, name, bitstring) \
|
||||||
for (auto const& e : std::vector<ArmMatcher<V>>{
|
do { \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
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);
|
||||||
#include "./arm.inc"
|
#include "./arm.inc"
|
||||||
#undef INST
|
#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;
|
||||||
return table;
|
}();
|
||||||
|
for (auto const& e : table[make_fast_index(instruction)])
|
||||||
|
if ((instruction & e.mask) == e.expect)
|
||||||
|
return e.fn(visitor, instruction);
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static std::optional<std::reference_wrapper<const ArmMatcher<V>>> DecodeArm(u32 instruction) noexcept {
|
static std::optional<std::string_view> GetNameArm(u32 inst) noexcept {
|
||||||
alignas(64) static const auto table = GetArmDecodeTable<V>();
|
|
||||||
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<std::reference_wrapper<const ArmMatcher<V>>>(*iter) : std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename V>
|
|
||||||
static std::optional<std::string_view> GetNameARM(u32 inst) noexcept {
|
|
||||||
std::vector<std::pair<std::string_view, ArmMatcher<V>>> list = {
|
std::vector<std::pair<std::string_view, ArmMatcher<V>>> list = {
|
||||||
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
|
#define INST(fn, name, bitstring) { name, DYNARMIC_DECODER_GET_MATCHER(ArmMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)) },
|
||||||
#include "./arm.inc"
|
#include "./arm.inc"
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,16 @@ namespace Dynarmic::A32 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using ASIMDMatcher = Decoder::Matcher<Visitor, u32>;
|
using ASIMDMatcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V, typename ReturnType>
|
||||||
static std::optional<std::reference_wrapper<const ASIMDMatcher<V>>> DecodeASIMD(u32 instruction) noexcept {
|
static std::optional<ReturnType> DecodeASIMD(V& visitor, u32 instruction) noexcept {
|
||||||
alignas(64) static const auto table = std::array{
|
#define INST(fn, name, bitstring) \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(ASIMDMatcher, fn, name, Decoder::detail::StringToArray<32>(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);
|
||||||
#include "./asimd.inc"
|
#include "./asimd.inc"
|
||||||
#undef INST
|
#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<std::reference_wrapper<const ASIMDMatcher<V>>>(*iter) : std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,16 @@ namespace Dynarmic::A32 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using Thumb16Matcher = Decoder::Matcher<Visitor, u16>;
|
using Thumb16Matcher = Decoder::Matcher<Visitor, u16>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V, typename ReturnType>
|
||||||
static std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
|
static std::optional<ReturnType> DecodeThumb16(V& visitor, u16 instruction) {
|
||||||
alignas(64) static const auto table = std::array{
|
#define INST(fn, name, bitstring) \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb16Matcher, fn, name, Decoder::detail::StringToArray<16>(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);
|
||||||
#include "./thumb16.inc"
|
#include "./thumb16.inc"
|
||||||
#undef INST
|
#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<std::reference_wrapper<const Thumb16Matcher<V>>>(*iter) : std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,16 @@ namespace Dynarmic::A32 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using Thumb32Matcher = Decoder::Matcher<Visitor, u32>;
|
using Thumb32Matcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V, typename ReturnType>
|
||||||
static std::optional<std::reference_wrapper<const Thumb32Matcher<V>>> DecodeThumb32(u32 instruction) {
|
static std::optional<ReturnType> DecodeThumb32(V& visitor, u32 instruction) {
|
||||||
alignas(64) static const auto table = std::array{
|
#define INST(fn, name, bitstring) \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Thumb32Matcher, fn, name, Decoder::detail::StringToArray<32>(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);
|
||||||
#include "./thumb32.inc"
|
#include "./thumb32.inc"
|
||||||
#undef INST
|
#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<std::reference_wrapper<const Thumb32Matcher<V>>>(*iter) : std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
|
|
||||||
|
|
@ -23,32 +23,18 @@ namespace Dynarmic::A32 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using VFPMatcher = Decoder::Matcher<Visitor, u32>;
|
using VFPMatcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V, typename ReturnType>
|
||||||
static std::optional<std::reference_wrapper<const VFPMatcher<V>>> DecodeVFP(u32 instruction) {
|
static std::optional<ReturnType> DecodeVFP(V& visitor, u32 instruction) {
|
||||||
using Table = std::vector<VFPMatcher<V>>;
|
bool const i_uncond = (instruction & 0xF0000000) == 0xF0000000;
|
||||||
alignas(64) static const struct Tables {
|
#define INST(fn, name, bitstring) \
|
||||||
Table unconditional;
|
do { \
|
||||||
Table conditional;
|
auto const [mask, expect] = DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \
|
||||||
} tables = []() {
|
bool const m_uncond = (mask & 0xF0000000) == 0xF0000000; \
|
||||||
Table list = {
|
if ((instruction & mask) == expect && m_uncond == i_uncond) return DYNARMIC_DECODER_GET_MATCHER_FUNCTION(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)); \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(VFPMatcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
} while (0);
|
||||||
#include "./vfp.inc"
|
#include "./vfp.inc"
|
||||||
#undef INST
|
#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<std::reference_wrapper<const VFPMatcher<V>>>(*iter) : std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCall
|
||||||
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
|
tcb->PreCodeTranslationHook(false, arm_pc, visitor.ir);
|
||||||
ticks_for_instruction = tcb->GetTicksForCode(false, arm_pc, *arm_instruction);
|
ticks_for_instruction = tcb->GetTicksForCode(false, arm_pc, *arm_instruction);
|
||||||
|
|
||||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(*arm_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor, bool>(visitor, *arm_instruction)) {
|
||||||
should_continue = vfp_decoder->get().call(visitor, *arm_instruction);
|
should_continue = *vfp_decoder;
|
||||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(*arm_instruction)) {
|
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor, bool>(visitor, *arm_instruction)) {
|
||||||
should_continue = asimd_decoder->get().call(visitor, *arm_instruction);
|
should_continue = *asimd_decoder;
|
||||||
} else if (const auto decoder = DecodeArm<TranslatorVisitor>(*arm_instruction)) {
|
} else if (const auto decoder = DecodeArm<TranslatorVisitor, bool>(visitor, *arm_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, *arm_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.arm_UDF();
|
should_continue = visitor.arm_UDF();
|
||||||
}
|
}
|
||||||
|
|
@ -88,12 +88,12 @@ bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descript
|
||||||
|
|
||||||
const u64 ticks_for_instruction = 1;
|
const u64 ticks_for_instruction = 1;
|
||||||
|
|
||||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(arm_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor, bool>(visitor, arm_instruction)) {
|
||||||
should_continue = vfp_decoder->get().call(visitor, arm_instruction);
|
should_continue = *vfp_decoder;
|
||||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(arm_instruction)) {
|
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor, bool>(visitor, arm_instruction)) {
|
||||||
should_continue = asimd_decoder->get().call(visitor, arm_instruction);
|
should_continue = *asimd_decoder;
|
||||||
} else if (const auto decoder = DecodeArm<TranslatorVisitor>(arm_instruction)) {
|
} else if (const auto decoder = DecodeArm<TranslatorVisitor, bool>(visitor, arm_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, arm_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.arm_UDF();
|
should_continue = visitor.arm_UDF();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,24 +126,24 @@ void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCa
|
||||||
|
|
||||||
if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
|
if (IsUnconditionalInstruction(is_thumb_16, thumb_instruction) || visitor.ThumbConditionPassed()) {
|
||||||
if (is_thumb_16) {
|
if (is_thumb_16) {
|
||||||
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
if (const auto decoder = DecodeThumb16<TranslatorVisitor, bool>(visitor, u16(thumb_instruction))) {
|
||||||
should_continue = decoder->get().call(visitor, static_cast<u16>(thumb_instruction));
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb16_UDF();
|
should_continue = visitor.thumb16_UDF();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (MaybeVFPOrASIMDInstruction(thumb_instruction)) {
|
if (MaybeVFPOrASIMDInstruction(thumb_instruction)) {
|
||||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(thumb_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = vfp_decoder->get().call(visitor, thumb_instruction);
|
should_continue = *vfp_decoder;
|
||||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(ConvertASIMDInstruction(thumb_instruction))) {
|
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor, bool>(visitor, ConvertASIMDInstruction(thumb_instruction))) {
|
||||||
should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction));
|
should_continue = *asimd_decoder;
|
||||||
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor>(thumb_instruction)) {
|
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, thumb_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb32_UDF();
|
should_continue = visitor.thumb32_UDF();
|
||||||
}
|
}
|
||||||
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor>(thumb_instruction)) {
|
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, thumb_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb32_UDF();
|
should_continue = visitor.thumb32_UDF();
|
||||||
}
|
}
|
||||||
|
|
@ -187,25 +187,25 @@ bool TranslateSingleThumbInstruction(IR::Block& block, LocationDescriptor descri
|
||||||
const u64 ticks_for_instruction = 1;
|
const u64 ticks_for_instruction = 1;
|
||||||
|
|
||||||
if (is_thumb_16) {
|
if (is_thumb_16) {
|
||||||
if (const auto decoder = DecodeThumb16<TranslatorVisitor>(static_cast<u16>(thumb_instruction))) {
|
if (const auto decoder = DecodeThumb16<TranslatorVisitor, bool>(visitor, u16(thumb_instruction))) {
|
||||||
should_continue = decoder->get().call(visitor, static_cast<u16>(thumb_instruction));
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb16_UDF();
|
should_continue = visitor.thumb16_UDF();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thumb_instruction = mcl::bit::swap_halves_32(thumb_instruction);
|
thumb_instruction = mcl::bit::swap_halves_32(thumb_instruction);
|
||||||
if (MaybeVFPOrASIMDInstruction(thumb_instruction)) {
|
if (MaybeVFPOrASIMDInstruction(thumb_instruction)) {
|
||||||
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor>(thumb_instruction)) {
|
if (const auto vfp_decoder = DecodeVFP<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = vfp_decoder->get().call(visitor, thumb_instruction);
|
should_continue = *vfp_decoder;
|
||||||
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor>(ConvertASIMDInstruction(thumb_instruction))) {
|
} else if (const auto asimd_decoder = DecodeASIMD<TranslatorVisitor, bool>(visitor, ConvertASIMDInstruction(thumb_instruction))) {
|
||||||
should_continue = asimd_decoder->get().call(visitor, ConvertASIMDInstruction(thumb_instruction));
|
should_continue = *asimd_decoder;
|
||||||
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor>(thumb_instruction)) {
|
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, thumb_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb32_UDF();
|
should_continue = visitor.thumb32_UDF();
|
||||||
}
|
}
|
||||||
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor>(thumb_instruction)) {
|
} else if (const auto decoder = DecodeThumb32<TranslatorVisitor, bool>(visitor, thumb_instruction)) {
|
||||||
should_continue = decoder->get().call(visitor, thumb_instruction);
|
should_continue = *decoder;
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.thumb32_UDF();
|
should_continue = visitor.thumb32_UDF();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,45 +26,37 @@ namespace Dynarmic::A64 {
|
||||||
template<typename Visitor>
|
template<typename Visitor>
|
||||||
using Matcher = Decoder::Matcher<Visitor, u32>;
|
using Matcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename Visitor>
|
template<typename V, typename ReturnType>
|
||||||
using DecodeTable = std::array<std::vector<Matcher<Visitor>>, 0x1000>;
|
static std::optional<ReturnType> Decode(V& visitor, u32 instruction) noexcept {
|
||||||
|
auto const make_fast_index = [](u32 a) {
|
||||||
namespace detail {
|
return ((a >> 10) & 0x00F) | ((a >> 18) & 0xFF0);
|
||||||
inline size_t ToFastLookupIndex(u32 instruction) {
|
};
|
||||||
return ((instruction >> 10) & 0x00F) | ((instruction >> 18) & 0xFF0);
|
struct Handler {
|
||||||
}
|
bool (*fn)(V&, u32);
|
||||||
} // namespace detail
|
u32 mask;
|
||||||
|
u32 expect;
|
||||||
template<typename V>
|
};
|
||||||
inline DecodeTable<V> GetDecodeTable() {
|
alignas(64) static const std::array<std::vector<Handler>, 0x1000> table = [&] {
|
||||||
DecodeTable<V> table{};
|
std::array<std::vector<Handler>, 0x1000> t{};
|
||||||
for (size_t i = 0; i < table.size(); ++i) {
|
for (size_t i = 0; i < t.size(); ++i) {
|
||||||
// PLEASE HEAP ELLIDE
|
#define INST(fn, name, bitstring) \
|
||||||
for (auto const& e : std::vector<Matcher<V>>{
|
do { \
|
||||||
#define INST(fn, name, bitstring) DYNARMIC_DECODER_GET_MATCHER(Matcher, fn, name, Decoder::detail::StringToArray<32>(bitstring)),
|
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);
|
||||||
#include "./a64.inc"
|
#include "./a64.inc"
|
||||||
#undef INST
|
#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;
|
||||||
return table;
|
}();
|
||||||
}
|
for (auto const& e : table[make_fast_index(instruction)])
|
||||||
|
if ((instruction & e.mask) == e.expect)
|
||||||
/// In practice it must always suceed, otherwise something else unrelated would have gone awry
|
return e.fn(visitor, instruction);
|
||||||
template<typename V>
|
return std::nullopt;
|
||||||
inline std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) {
|
|
||||||
alignas(64) static const auto table = GetDecodeTable<V>();
|
|
||||||
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<const Matcher<V>>(*iter) }
|
|
||||||
: std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,8 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu
|
||||||
do {
|
do {
|
||||||
const u64 pc = visitor.ir.current_location->PC();
|
const u64 pc = visitor.ir.current_location->PC();
|
||||||
if (const auto instruction = memory_read_code(pc)) {
|
if (const auto instruction = memory_read_code(pc)) {
|
||||||
auto decoder = Decode<TranslatorVisitor>(*instruction);
|
if (auto decoder = Decode<TranslatorVisitor, bool>(visitor, *instruction)) {
|
||||||
if (decoder) {
|
should_continue = *decoder;
|
||||||
should_continue = decoder->get().call(visitor, *instruction);
|
|
||||||
} else {
|
} else {
|
||||||
should_continue = visitor.RaiseException(Exception::UnallocatedEncoding);
|
should_continue = visitor.RaiseException(Exception::UnallocatedEncoding);
|
||||||
}
|
}
|
||||||
|
|
@ -47,13 +46,9 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu
|
||||||
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction) {
|
||||||
TranslatorVisitor visitor{block, descriptor, {}};
|
TranslatorVisitor visitor{block, descriptor, {}};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = false;
|
||||||
auto const decoder = Decode<TranslatorVisitor>(instruction);
|
if (auto const decoder = Decode<TranslatorVisitor, bool>(visitor, instruction))
|
||||||
if (decoder) {
|
should_continue = *decoder;
|
||||||
should_continue = decoder->get().call(visitor, instruction);
|
|
||||||
} else {
|
|
||||||
should_continue = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
||||||
block.CycleCount()++;
|
block.CycleCount()++;
|
||||||
|
|
|
||||||
|
|
@ -8,31 +8,25 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "dynarmic/mcl/bit.hpp"
|
#include "dynarmic/mcl/bit.hpp"
|
||||||
#include "dynarmic/mcl/function_info.hpp"
|
|
||||||
|
|
||||||
namespace Dynarmic::Decoder {
|
namespace Dynarmic::Decoder {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
inline consteval std::array<char, N> StringToArray(const char (&str)[N + 1]) {
|
inline consteval std::array<char, N> StringToArray(const char (&s)[N + 1]) {
|
||||||
std::array<char, N> result{};
|
std::array<char, N> r{};
|
||||||
for (size_t i = 0; i < N; i++) {
|
for (size_t i = 0; i < N; i++)
|
||||||
result[i] = str[i];
|
r[i] = s[i];
|
||||||
}
|
return r;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// @brief Helper functions for the decoders.
|
||||||
* Helper functions for the decoders.
|
/// @tparam MatcherT The type of the Matcher to use.
|
||||||
*
|
|
||||||
* @tparam MatcherT The type of the Matcher to use.
|
|
||||||
*/
|
|
||||||
template<class MatcherT>
|
template<class MatcherT>
|
||||||
struct detail {
|
struct detail {
|
||||||
using opcode_type = typename MatcherT::opcode_type;
|
using opcode_type = typename MatcherT::opcode_type;
|
||||||
|
|
@ -40,17 +34,15 @@ struct detail {
|
||||||
|
|
||||||
static constexpr size_t opcode_bitsize = mcl::bitsizeof<opcode_type>;
|
static constexpr size_t opcode_bitsize = mcl::bitsizeof<opcode_type>;
|
||||||
|
|
||||||
/**
|
/// @brief Generates the mask and the expected value after masking from a given bitstring.
|
||||||
* 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 '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.
|
||||||
* A '1' in a bitstring indicates that a one must be present at that bit position.
|
|
||||||
*/
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
static constexpr auto GetMaskAndExpect(std::array<char, opcode_bitsize> bitstring) {
|
static constexpr auto GetMaskAndExpect(std::array<char, opcode_bitsize> bitstring) {
|
||||||
#else
|
#else
|
||||||
static consteval auto GetMaskAndExpect(std::array<char, opcode_bitsize> bitstring) {
|
static consteval auto GetMaskAndExpect(std::array<char, opcode_bitsize> bitstring) {
|
||||||
#endif
|
#endif
|
||||||
const auto one = static_cast<opcode_type>(1);
|
const auto one = opcode_type(1);
|
||||||
opcode_type mask = 0, expect = 0;
|
opcode_type mask = 0, expect = 0;
|
||||||
for (size_t i = 0; i < opcode_bitsize; i++) {
|
for (size_t i = 0; i < opcode_bitsize; i++) {
|
||||||
const size_t bit_position = opcode_bitsize - i - 1;
|
const size_t bit_position = opcode_bitsize - i - 1;
|
||||||
|
|
@ -101,7 +93,7 @@ struct detail {
|
||||||
}
|
}
|
||||||
#if !defined(DYNARMIC_IGNORE_ASSERTS) && !defined(__ANDROID__)
|
#if !defined(DYNARMIC_IGNORE_ASSERTS) && !defined(__ANDROID__)
|
||||||
// Avoids a MSVC ICE, and avoids Android NDK issue.
|
// Avoids a MSVC ICE, and avoids Android NDK issue.
|
||||||
ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m) { return m != 0; }));
|
DEBUG_ASSERT(std::all_of(masks.begin(), masks.end(), [](auto m) { return m != 0; }));
|
||||||
#endif
|
#endif
|
||||||
return std::make_tuple(masks, shifts);
|
return std::make_tuple(masks, shifts);
|
||||||
}
|
}
|
||||||
|
|
@ -109,65 +101,32 @@ struct detail {
|
||||||
/// @brief This struct's Make member function generates a lambda which decodes an instruction
|
/// @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
|
/// based on the provided arg_masks and arg_shifts. The Visitor member function to call is
|
||||||
/// provided as a template argument.
|
/// provided as a template argument.
|
||||||
template<typename FnT>
|
|
||||||
struct VisitorCaller;
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning)
|
# pragma warning(disable : 4800) // forcing value to bool 'true' or 'false' (performance warning)
|
||||||
#endif
|
#endif
|
||||||
template<typename V, typename... Args, typename ReturnType>
|
template<typename V, typename ReturnType, typename... Args>
|
||||||
struct VisitorCaller<ReturnType (V::*)(Args...)> {
|
struct VisitorCaller {
|
||||||
template<size_t... iota>
|
template<std::size_t... iota>
|
||||||
static constexpr auto Make(std::integer_sequence<size_t, iota...>,
|
static inline constexpr auto Invoke(std::index_sequence<iota...>, V& visitor, [[maybe_unused]] opcode_type instruction, ReturnType (V::*const fn)(Args...), [[maybe_unused]] const std::array<opcode_type, sizeof...(Args)> arg_masks, [[maybe_unused]] const std::array<size_t, sizeof...(Args)> arg_shifts) {
|
||||||
ReturnType (V::*const fn)(Args...),
|
return (visitor.*fn)(Args((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
|
||||||
const std::array<opcode_type, sizeof...(iota)> arg_masks,
|
|
||||||
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
|
||||||
static_assert(std::is_same_v<visitor_type, 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<typename V, typename... Args, typename ReturnType>
|
|
||||||
struct VisitorCaller<ReturnType (V::*)(Args...) const> {
|
|
||||||
template<size_t... iota>
|
|
||||||
static constexpr auto Make(std::integer_sequence<size_t, iota...>,
|
|
||||||
ReturnType (V::*const fn)(Args...) const,
|
|
||||||
const std::array<opcode_type, sizeof...(iota)> arg_masks,
|
|
||||||
const std::array<size_t, sizeof...(iota)> arg_shifts) {
|
|
||||||
static_assert(std::is_same_v<visitor_type, const 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
|
#ifdef _MSC_VER
|
||||||
# pragma warning(pop)
|
# pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// @brief Creates a matcher that can match and parse instructions based on bitstring.
|
template<auto bitstring, typename V, typename ReturnType, typename... Args>
|
||||||
/// See also: GetMaskAndExpect and GetArgInfo for format of bitstring.
|
static inline constexpr auto GetMatcherFunction(V& visitor, [[maybe_unused]] opcode_type instruction, ReturnType (V::*const fn)(Args...)) {
|
||||||
template<auto bitstring, typename F>
|
constexpr auto arg_masks = std::get<0>(GetArgInfo<sizeof...(Args)>(bitstring));
|
||||||
static constexpr auto GetMatcher(F fn) {
|
constexpr auto arg_shifts = std::get<1>(GetArgInfo<sizeof...(Args)>(bitstring));
|
||||||
constexpr size_t args_count = mcl::parameter_count_v<F>;
|
return VisitorCaller<V, ReturnType, Args...>::Invoke(std::index_sequence_for<Args...>(), visitor, instruction, fn, arg_masks, arg_shifts);
|
||||||
constexpr auto mask = std::get<0>(GetMaskAndExpect(bitstring));
|
|
||||||
constexpr auto expect = std::get<1>(GetMaskAndExpect(bitstring));
|
|
||||||
constexpr auto arg_masks = std::get<0>(GetArgInfo<args_count>(bitstring));
|
|
||||||
constexpr auto arg_shifts = std::get<1>(GetArgInfo<args_count>(bitstring));
|
|
||||||
const auto proxy_fn = VisitorCaller<F>::Make(std::make_index_sequence<args_count>(), fn, arg_masks, arg_shifts);
|
|
||||||
return MatcherT(mask, expect, proxy_fn);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail<MatcherT<V>>::template GetMatcher<bitstring>(&V::fn)
|
#define DYNARMIC_DECODER_GET_MATCHER(MatcherT, fn, name, bitstring) Decoder::detail::detail<MatcherT<V>>::GetMaskAndExpect(bitstring)
|
||||||
|
|
||||||
|
#define DYNARMIC_DECODER_GET_MATCHER_FUNCTION(MatcherT, fn, name, bitstring) Decoder::detail::detail<MatcherT<V>>::template GetMatcherFunction<bitstring, V>(visitor, instruction, &V::fn)
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace Dynarmic::Decoder
|
} // namespace Dynarmic::Decoder
|
||||||
|
|
|
||||||
|
|
@ -15,50 +15,41 @@
|
||||||
namespace Dynarmic::Decoder {
|
namespace Dynarmic::Decoder {
|
||||||
|
|
||||||
/// Generic instruction handling construct.
|
/// Generic instruction handling construct.
|
||||||
/// @tparam Visitor An arbitrary visitor type that will be passed through
|
/// @tparam V An arbitrary visitor type that will be passed through
|
||||||
/// to the function being handled. This type must be the
|
/// to the function being handled. This type must be the
|
||||||
/// type of the first parameter in a handler function.
|
/// type of the first parameter in a handler function.
|
||||||
/// @tparam OpcodeType Type representing an opcode. This must be the
|
/// @tparam T Type representing an opcode. This must be the
|
||||||
/// type of the second parameter in a handler function.
|
/// type of the second parameter in a handler function.
|
||||||
template<typename Visitor, typename OpcodeType>
|
template<typename V, typename T>
|
||||||
class Matcher {
|
class Matcher {
|
||||||
public:
|
public:
|
||||||
using opcode_type = OpcodeType;
|
using opcode_type = T;
|
||||||
using visitor_type = Visitor;
|
using visitor_type = V;
|
||||||
using handler_return_type = typename Visitor::instruction_return_type;
|
|
||||||
using handler_function = std::function<handler_return_type(Visitor&, opcode_type)>;
|
|
||||||
Matcher(opcode_type mask, opcode_type expected, handler_function func)
|
|
||||||
: mask{mask}, expected{expected}, fn{std::move(func)} {}
|
|
||||||
|
|
||||||
/// Gets the mask for this instruction.
|
constexpr Matcher(T mask, T expected) noexcept
|
||||||
inline opcode_type GetMask() const noexcept {
|
: mask{mask}
|
||||||
|
, expected{expected}
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// @brief Gets the mask for this instruction.
|
||||||
|
constexpr inline T GetMask() const noexcept {
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the expected value after masking for this instruction.
|
/// @brief Gets the expected value after masking for this instruction.
|
||||||
inline opcode_type GetExpected() const noexcept {
|
constexpr inline T GetExpected() const noexcept {
|
||||||
return expected;
|
return expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests to see if the given instruction is the instruction this matcher represents.
|
/// @brief Tests to see if the given instruction is the instruction this matcher represents.
|
||||||
/// @param instruction The instruction to test
|
/// @param instruction The instruction to test
|
||||||
/// @returns true if the given instruction matches.
|
/// @returns true if the given instruction matches.
|
||||||
inline bool Matches(opcode_type instruction) const noexcept {
|
constexpr inline bool Matches(T instruction) const noexcept {
|
||||||
return (instruction & mask) == expected;
|
return (instruction & mask) == expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls the corresponding instruction handler on visitor for this type of instruction.
|
T mask;
|
||||||
/// @param v The visitor to use
|
T expected;
|
||||||
/// @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
|
} // namespace Dynarmic::Decoder
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,8 @@ class Imm {
|
||||||
public:
|
public:
|
||||||
static constexpr size_t bit_size = bit_size_;
|
static constexpr size_t bit_size = bit_size_;
|
||||||
|
|
||||||
explicit Imm(u32 value)
|
explicit Imm(u32 value) : value(value) {
|
||||||
: value(value) {
|
DEBUG_ASSERT((mcl::bit::get_bits<0, bit_size - 1>(value) == value) && "More bits in value than expected");
|
||||||
ASSERT((mcl::bit::get_bits<0, bit_size - 1>(value) == value) && "More bits in value than expected");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T = u32>
|
template<typename T = u32>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ TEST_CASE("ASIMD Decoder: Ensure table order correctness", "[decode][a32][.]") {
|
||||||
|
|
||||||
const bool iserr = is_decode_error(*iter, instruction);
|
const bool iserr = is_decode_error(*iter, instruction);
|
||||||
const auto alternative = std::find_if(table.cbegin(), iter, [instruction](const auto& m) {
|
const auto alternative = std::find_if(table.cbegin(), iter, [instruction](const auto& m) {
|
||||||
return m.Matches(instruction);
|
return (instruction & mask) == expect;
|
||||||
});
|
});
|
||||||
const bool altiserr = is_decode_error(*alternative, instruction);
|
const bool altiserr = is_decode_error(*alternative, instruction);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,12 +43,12 @@
|
||||||
using namespace Dynarmic;
|
using namespace Dynarmic;
|
||||||
|
|
||||||
std::string_view GetNameOfA32Instruction(u32 instruction) {
|
std::string_view GetNameOfA32Instruction(u32 instruction) {
|
||||||
if (auto const vfp_decoder = A32::DecodeVFP<A32::TranslatorVisitor>(instruction))
|
if (auto const vfp_decoder = A32::GetNameVFP<A32::TranslatorVisitor>(instruction))
|
||||||
return *A32::GetNameVFP<A32::TranslatorVisitor>(instruction);
|
return *vfp_decoder;
|
||||||
else if (auto const asimd_decoder = A32::DecodeASIMD<A32::TranslatorVisitor>(instruction))
|
else if (auto const asimd_decoder = A32::GetNameASIMD<A32::TranslatorVisitor>(instruction))
|
||||||
return *A32::GetNameASIMD<A32::TranslatorVisitor>(instruction);
|
return *asimd_decoder;
|
||||||
else if (auto const decoder = A32::DecodeArm<A32::TranslatorVisitor>(instruction))
|
else if (auto const decoder = A32::GetNameArm<A32::TranslatorVisitor>(instruction))
|
||||||
return *A32::GetNameARM<A32::TranslatorVisitor>(instruction);
|
return *decoder;
|
||||||
return "<null>";
|
return "<null>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue