mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-22 15:48:56 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 466788c006 | |||
| 19e2dba35a | |||
| 0634b4a278 | |||
| ee428deb1e | |||
| 07bc77c7e7 | |||
| 72973fe582 | |||
| c263b6af6f | |||
| e46576b4c3 |
@@ -84,7 +84,11 @@ function(SystemPackageViable JSON_NAME)
|
|||||||
parse_object(${object})
|
parse_object(${object})
|
||||||
|
|
||||||
string(REPLACE " " ";" find_args "${find_args}")
|
string(REPLACE " " ";" find_args "${find_args}")
|
||||||
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
if (${package}_FORCE_BUNDLED)
|
||||||
|
set(${package}_FOUND OFF)
|
||||||
|
else()
|
||||||
|
find_package(${package} ${version} ${find_args} QUIET NO_POLICY_SCOPE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
set(${pkg}_VIABLE ${${package}_FOUND} PARENT_SCOPE)
|
||||||
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
set(${pkg}_PACKAGE ${package} PARENT_SCOPE)
|
||||||
|
|||||||
Vendored
+1
-3
@@ -150,7 +150,7 @@
|
|||||||
"package": "SDL2",
|
"package": "SDL2",
|
||||||
"name": "SDL2",
|
"name": "SDL2",
|
||||||
"repo": "crueter-ci/SDL2",
|
"repo": "crueter-ci/SDL2",
|
||||||
"version": "2.32.10-a65111bd2d",
|
"version": "2.32.10-cf5dabd6ea",
|
||||||
"min_version": "2.26.4"
|
"min_version": "2.26.4"
|
||||||
},
|
},
|
||||||
"catch2": {
|
"catch2": {
|
||||||
@@ -184,7 +184,6 @@
|
|||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"tag": "release-%VERSION%",
|
"tag": "release-%VERSION%",
|
||||||
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
|
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
|
||||||
"key": "generic",
|
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"git_version": "2.32.10",
|
"git_version": "2.32.10",
|
||||||
"skip_updates": true
|
"skip_updates": true
|
||||||
@@ -194,7 +193,6 @@
|
|||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"sha": "cc016b0046",
|
"sha": "cc016b0046",
|
||||||
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
|
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
|
||||||
"key": "steamdeck",
|
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"skip_updates": "true"
|
"skip_updates": "true"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -507,7 +507,7 @@
|
|||||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout</string>
|
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno 700), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||||
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
|
||||||
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
|
||||||
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
|
||||||
|
|||||||
@@ -568,13 +568,7 @@ struct Values {
|
|||||||
Category::RendererHacks};
|
Category::RendererHacks};
|
||||||
|
|
||||||
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
|
||||||
#if defined (_WIN32)
|
#if defined (ANDROID) || defined (__APPLE__)
|
||||||
ExtendedDynamicState::EDS3,
|
|
||||||
#elif defined (__FreeBSD__)
|
|
||||||
ExtendedDynamicState::EDS3,
|
|
||||||
#elif defined (ANDROID)
|
|
||||||
ExtendedDynamicState::Disabled,
|
|
||||||
#elif defined (__APPLE__)
|
|
||||||
ExtendedDynamicState::Disabled,
|
ExtendedDynamicState::Disabled,
|
||||||
#else
|
#else
|
||||||
ExtendedDynamicState::EDS2,
|
ExtendedDynamicState::EDS2,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -38,10 +38,16 @@ u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
|
|||||||
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
|
||||||
return m_memory.Read64(vaddr);
|
return m_memory.Read64(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
|
||||||
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return m_memory.Read32(vaddr);
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <dynarmic/interface/A32/a32.h>
|
#include <dynarmic/interface/A32/a32.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
|
||||||
@@ -49,6 +50,9 @@ public:
|
|||||||
u64 GetTicksRemaining() override;
|
u64 GetTicksRemaining() override;
|
||||||
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
||||||
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
|
void ReturnException(u32 pc, Dynarmic::HaltReason hr);
|
||||||
|
//
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
ArmDynarmic32& m_parent;
|
ArmDynarmic32& m_parent;
|
||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
Kernel::KProcess* m_process{};
|
Kernel::KProcess* m_process{};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
@@ -41,10 +41,17 @@ Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
|
|||||||
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
|
||||||
return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
|
return {m_memory.Read64(vaddr), m_memory.Read64(vaddr + 8)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
|
||||||
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
if (!m_memory.IsValidVirtualAddressRange(vaddr, sizeof(u32)))
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
return m_memory.Read32(vaddr);
|
// return m_memory.Read32(vaddr);
|
||||||
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
m_memory.ReadBlock(aligned_vaddr, &cached_code_page, sizeof(cached_code_page));
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <ankerl/unordered_dense.h>
|
#include <ankerl/unordered_dense.h>
|
||||||
|
|
||||||
#include <dynarmic/interface/A64/a64.h>
|
#include <dynarmic/interface/A64/a64.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/hash.h"
|
#include "common/hash.h"
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
@@ -61,6 +62,8 @@ public:
|
|||||||
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
bool CheckMemoryAccess(u64 addr, u64 size, Kernel::DebugWatchpointType type);
|
||||||
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
|
void ReturnException(u64 pc, Dynarmic::HaltReason hr);
|
||||||
|
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
ArmDynarmic64& m_parent;
|
ArmDynarmic64& m_parent;
|
||||||
Core::Memory::Memory& m_memory;
|
Core::Memory::Memory& m_memory;
|
||||||
u64 m_tpidrro_el0{};
|
u64 m_tpidrro_el0{};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
#include <dynarmic/interface/A64/a64.h>
|
#include <dynarmic/interface/A64/a64.h>
|
||||||
#include <dynarmic/interface/A64/config.h>
|
#include <dynarmic/interface/A64/config.h>
|
||||||
|
#include <dynarmic/interface/code_page.h>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
@@ -46,6 +47,15 @@ public:
|
|||||||
: memory{memory_}, local_memory{local_memory_},
|
: memory{memory_}, local_memory{local_memory_},
|
||||||
mapped_ranges{mapped_ranges_}, parent{parent_} {}
|
mapped_ranges{mapped_ranges_}, parent{parent_} {}
|
||||||
|
|
||||||
|
std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override {
|
||||||
|
static_assert(Core::Memory::YUZU_PAGESIZE == Dynarmic::CODE_PAGE_SIZE);
|
||||||
|
auto const aligned_vaddr = vaddr & ~Core::Memory::YUZU_PAGEMASK;
|
||||||
|
if (last_code_addr != aligned_vaddr) {
|
||||||
|
cached_code_page = ReadMemory<Dynarmic::CodePage>(aligned_vaddr);
|
||||||
|
last_code_addr = aligned_vaddr;
|
||||||
|
}
|
||||||
|
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
|
||||||
|
}
|
||||||
u8 MemoryRead8(u64 vaddr) override {
|
u8 MemoryRead8(u64 vaddr) override {
|
||||||
return ReadMemory<u8>(vaddr);
|
return ReadMemory<u8>(vaddr);
|
||||||
}
|
}
|
||||||
@@ -116,8 +126,7 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template<typename T> T ReadMemory(u64 vaddr) {
|
||||||
T ReadMemory(u64 vaddr) {
|
|
||||||
T ret{};
|
T ret{};
|
||||||
if (boost::icl::contains(mapped_ranges, vaddr)) {
|
if (boost::icl::contains(mapped_ranges, vaddr)) {
|
||||||
memory.ReadBlock(vaddr, &ret, sizeof(T));
|
memory.ReadBlock(vaddr, &ret, sizeof(T));
|
||||||
@@ -146,6 +155,9 @@ private:
|
|||||||
std::vector<u8>& local_memory;
|
std::vector<u8>& local_memory;
|
||||||
IntervalSet& mapped_ranges;
|
IntervalSet& mapped_ranges;
|
||||||
JITContextImpl& parent;
|
JITContextImpl& parent;
|
||||||
|
|
||||||
|
Dynarmic::CodePage cached_code_page;
|
||||||
|
u64 last_code_addr = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JITContextImpl {
|
class JITContextImpl {
|
||||||
|
|||||||
+2
-3
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
|
||||||
@@ -36,8 +36,7 @@
|
|||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
|
|
||||||
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr,
|
static inline bool AddressSpaceContains(const Common::PageTable& table, const Common::ProcessAddress addr, const std::size_t size) {
|
||||||
const std::size_t size) {
|
|
||||||
const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
|
const Common::ProcessAddress max_addr = 1ULL << table.GetAddressSpaceBits();
|
||||||
return addr + size >= addr && addr + size <= max_addr;
|
return addr + size >= addr && addr + size <= max_addr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,9 +105,6 @@ add_library(dynarmic STATIC
|
|||||||
frontend/A32/decoder/thumb32.inc
|
frontend/A32/decoder/thumb32.inc
|
||||||
frontend/A32/decoder/vfp.h
|
frontend/A32/decoder/vfp.h
|
||||||
frontend/A32/decoder/vfp.inc
|
frontend/A32/decoder/vfp.inc
|
||||||
frontend/A32/disassembler/disassembler.h
|
|
||||||
frontend/A32/disassembler/disassembler_arm.cpp
|
|
||||||
frontend/A32/disassembler/disassembler_thumb.cpp
|
|
||||||
frontend/A32/FPSCR.h
|
frontend/A32/FPSCR.h
|
||||||
frontend/A32/ITState.h
|
frontend/A32/ITState.h
|
||||||
frontend/A32/PSR.h
|
frontend/A32/PSR.h
|
||||||
@@ -122,7 +119,6 @@ add_library(dynarmic STATIC
|
|||||||
interface/A32/config.h
|
interface/A32/config.h
|
||||||
interface/A32/coprocessor.h
|
interface/A32/coprocessor.h
|
||||||
interface/A32/coprocessor_util.h
|
interface/A32/coprocessor_util.h
|
||||||
interface/A32/disassembler.h
|
|
||||||
# A64
|
# A64
|
||||||
frontend/A64/a64_ir_emitter.cpp
|
frontend/A64/a64_ir_emitter.cpp
|
||||||
frontend/A64/a64_ir_emitter.h
|
frontend/A64/a64_ir_emitter.h
|
||||||
|
|||||||
@@ -65,11 +65,10 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
|
|||||||
|
|
||||||
struct Jit::Impl {
|
struct Jit::Impl {
|
||||||
Impl(Jit* jit, A32::UserConfig conf) noexcept
|
Impl(Jit* jit, A32::UserConfig conf) noexcept
|
||||||
: ir_block{LocationDescriptor(0, PSR(0), FPSCR(0), false)}
|
: block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
||||||
, conf(std::move(conf))
|
|
||||||
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
|
||||||
, emitter(block_of_code, conf, jit)
|
, emitter(block_of_code, conf, jit)
|
||||||
, polyfill_options(GenPolyfillOptions(block_of_code))
|
, polyfill_options(GenPolyfillOptions(block_of_code))
|
||||||
|
, conf(std::move(conf))
|
||||||
, jit_interface(jit)
|
, jit_interface(jit)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -204,8 +203,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
||||||
auto block = emitter.GetBasicBlock(descriptor);
|
if (auto block = emitter.GetBasicBlock(descriptor))
|
||||||
if (block)
|
|
||||||
return *block;
|
return *block;
|
||||||
|
|
||||||
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
||||||
@@ -215,8 +213,10 @@ private:
|
|||||||
}
|
}
|
||||||
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
|
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
|
||||||
|
|
||||||
ir_block.Reset(descriptor);
|
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
auto const arch_descriptor = A32::LocationDescriptor{descriptor};
|
||||||
|
ir_block.Reset(arch_descriptor);
|
||||||
|
A32::Translate(ir_block, arch_descriptor, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||||
Optimization::Optimize(ir_block, conf, polyfill_options);
|
Optimization::Optimize(ir_block, conf, polyfill_options);
|
||||||
return emitter.Emit(ir_block);
|
return emitter.Emit(ir_block);
|
||||||
}
|
}
|
||||||
@@ -243,12 +243,13 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block ir_block;
|
IR::Block ir_block = {LocationDescriptor(0, PSR(0), FPSCR(0), false)};
|
||||||
const A32::UserConfig conf;
|
|
||||||
A32JitState jit_state;
|
A32JitState jit_state;
|
||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
A32EmitX64 emitter;
|
A32EmitX64 emitter;
|
||||||
Optimization::PolyfillOptions polyfill_options;
|
Optimization::PolyfillOptions polyfill_options;
|
||||||
|
// Keep it here, you don't wanna mess with the fuckery that's initializer lists
|
||||||
|
const A32::UserConfig conf;
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
|
|
||||||
// Requests made during execution to invalidate the cache are queued up here.
|
// Requests made during execution to invalidate the cache are queued up here.
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ static Optimization::PolyfillOptions GenPolyfillOptions(const BlockOfCode& code)
|
|||||||
struct Jit::Impl final {
|
struct Jit::Impl final {
|
||||||
public:
|
public:
|
||||||
Impl(Jit* jit, UserConfig conf)
|
Impl(Jit* jit, UserConfig conf)
|
||||||
: ir_block{LocationDescriptor(0, FP::FPCR(0), false)}
|
: conf(conf)
|
||||||
, conf(conf)
|
|
||||||
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
, block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this, conf), JitStateInfo{jit_state}, conf.code_cache_size, GenRCP(conf))
|
||||||
, emitter(block_of_code, conf, jit)
|
, emitter(block_of_code, conf, jit)
|
||||||
, polyfill_options(GenPolyfillOptions(block_of_code))
|
, polyfill_options(GenPolyfillOptions(block_of_code))
|
||||||
@@ -257,8 +256,8 @@ private:
|
|||||||
return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true));
|
return GetBlock(A64::LocationDescriptor{GetCurrentLocation()}.SetSingleStepping(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
CodePtr GetBlock(IR::LocationDescriptor current_location) {
|
CodePtr GetBlock(IR::LocationDescriptor descriptor) {
|
||||||
if (auto block = emitter.GetBasicBlock(current_location))
|
if (auto block = emitter.GetBasicBlock(descriptor))
|
||||||
return block->entrypoint;
|
return block->entrypoint;
|
||||||
|
|
||||||
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
constexpr size_t MINIMUM_REMAINING_CODESIZE = 1 * 1024 * 1024;
|
||||||
@@ -271,8 +270,10 @@ private:
|
|||||||
|
|
||||||
// JIT Compile
|
// JIT Compile
|
||||||
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
||||||
ir_block.Reset(current_location);
|
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||||
A64::Translate(ir_block, A64::LocationDescriptor{current_location}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
auto const arch_descriptor = A64::LocationDescriptor{descriptor};
|
||||||
|
ir_block.Reset(arch_descriptor);
|
||||||
|
A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
||||||
Optimization::Optimize(ir_block, conf, polyfill_options);
|
Optimization::Optimize(ir_block, conf, polyfill_options);
|
||||||
return emitter.Emit(ir_block).entrypoint;
|
return emitter.Emit(ir_block).entrypoint;
|
||||||
}
|
}
|
||||||
@@ -299,7 +300,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block ir_block;
|
IR::Block ir_block = {LocationDescriptor(0, FP::FPCR(0), false)};
|
||||||
const UserConfig conf;
|
const UserConfig conf;
|
||||||
A64JitState jit_state;
|
A64JitState jit_state;
|
||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "dynarmic/common/common_types.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
std::string DisassembleArm(u32 instruction);
|
|
||||||
std::string DisassembleThumb16(u16 instruction);
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,397 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <fmt/ostream.h>
|
|
||||||
#include <mcl/bit/bit_field.hpp>
|
|
||||||
|
|
||||||
#include "dynarmic/common/string_util.h"
|
|
||||||
#include "dynarmic/frontend/A32/a32_types.h"
|
|
||||||
#include "dynarmic/frontend/A32/decoder/thumb16.h"
|
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
#include "dynarmic/frontend/imm.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A32 {
|
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
|
||||||
public:
|
|
||||||
using instruction_return_type = std::string;
|
|
||||||
|
|
||||||
std::string thumb16_LSL_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
return fmt::format("lsls {}, {}, #{}", d, m, imm5.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
|
||||||
return fmt::format("lsrs {}, {}, #{}", d, m, shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ASR_imm(Imm<5> imm5, Reg m, Reg d) {
|
|
||||||
const u32 shift = imm5 != 0 ? imm5.ZeroExtend() : 32U;
|
|
||||||
return fmt::format("asrs {}, {}, #{}", d, m, shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_reg_t1(Reg m, Reg n, Reg d) {
|
|
||||||
return fmt::format("adds {}, {}, {}", d, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_reg(Reg m, Reg n, Reg d) {
|
|
||||||
return fmt::format("subs {}, {}, {}", d, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
|
||||||
return fmt::format("adds {}, {}, #{}", d, n, imm3.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_imm_t1(Imm<3> imm3, Reg n, Reg d) {
|
|
||||||
return fmt::format("subs {}, {}, #{}", d, n, imm3.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MOV_imm(Reg d, Imm<8> imm8) {
|
|
||||||
return fmt::format("movs {}, #{}", d, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_imm(Reg n, Imm<8> imm8) {
|
|
||||||
return fmt::format("cmp {}, #{}", n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_imm_t2(Reg d_n, Imm<8> imm8) {
|
|
||||||
return fmt::format("adds {}, #{}", d_n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_imm_t2(Reg d_n, Imm<8> imm8) {
|
|
||||||
return fmt::format("subs {}, #{}", d_n, imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_AND_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("ands {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_EOR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("eors {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSL_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("lsls {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LSR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("lsrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ASR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("asrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("adcs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SBC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("sbcs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ROR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("rors {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_TST_reg(Reg m, Reg n) {
|
|
||||||
return fmt::format("tst {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_RSB_imm(Reg n, Reg d) {
|
|
||||||
// Pre-UAL syntax: NEGS <Rd>, <Rn>
|
|
||||||
return fmt::format("rsbs {}, {}, #0", d, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_reg_t1(Reg m, Reg n) {
|
|
||||||
return fmt::format("cmp {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMN_reg(Reg m, Reg n) {
|
|
||||||
return fmt::format("cmn {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ORR_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("orrs {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MUL_reg(Reg n, Reg d_m) {
|
|
||||||
return fmt::format("muls {}, {}, {}", d_m, n, d_m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BIC_reg(Reg m, Reg d_n) {
|
|
||||||
return fmt::format("bics {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MVN_reg(Reg m, Reg d) {
|
|
||||||
return fmt::format("mvns {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_reg_t2(bool d_n_hi, Reg m, Reg d_n_lo) {
|
|
||||||
const Reg d_n = d_n_hi ? (d_n_lo + 8) : d_n_lo;
|
|
||||||
return fmt::format("add {}, {}", d_n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) {
|
|
||||||
const Reg n = n_hi ? (n_lo + 8) : n_lo;
|
|
||||||
return fmt::format("cmp {}, {}", n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_MOV_reg(bool d_hi, Reg m, Reg d_lo) {
|
|
||||||
const Reg d = d_hi ? (d_lo + 8) : d_lo;
|
|
||||||
return fmt::format("mov {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_literal(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [pc, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("str {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("strh {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("strb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRSB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrsb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldr {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrh {}, [%s, %s]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRB_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrb {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRSH_reg(Reg m, Reg n, Reg t) {
|
|
||||||
return fmt::format("ldrsh {}, [{}, {}]", t, n, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
|
||||||
return fmt::format("str {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_imm_t1(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend();
|
|
||||||
return fmt::format("strb {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRB_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend();
|
|
||||||
return fmt::format("ldrb {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
|
||||||
return fmt::format("strh {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDRH_imm(Imm<5> imm5, Reg n, Reg t) {
|
|
||||||
const u32 imm32 = imm5.ZeroExtend() << 1;
|
|
||||||
return fmt::format("ldrh {}, [{}, #{}]", t, n, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STR_imm_t2(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("str {}, [sp, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDR_imm_t2(Reg t, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("ldr {}, [sp, #{}]", t, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADR(Reg d, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("adr {}, +#{}", d, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_sp_t1(Reg d, Imm<8> imm8) {
|
|
||||||
const u32 imm32 = imm8.ZeroExtend() << 2;
|
|
||||||
return fmt::format("add {}, sp, #{}", d, imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_ADD_sp_t2(Imm<7> imm7) {
|
|
||||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
|
||||||
return fmt::format("add sp, sp, #{}", imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SUB_sp(Imm<7> imm7) {
|
|
||||||
const u32 imm32 = imm7.ZeroExtend() << 2;
|
|
||||||
return fmt::format("sub sp, sp, #{}", imm32);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_NOP() {
|
|
||||||
return "nop";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SEV() {
|
|
||||||
return "sev";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SEVL() {
|
|
||||||
return "sevl";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_WFE() {
|
|
||||||
return "wfe";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_WFI() {
|
|
||||||
return "wfi";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_YIELD() {
|
|
||||||
return "yield";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_IT(Imm<8> imm8) {
|
|
||||||
const Cond firstcond = imm8.Bits<4, 7, Cond>();
|
|
||||||
const bool firstcond0 = imm8.Bit<4>();
|
|
||||||
const auto [x, y, z] = [&] {
|
|
||||||
if (imm8.Bits<0, 3>() == 0b1000) {
|
|
||||||
return std::make_tuple("", "", "");
|
|
||||||
}
|
|
||||||
if (imm8.Bits<0, 2>() == 0b100) {
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", "", "");
|
|
||||||
}
|
|
||||||
if (imm8.Bits<0, 1>() == 0b10) {
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", "");
|
|
||||||
}
|
|
||||||
// Sanity note: Here imm8.Bit<0>() is guaranteed to be == 1. (imm8 can never be 0bxxxx0000)
|
|
||||||
return std::make_tuple(imm8.Bit<3>() == firstcond0 ? "t" : "e", imm8.Bit<2>() == firstcond0 ? "t" : "e", imm8.Bit<1>() == firstcond0 ? "t" : "e");
|
|
||||||
}();
|
|
||||||
return fmt::format("it{}{}{} {}", x, y, z, CondToString(firstcond));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SXTH(Reg m, Reg d) {
|
|
||||||
return fmt::format("sxth {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SXTB(Reg m, Reg d) {
|
|
||||||
return fmt::format("sxtb {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UXTH(Reg m, Reg d) {
|
|
||||||
return fmt::format("uxth {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UXTB(Reg m, Reg d) {
|
|
||||||
return fmt::format("uxtb {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_PUSH(bool M, RegList reg_list) {
|
|
||||||
if (M)
|
|
||||||
reg_list |= 1 << 14;
|
|
||||||
return fmt::format("push {{{}}}", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_POP(bool P, RegList reg_list) {
|
|
||||||
if (P)
|
|
||||||
reg_list |= 1 << 15;
|
|
||||||
return fmt::format("pop {{{}}}", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SETEND(bool E) {
|
|
||||||
return fmt::format("setend {}", E ? "BE" : "LE");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CPS(bool im, bool a, bool i, bool f) {
|
|
||||||
return fmt::format("cps{} {}{}{}", im ? "id" : "ie", a ? "a" : "", i ? "i" : "", f ? "f" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REV(Reg m, Reg d) {
|
|
||||||
return fmt::format("rev {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REV16(Reg m, Reg d) {
|
|
||||||
return fmt::format("rev16 {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_REVSH(Reg m, Reg d) {
|
|
||||||
return fmt::format("revsh {}, {}", d, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BKPT(Imm<8> imm8) {
|
|
||||||
return fmt::format("bkpt #{}", imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_STMIA(Reg n, RegList reg_list) {
|
|
||||||
return fmt::format("stm {}!, {{{}}}", n, RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_LDMIA(Reg n, RegList reg_list) {
|
|
||||||
const bool write_back = !mcl::bit::get_bit(static_cast<size_t>(n), reg_list);
|
|
||||||
return fmt::format("ldm {}{}, {{{}}}", n, write_back ? "!" : "", RegListToString(reg_list));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BX(Reg m) {
|
|
||||||
return fmt::format("bx {}", m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_BLX_reg(Reg m) {
|
|
||||||
return fmt::format("blx {}", m);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_CBZ_CBNZ(bool nonzero, Imm<1> i, Imm<5> imm5, Reg n) {
|
|
||||||
const char* const name = nonzero ? "cbnz" : "cbz";
|
|
||||||
const u32 imm = concatenate(i, imm5, Imm<1>{0}).ZeroExtend();
|
|
||||||
|
|
||||||
return fmt::format("{} {}, #{}", name, n, imm);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_UDF() {
|
|
||||||
return fmt::format("udf");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_SVC(Imm<8> imm8) {
|
|
||||||
return fmt::format("svc #{}", imm8.ZeroExtend());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_B_t1(Cond cond, Imm<8> imm8) {
|
|
||||||
const s32 imm32 = static_cast<s32>((imm8.SignExtend<u32>() << 1) + 4);
|
|
||||||
return fmt::format("b{} {}#{}",
|
|
||||||
CondToString(cond),
|
|
||||||
Common::SignToChar(imm32),
|
|
||||||
abs(imm32));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string thumb16_B_t2(Imm<11> imm11) {
|
|
||||||
const s32 imm32 = static_cast<s32>((imm11.SignExtend<u32>() << 1) + 4);
|
|
||||||
return fmt::format("b {}#{}",
|
|
||||||
Common::SignToChar(imm32),
|
|
||||||
abs(imm32));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string DisassembleThumb16(u16 instruction) {
|
|
||||||
DisassemblerVisitor visitor;
|
|
||||||
auto decoder = DecodeThumb16<DisassemblerVisitor>(instruction);
|
|
||||||
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->get().call(visitor, instruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Dynarmic::A32
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
namespace A32 {
|
|
||||||
|
|
||||||
std::string DisassembleArm(std::uint32_t instruction);
|
|
||||||
std::string DisassembleThumb16(std::uint16_t instruction);
|
|
||||||
|
|
||||||
} // namespace A32
|
|
||||||
} // namespace Dynarmic
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
|
||||||
|
/// @brief Smallest valid page (may change for Apple?)
|
||||||
|
constexpr inline uint64_t CODE_PAGE_SIZE = 4096;
|
||||||
|
struct CodePage {
|
||||||
|
uint32_t inst[CODE_PAGE_SIZE / sizeof(uint32_t)];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -22,13 +22,10 @@
|
|||||||
|
|
||||||
namespace Dynarmic::IR {
|
namespace Dynarmic::IR {
|
||||||
|
|
||||||
Block::Block(const LocationDescriptor& location)
|
Block::Block(LocationDescriptor location) noexcept
|
||||||
: location{location},
|
: location{location}
|
||||||
end_location{location},
|
, end_location{location}
|
||||||
cond{Cond::AL}
|
{}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Prepends a new instruction to this basic block before the insertion point,
|
/// Prepends a new instruction to this basic block before the insertion point,
|
||||||
/// handling any allocations necessary to do so.
|
/// handling any allocations necessary to do so.
|
||||||
@@ -60,6 +57,21 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, s
|
|||||||
return instructions.insert_before(insertion_point, inst);
|
return instructions.insert_before(insertion_point, inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Block::Reset(LocationDescriptor location_) noexcept {
|
||||||
|
mcl::intrusive_list<IR::Inst> tmp = {};
|
||||||
|
instructions.swap(tmp);
|
||||||
|
inlined_inst.clear();
|
||||||
|
pooled_inst.clear();
|
||||||
|
cond_failed.reset();
|
||||||
|
location = location_;
|
||||||
|
end_location = location_;
|
||||||
|
cond = Cond::AL;
|
||||||
|
terminal = Term::Invalid{};
|
||||||
|
cond_failed_cycle_count = 0;
|
||||||
|
cycle_count = 0;
|
||||||
|
ASSERT(instructions.size() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
||||||
struct : boost::static_visitor<std::string> {
|
struct : boost::static_visitor<std::string> {
|
||||||
std::string operator()(const Term::Invalid&) const {
|
std::string operator()(const Term::Invalid&) const {
|
||||||
@@ -123,11 +135,11 @@ std::string DumpBlock(const IR::Block& block) noexcept {
|
|||||||
case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef());
|
case Type::A32ExtReg: return A32::ExtRegToString(arg.GetA32ExtRegRef());
|
||||||
case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef());
|
case Type::A64Reg: return A64::RegToString(arg.GetA64RegRef());
|
||||||
case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef());
|
case Type::A64Vec: return A64::VecToString(arg.GetA64VecRef());
|
||||||
case Type::CoprocInfo: return fmt::format("#<coproc>");
|
case Type::CoprocInfo: return fmt::format("$coproc{}", arg.GetCoprocInfo()[0]);
|
||||||
case Type::NZCVFlags: return fmt::format("#<NZCV flags>");
|
case Type::NZCVFlags: return fmt::format("$nzcv");
|
||||||
case Type::Cond: return fmt::format("#<cond={}>", A32::CondToString(arg.GetCond()));
|
case Type::Cond: return fmt::format("$cond={}", A32::CondToString(arg.GetCond()));
|
||||||
case Type::Table: return fmt::format("#<table>");
|
case Type::Table: return fmt::format("$table");
|
||||||
case Type::AccType: return fmt::format("#<acc-type={}>", u32(arg.GetAccType()));
|
case Type::AccType: return fmt::format("$acc-type={}", u32(arg.GetAccType()));
|
||||||
default: return fmt::format("<unknown immediate type {}>", arg.GetType());
|
default: return fmt::format("<unknown immediate type {}>", arg.GetType());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public:
|
|||||||
using reverse_iterator = instruction_list_type::reverse_iterator;
|
using reverse_iterator = instruction_list_type::reverse_iterator;
|
||||||
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
using const_reverse_iterator = instruction_list_type::const_reverse_iterator;
|
||||||
|
|
||||||
explicit Block(const LocationDescriptor& location);
|
Block(LocationDescriptor location) noexcept;
|
||||||
~Block() = default;
|
~Block() = default;
|
||||||
Block(const Block&) = delete;
|
Block(const Block&) = delete;
|
||||||
Block& operator=(const Block&) = delete;
|
Block& operator=(const Block&) = delete;
|
||||||
@@ -58,6 +58,7 @@ public:
|
|||||||
return PrependNewInst(instructions.end(), opcode, args);
|
return PrependNewInst(instructions.end(), opcode, args);
|
||||||
}
|
}
|
||||||
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
iterator PrependNewInst(iterator insertion_point, Opcode op, std::initializer_list<Value> args) noexcept;
|
||||||
|
void Reset(LocationDescriptor location_) noexcept;
|
||||||
|
|
||||||
/// Gets a mutable reference to the instruction list for this basic block.
|
/// Gets a mutable reference to the instruction list for this basic block.
|
||||||
inline instruction_list_type& Instructions() noexcept {
|
inline instruction_list_type& Instructions() noexcept {
|
||||||
@@ -140,18 +141,6 @@ public:
|
|||||||
return cycle_count;
|
return cycle_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Reset(LocationDescriptor location_) noexcept {
|
|
||||||
inlined_inst.clear();
|
|
||||||
pooled_inst.clear();
|
|
||||||
cond_failed.reset();
|
|
||||||
location = location_;
|
|
||||||
terminal = Term::Invalid{};
|
|
||||||
cond_failed_cycle_count = 0;
|
|
||||||
cycle_count = 0;
|
|
||||||
instruction_list_type tmp{};
|
|
||||||
instructions.swap(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// "Hot cache" for small blocks so we don't call global allocator
|
/// "Hot cache" for small blocks so we don't call global allocator
|
||||||
boost::container::static_vector<Inst, 30> inlined_inst;
|
boost::container::static_vector<Inst, 30> inlined_inst;
|
||||||
/// List of instructions in this block.
|
/// List of instructions in this block.
|
||||||
@@ -165,7 +154,7 @@ public:
|
|||||||
/// Description of the end location of this block
|
/// Description of the end location of this block
|
||||||
LocationDescriptor end_location;
|
LocationDescriptor end_location;
|
||||||
/// Conditional to pass in order to execute this block
|
/// Conditional to pass in order to execute this block
|
||||||
Cond cond;
|
Cond cond = Cond::AL;
|
||||||
/// Terminal instruction of this block.
|
/// Terminal instruction of this block.
|
||||||
Terminal terminal = Term::Invalid{};
|
Terminal terminal = Term::Invalid{};
|
||||||
/// Number of cycles this block takes to execute if the conditional fails.
|
/// Number of cycles this block takes to execute if the conditional fails.
|
||||||
|
|||||||
@@ -1042,6 +1042,11 @@ static void FoldZeroExtendXToLong(IR::Inst& inst) {
|
|||||||
static void ConstantPropagation(IR::Block& block) {
|
static void ConstantPropagation(IR::Block& block) {
|
||||||
for (auto& inst : block.instructions) {
|
for (auto& inst : block.instructions) {
|
||||||
auto const opcode = inst.GetOpcode();
|
auto const opcode = inst.GetOpcode();
|
||||||
|
// skip NZCV so we dont end up discarding side effects :)
|
||||||
|
// TODO(lizzie): hey stupid maybe fix the A64 codegen for folded constants AND
|
||||||
|
// redirect the mfer properly?!??! just saying :)
|
||||||
|
if (IR::MayGetNZCVFromOp(opcode) && inst.GetAssociatedPseudoOperation(IR::Opcode::GetNZCVFromOp))
|
||||||
|
continue;
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case Op::LeastSignificantWord:
|
case Op::LeastSignificantWord:
|
||||||
FoldLeastSignificantWord(inst);
|
FoldLeastSignificantWord(inst);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "dynarmic/frontend/A32/FPSCR.h"
|
#include "dynarmic/frontend/A32/FPSCR.h"
|
||||||
#include "dynarmic/frontend/A32/PSR.h"
|
#include "dynarmic/frontend/A32/PSR.h"
|
||||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* SPDX-License-Identifier: 0BSD
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <catch2/catch_test_macros.hpp>
|
|
||||||
|
|
||||||
#include "dynarmic/frontend/A32/disassembler/disassembler.h"
|
|
||||||
|
|
||||||
using Dynarmic::A32::DisassembleArm;
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
|
||||||
REQUIRE(DisassembleArm(0xEB000008) == "bl +#40");
|
|
||||||
REQUIRE(DisassembleArm(0xFBFFFFFE) == "blx +#2");
|
|
||||||
REQUIRE(DisassembleArm(0xFAFFFFFF) == "blx +#4");
|
|
||||||
REQUIRE(DisassembleArm(0xFBE1E7FE) == "blx -#7888894");
|
|
||||||
REQUIRE(DisassembleArm(0xE12FFF3D) == "blx sp");
|
|
||||||
REQUIRE(DisassembleArm(0x312FFF13) == "bxcc r3");
|
|
||||||
REQUIRE(DisassembleArm(0x012FFF29) == "bxjeq r9");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble data processing instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE2A21004) == "adc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21143) == "adc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21103) == "adc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21123) == "adc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21163) == "adc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21003) == "adc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21063) == "adc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21453) == "adc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21413) == "adc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21433) == "adc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21473) == "adc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2B21004) == "adcs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21143) == "adcs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21103) == "adcs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21123) == "adcs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21163) == "adcs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21003) == "adcs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21063) == "adcs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21453) == "adcs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21413) == "adcs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21433) == "adcs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21473) == "adcs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2853004) == "add r3, r5, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821143) == "add r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821103) == "add r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821123) == "add r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821163) == "add r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821003) == "add r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821453) == "add r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821413) == "add r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821433) == "add r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821473) == "add r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0821063) == "add r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2953004) == "adds r3, r5, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921143) == "adds r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921103) == "adds r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921123) == "adds r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921163) == "adds r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921003) == "adds r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921063) == "adds r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921453) == "adds r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921413) == "adds r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921433) == "adds r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921473) == "adds r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2021004) == "and r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021143) == "and r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021103) == "and r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021123) == "and r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021163) == "and r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021003) == "and r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021453) == "and r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021413) == "and r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021433) == "and r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021473) == "and r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0021063) == "and r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2121004) == "ands r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121143) == "ands r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121103) == "ands r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121123) == "ands r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121163) == "ands r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121003) == "ands r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121063) == "ands r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121453) == "ands r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121413) == "ands r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121433) == "ands r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0121473) == "ands r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3C21004) == "bic r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21143) == "bic r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21103) == "bic r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21123) == "bic r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21163) == "bic r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21003) == "bic r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21453) == "bic r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21413) == "bic r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21433) == "bic r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21473) == "bic r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C21063) == "bic r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE3D21004) == "bics r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21143) == "bics r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21103) == "bics r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21123) == "bics r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21163) == "bics r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21003) == "bics r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21063) == "bics r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21453) == "bics r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21413) == "bics r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21433) == "bics r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21473) == "bics r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3710004) == "cmn r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710142) == "cmn r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710102) == "cmn r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710122) == "cmn r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710162) == "cmn r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710002) == "cmn r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710062) == "cmn r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710352) == "cmn r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710312) == "cmn r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710332) == "cmn r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1710372) == "cmn r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3510004) == "cmp r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510142) == "cmp r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510102) == "cmp r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510122) == "cmp r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510162) == "cmp r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510002) == "cmp r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510062) == "cmp r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510352) == "cmp r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510312) == "cmp r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510332) == "cmp r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1510372) == "cmp r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2221004) == "eor r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221243) == "eor r1, r2, r3, asr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221203) == "eor r1, r2, r3, lsl #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221223) == "eor r1, r2, r3, lsr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221263) == "eor r1, r2, r3, ror #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221003) == "eor r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221453) == "eor r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221413) == "eor r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221433) == "eor r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221473) == "eor r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0221063) == "eor r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE2321004) == "eors r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321243) == "eors r1, r2, r3, asr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321203) == "eors r1, r2, r3, lsl #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321223) == "eors r1, r2, r3, lsr #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321263) == "eors r1, r2, r3, ror #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321003) == "eors r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321453) == "eors r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321413) == "eors r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321433) == "eors r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321473) == "eors r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0321063) == "eors r1, r2, r3, rrx");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3A010FF) == "mov r1, #255");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01142) == "mov r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01102) == "mov r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01122) == "mov r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01162) == "mov r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A01062) == "mov r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A0E00F) == "mov lr, pc");
|
|
||||||
REQUIRE(DisassembleArm(0xE3B010FF) == "movs r1, #255");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B0E00F) == "movs lr, pc");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01142) == "movs r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01102) == "movs r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01122) == "movs r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B01162) == "movs r1, r2, ror #2");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3E01004) == "mvn r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01142) == "mvn r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01102) == "mvn r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01122) == "mvn r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01162) == "mvn r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01062) == "mvn r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01002) == "mvn r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01352) == "mvn r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01312) == "mvn r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01332) == "mvn r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E01372) == "mvn r1, r2, ror r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE3F01004) == "mvns r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01142) == "mvns r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01102) == "mvns r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01122) == "mvns r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01162) == "mvns r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01062) == "mvns r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01002) == "mvns r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01352) == "mvns r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01312) == "mvns r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01332) == "mvns r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F01372) == "mvns r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3821004) == "orr r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821143) == "orr r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821103) == "orr r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821123) == "orr r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821163) == "orr r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821063) == "orr r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821003) == "orr r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821453) == "orr r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821413) == "orr r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821433) == "orr r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1821473) == "orr r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE3921004) == "orrs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921143) == "orrs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921103) == "orrs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921123) == "orrs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921163) == "orrs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921063) == "orrs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921003) == "orrs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921453) == "orrs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921413) == "orrs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921433) == "orrs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1921473) == "orrs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2621004) == "rsb r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621143) == "rsb r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621103) == "rsb r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621123) == "rsb r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621163) == "rsb r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621063) == "rsb r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621003) == "rsb r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621453) == "rsb r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621413) == "rsb r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621433) == "rsb r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0621473) == "rsb r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2721004) == "rsbs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721143) == "rsbs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721103) == "rsbs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721123) == "rsbs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721163) == "rsbs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721063) == "rsbs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721003) == "rsbs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721453) == "rsbs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721413) == "rsbs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721433) == "rsbs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0721473) == "rsbs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2E21004) == "rsc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21143) == "rsc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21103) == "rsc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21123) == "rsc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21163) == "rsc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21063) == "rsc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21003) == "rsc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21453) == "rsc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21413) == "rsc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21433) == "rsc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21473) == "rsc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2F21004) == "rscs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21143) == "rscs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21103) == "rscs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21123) == "rscs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21163) == "rscs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21063) == "rscs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21003) == "rscs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21453) == "rscs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21413) == "rscs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21433) == "rscs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21473) == "rscs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE2C21004) == "sbc r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21143) == "sbc r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21103) == "sbc r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21123) == "sbc r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21163) == "sbc r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21063) == "sbc r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21003) == "sbc r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21453) == "sbc r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21413) == "sbc r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21433) == "sbc r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21473) == "sbc r1, r2, r3, ror r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE2D21004) == "sbcs r1, r2, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21143) == "sbcs r1, r2, r3, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21103) == "sbcs r1, r2, r3, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21123) == "sbcs r1, r2, r3, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21163) == "sbcs r1, r2, r3, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21063) == "sbcs r1, r2, r3, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21003) == "sbcs r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21453) == "sbcs r1, r2, r3, asr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21413) == "sbcs r1, r2, r3, lsl r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21433) == "sbcs r1, r2, r3, lsr r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21473) == "sbcs r1, r2, r3, ror r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3310004) == "teq r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310142) == "teq r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310102) == "teq r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310122) == "teq r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310162) == "teq r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310002) == "teq r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310062) == "teq r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310352) == "teq r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310312) == "teq r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310332) == "teq r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1310372) == "teq r1, r2, ror r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE3110004) == "tst r1, #4");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110142) == "tst r1, r2, asr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110102) == "tst r1, r2, lsl #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110122) == "tst r1, r2, lsr #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110162) == "tst r1, r2, ror #2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110002) == "tst r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110062) == "tst r1, r2, rrx");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110352) == "tst r1, r2, asr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110312) == "tst r1, r2, lsl r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110332) == "tst r1, r2, lsr r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE1110372) == "tst r1, r2, ror r3");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble half-word multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE1003281) == "smlabb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032C1) == "smlabt r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032A1) == "smlatb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE10032E1) == "smlatt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1203281) == "smlawb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE12032C1) == "smlawt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE12002A1) == "smulwb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE12002E1) == "smulwt r0, r1, r2");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1410382) == "smlalbb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103C2) == "smlalbt r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103A2) == "smlaltb r0, r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE14103E2) == "smlaltt r0, r1, r2, r3");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1600281) == "smulbb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002C1) == "smulbt r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002A1) == "smultb r0, r1, r2");
|
|
||||||
REQUIRE(DisassembleArm(0xE16002E1) == "smultt r0, r1, r2");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble multiply and multiply accumulate instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE0214392) == "mla r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0314392) == "mlas r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0010392) == "mul r1, r2, r3");
|
|
||||||
REQUIRE(DisassembleArm(0xE0110392) == "muls r1, r2, r3");
|
|
||||||
|
|
||||||
// TODO: MLS should be here whenever it's supported.
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0E21493) == "smlal r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0F21493) == "smlals r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0C21493) == "smull r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0D21493) == "smulls r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0421493) == "umaal r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0A21493) == "umlal r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0B21493) == "umlals r1, r2, r3, r4");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE0821493) == "umull r1, r2, r3, r4");
|
|
||||||
REQUIRE(DisassembleArm(0xE0921493) == "umulls r1, r2, r3, r4");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble synchronization primitive instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE1921F9F) == "ldrex r1, [r2]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1D21F9F) == "ldrexb r1, [r2]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1B31F9F) == "ldrexd r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1F21F9F) == "ldrexh r1, [r2]");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1831F92) == "strex r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1C31F92) == "strexb r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1A41F92) == "strexd r1, r2, r3, [r4]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1E31F92) == "strexh r1, r2, [r3]");
|
|
||||||
|
|
||||||
REQUIRE(DisassembleArm(0xE1031092) == "swp r1, r2, [r3]");
|
|
||||||
REQUIRE(DisassembleArm(0xE1431092) == "swpb r1, r2, [r3]");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Disassemble load / store multiple instructions", "[arm][disassembler]") {
|
|
||||||
REQUIRE(DisassembleArm(0xE92D500F) == "stmdb sp!, {r0, r1, r2, r3, r12, lr}");
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
include(TargetArchitectureSpecificSources)
|
include(TargetArchitectureSpecificSources)
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@ add_executable(dynarmic_tests
|
|||||||
fp/unpacked_tests.cpp
|
fp/unpacked_tests.cpp
|
||||||
rand_int.h
|
rand_int.h
|
||||||
# A32
|
# A32
|
||||||
A32/test_arm_disassembler.cpp
|
|
||||||
A32/test_arm_instructions.cpp
|
A32/test_arm_instructions.cpp
|
||||||
A32/test_coprocessor.cpp
|
A32/test_coprocessor.cpp
|
||||||
A32/test_svc.cpp
|
A32/test_svc.cpp
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
/* This file is part of the dynarmic project.
|
/* This file is part of the dynarmic project.
|
||||||
@@ -34,7 +34,6 @@
|
|||||||
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
||||||
#include "dynarmic/interface/A32/a32.h"
|
#include "dynarmic/interface/A32/a32.h"
|
||||||
#include "dynarmic/interface/A32/config.h"
|
#include "dynarmic/interface/A32/config.h"
|
||||||
#include "dynarmic/interface/A32/disassembler.h"
|
|
||||||
#include "dynarmic/ir/basic_block.h"
|
#include "dynarmic/ir/basic_block.h"
|
||||||
#include "dynarmic/ir/opt_passes.h"
|
#include "dynarmic/ir/opt_passes.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines
|
// Prefer small grow rates to avoid saturating the descriptor pool with barely used pipelines
|
||||||
constexpr size_t SETS_GROW_RATE = 32; //test difference between 16 and 32
|
constexpr size_t SETS_GROW_RATE = 16;
|
||||||
constexpr s32 SCORE_THRESHOLD = 3;
|
constexpr s32 SCORE_THRESHOLD = 3;
|
||||||
|
|
||||||
struct DescriptorBank {
|
struct DescriptorBank {
|
||||||
@@ -29,12 +29,9 @@ struct DescriptorBank {
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept {
|
bool DescriptorBankInfo::IsSuperset(const DescriptorBankInfo& subset) const noexcept {
|
||||||
return uniform_buffers >= subset.uniform_buffers &&
|
return uniform_buffers >= subset.uniform_buffers && storage_buffers >= subset.storage_buffers &&
|
||||||
storage_buffers >= subset.storage_buffers &&
|
texture_buffers >= subset.texture_buffers && image_buffers >= subset.image_buffers &&
|
||||||
texture_buffers >= subset.texture_buffers &&
|
textures >= subset.textures && images >= subset.images;
|
||||||
image_buffers >= subset.image_buffers &&
|
|
||||||
textures >= subset.textures &&
|
|
||||||
images >= subset.images;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Descriptors>
|
template <typename Descriptors>
|
||||||
@@ -48,19 +45,6 @@ static u32 Accumulate(const Descriptors& descriptors) {
|
|||||||
|
|
||||||
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
|
static DescriptorBankInfo MakeBankInfo(std::span<const Shader::Info> infos) {
|
||||||
DescriptorBankInfo bank;
|
DescriptorBankInfo bank;
|
||||||
if (infos.size() == 1) {
|
|
||||||
const auto& info = infos.front();
|
|
||||||
const auto acc = [](const auto& ds){ u32 c=0; for (const auto& d: ds) c+=d.count; return c; };
|
|
||||||
bank.uniform_buffers += acc(info.constant_buffer_descriptors);
|
|
||||||
bank.storage_buffers += acc(info.storage_buffers_descriptors);
|
|
||||||
bank.texture_buffers += acc(info.texture_buffer_descriptors);
|
|
||||||
bank.image_buffers += acc(info.image_buffer_descriptors);
|
|
||||||
bank.textures += acc(info.texture_descriptors);
|
|
||||||
bank.images += acc(info.image_descriptors);
|
|
||||||
bank.score = bank.uniform_buffers + bank.storage_buffers + bank.texture_buffers +
|
|
||||||
bank.image_buffers + bank.textures + bank.images;
|
|
||||||
return bank;
|
|
||||||
}
|
|
||||||
for (const Shader::Info& info : infos) {
|
for (const Shader::Info& info : infos) {
|
||||||
bank.uniform_buffers += Accumulate(info.constant_buffer_descriptors);
|
bank.uniform_buffers += Accumulate(info.constant_buffer_descriptors);
|
||||||
bank.storage_buffers += Accumulate(info.storage_buffers_descriptors);
|
bank.storage_buffers += Accumulate(info.storage_buffers_descriptors);
|
||||||
@@ -118,22 +102,13 @@ void DescriptorAllocator::Allocate(size_t begin, size_t end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
|
vk::DescriptorSets DescriptorAllocator::AllocateDescriptors(size_t count) {
|
||||||
std::array<VkDescriptorSetLayout, 64> stack{};
|
const std::vector<VkDescriptorSetLayout> layouts(count, layout);
|
||||||
const VkDescriptorSetLayout* p_layouts = nullptr;
|
|
||||||
std::vector<VkDescriptorSetLayout> heap;
|
|
||||||
if (count <= stack.size()) {
|
|
||||||
stack.fill(layout);
|
|
||||||
p_layouts = stack.data();
|
|
||||||
} else {
|
|
||||||
heap.assign(count, layout);
|
|
||||||
p_layouts = heap.data();
|
|
||||||
}
|
|
||||||
VkDescriptorSetAllocateInfo allocate_info{
|
VkDescriptorSetAllocateInfo allocate_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.descriptorPool = *bank->pools.back(),
|
.descriptorPool = *bank->pools.back(),
|
||||||
.descriptorSetCount = static_cast<u32>(count),
|
.descriptorSetCount = static_cast<u32>(count),
|
||||||
.pSetLayouts = p_layouts,
|
.pSetLayouts = layouts.data(),
|
||||||
};
|
};
|
||||||
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
|
vk::DescriptorSets new_sets = bank->pools.back().Allocate(allocate_info);
|
||||||
if (!new_sets.IsOutOfPoolMemory()) {
|
if (!new_sets.IsOutOfPoolMemory()) {
|
||||||
@@ -171,58 +146,21 @@ DescriptorAllocator DescriptorPool::Allocator(VkDescriptorSetLayout layout,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
|
DescriptorBank& DescriptorPool::Bank(const DescriptorBankInfo& reqs) {
|
||||||
{
|
|
||||||
std::scoped_lock lk(cache_mutex);
|
|
||||||
DescriptorBank* best = nullptr; u64 best_stamp = 0;
|
|
||||||
for (const auto& e : cache_) {
|
|
||||||
if (!e.bank) continue;
|
|
||||||
if (std::abs(e.info.score - reqs.score) < SCORE_THRESHOLD && e.info.IsSuperset(reqs)) {
|
|
||||||
if (e.stamp >= best_stamp) { best_stamp = e.stamp; best = e.bank; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (best) return *best;
|
|
||||||
}
|
|
||||||
std::shared_lock read_lock{banks_mutex};
|
std::shared_lock read_lock{banks_mutex};
|
||||||
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
const auto it = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
||||||
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
||||||
});
|
});
|
||||||
if (it != bank_infos.end()) {
|
if (it != bank_infos.end()) {
|
||||||
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it)].get();
|
return *banks[std::distance(bank_infos.begin(), it)].get();
|
||||||
read_lock.unlock();
|
|
||||||
// update cache
|
|
||||||
std::scoped_lock lk(cache_mutex);
|
|
||||||
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
||||||
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
||||||
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
read_lock.unlock();
|
read_lock.unlock();
|
||||||
|
|
||||||
std::unique_lock write_lock{banks_mutex};
|
std::unique_lock write_lock{banks_mutex};
|
||||||
auto it2 = std::ranges::find_if(bank_infos, [&reqs](const DescriptorBankInfo& bank) {
|
|
||||||
return std::abs(bank.score - reqs.score) < SCORE_THRESHOLD && bank.IsSuperset(reqs);
|
|
||||||
});
|
|
||||||
if (it2 != bank_infos.end()) {
|
|
||||||
DescriptorBank& found = *banks[std::distance(bank_infos.begin(), it2)].get();
|
|
||||||
// update cache
|
|
||||||
std::scoped_lock lk(cache_mutex);
|
|
||||||
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
||||||
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
||||||
cache_[victim] = CacheEntry{found.info, &found, ++cache_tick_};
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
bank_infos.push_back(reqs);
|
bank_infos.push_back(reqs);
|
||||||
|
|
||||||
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
|
auto& bank = *banks.emplace_back(std::make_unique<DescriptorBank>());
|
||||||
bank.info = reqs;
|
bank.info = reqs;
|
||||||
AllocatePool(device, bank);
|
AllocatePool(device, bank);
|
||||||
// update cache
|
|
||||||
{
|
|
||||||
std::scoped_lock lk(cache_mutex);
|
|
||||||
size_t victim = 0; u64 oldest = UINT64_MAX;
|
|
||||||
for (size_t i=0;i<cache_.size();++i) if (cache_[i].stamp < oldest) { oldest = cache_[i].stamp; victim = i; }
|
|
||||||
cache_[victim] = CacheEntry{bank.info, &bank, ++cache_tick_};
|
|
||||||
}
|
|
||||||
return bank;
|
return bank;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -9,8 +6,7 @@
|
|||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
|
||||||
#include <mutex>
|
|
||||||
#include "shader_recompiler/shader_info.h"
|
#include "shader_recompiler/shader_info.h"
|
||||||
#include "video_core/renderer_vulkan/vk_resource_pool.h"
|
#include "video_core/renderer_vulkan/vk_resource_pool.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
@@ -79,14 +75,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DescriptorBank& Bank(const DescriptorBankInfo& reqs);
|
DescriptorBank& Bank(const DescriptorBankInfo& reqs);
|
||||||
struct CacheEntry {
|
|
||||||
DescriptorBankInfo info{};
|
|
||||||
DescriptorBank* bank{nullptr};
|
|
||||||
u64 stamp{0};
|
|
||||||
};
|
|
||||||
std::mutex cache_mutex{};
|
|
||||||
std::array<CacheEntry, 8> cache_{}; //test and then adjust
|
|
||||||
u64 cache_tick_{0};
|
|
||||||
|
|
||||||
const Device& device;
|
const Device& device;
|
||||||
MasterSemaphore& master_semaphore;
|
MasterSemaphore& master_semaphore;
|
||||||
|
|||||||
Reference in New Issue
Block a user