mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-28 11:35:11 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9cfc2f62f | |||
| 815325ccec |
@@ -333,6 +333,11 @@
|
||||
"repo": "herumi/xbyak",
|
||||
"version": "v7.40.1"
|
||||
},
|
||||
"zbic": {
|
||||
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
|
||||
"repo": "kinnay/zbic",
|
||||
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
|
||||
},
|
||||
"zlib": {
|
||||
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
|
||||
"min_version": "1.2",
|
||||
|
||||
Vendored
+5
@@ -48,6 +48,11 @@ if (NOT TARGET stb::headers)
|
||||
add_library(stb::headers ALIAS stb)
|
||||
endif()
|
||||
|
||||
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
|
||||
set(ZBIC_INCLUDE_DIR
|
||||
"${zbic_SOURCE_DIR}/src"
|
||||
PARENT_SCOPE)
|
||||
|
||||
# ItaniumDemangle (Windows only)
|
||||
if (WIN32 AND NOT TARGET LLVM::Demangle)
|
||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||
|
||||
@@ -137,6 +137,8 @@ add_library(
|
||||
uuid.cpp
|
||||
uuid.h
|
||||
vector_math.h
|
||||
zbic_compression.cpp
|
||||
zbic_compression.h
|
||||
zstd_compression.cpp
|
||||
zstd_compression.h
|
||||
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
|
||||
@@ -147,6 +149,10 @@ add_library(
|
||||
net/net.h net/net.cpp
|
||||
container/unordered_map.h container/unordered_set.h)
|
||||
|
||||
set_source_files_properties(zbic_compression.cpp PROPERTIES
|
||||
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
|
||||
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function;-Wno-missing-declarations;-Wno-shadow>")
|
||||
|
||||
if(WIN32)
|
||||
target_sources(common PRIVATE windows/timer_resolution.cpp
|
||||
windows/timer_resolution.h)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/zbic_compression.h"
|
||||
|
||||
#define ZSTD_ZBIC_SUPPORT 1
|
||||
#define ZSTDLIB_VISIBLE static
|
||||
#define ZSTDLIB_HIDDEN static
|
||||
#define ZSTDERRORLIB_VISIBLE static
|
||||
#define ZSTDERRORLIB_HIDDEN static
|
||||
#undef ZSTD_MULTITHREAD
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#undef _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "zstd.h"
|
||||
#define g_ZSTD_threading_useless_symbol g_ZSTD_zbic_threading_useless_symbol
|
||||
#include "zstd.c"
|
||||
#undef g_ZSTD_threading_useless_symbol
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
bool IsZBIC(std::span<const u8> src) {
|
||||
if (src.size() < sizeof(u32)) {
|
||||
return false;
|
||||
}
|
||||
u32 magic = 0;
|
||||
std::memcpy(&magic, src.data(), sizeof(u32));
|
||||
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
|
||||
}
|
||||
|
||||
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
|
||||
if (dst.empty() || src.empty()) {
|
||||
return -1;
|
||||
}
|
||||
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
|
||||
if (ZSTD_isError(res)) {
|
||||
return -1;
|
||||
}
|
||||
return static_cast<int>(res);
|
||||
}
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common::Compression {
|
||||
|
||||
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
|
||||
|
||||
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
|
||||
|
||||
} // namespace Common::Compression
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "core/hle/service/ro/ro_types.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#ifdef HAS_NCE
|
||||
#include "core/arm/nce/patcher.h"
|
||||
#include "core/hle/kernel/k_shared_memory.h"
|
||||
#endif
|
||||
|
||||
namespace Service::RO {
|
||||
|
||||
@@ -386,7 +390,7 @@ public:
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address,
|
||||
Result MapManualLoadModuleMemory(Kernel::KernelCore& kernel, u64* out_address, size_t context_id, u64 nro_address,
|
||||
u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
// Get context.
|
||||
ProcessContext* context = this->GetContextById(context_id);
|
||||
@@ -421,7 +425,31 @@ public:
|
||||
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
|
||||
std::addressof(ro_size), std::addressof(rw_size),
|
||||
nro_info->base_address, nro_size, bss_size));
|
||||
#ifdef HAS_NCE
|
||||
if (Settings::IsNceEnabled()) {
|
||||
auto* process = context->GetProcess();
|
||||
auto& memory = process->GetMemory();
|
||||
|
||||
std::vector<u8> image(total_size);
|
||||
memory.ReadBlock(nro_info->base_address, image.data(), rx_size);
|
||||
|
||||
Kernel::CodeSet::Segment code{.size = static_cast<u32>(rx_size)};
|
||||
Core::NCE::Patcher patch;
|
||||
patch.PatchText(image, code);
|
||||
patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr);
|
||||
|
||||
const u64 patch_address = nro_info->base_address + total_size;
|
||||
const size_t patch_size = patch.GetSectionSize();
|
||||
constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute;
|
||||
|
||||
auto* patch_memory = Kernel::KSharedMemory::Create(kernel);
|
||||
R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size));
|
||||
std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size);
|
||||
R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size));
|
||||
R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission));
|
||||
memory.WriteBlock(nro_info->base_address, image.data(), rx_size);
|
||||
}
|
||||
#endif
|
||||
// Set NRO perms.
|
||||
R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
|
||||
rw_size + bss_size));
|
||||
@@ -531,7 +559,7 @@ public:
|
||||
Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
|
||||
u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
|
||||
R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address,
|
||||
R_RETURN(m_ro->MapManualLoadModuleMemory(system.Kernel(), out_load_address.Get(), m_context_id, nro_address,
|
||||
nro_size, bss_address, bss_size));
|
||||
}
|
||||
|
||||
|
||||
+31
-4
@@ -7,12 +7,14 @@
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/lz4_compression.h"
|
||||
#include "common/zbic_compression.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
@@ -104,11 +106,36 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
|
||||
for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
|
||||
nso_file.Read(compressed_data.data(), nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
|
||||
if (nso_header.IsSegmentCompressed(i)) {
|
||||
int r = Common::Compression::DecompressDataLZ4(decompressed_size.data(), nso_header.segments[i].size, compressed_data.data(), nso_header.segments_compressed_size[i]);
|
||||
ASSERT(r == int(nso_header.segments[i].size));
|
||||
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, decompressed_size.data(), nso_header.segments[i].size);
|
||||
if (nso_header.IsZBICCompressed()) {
|
||||
// ZBIC compression
|
||||
const int r = Common::Compression::DecompressDataZBIC(
|
||||
std::span<u8>{decompressed_size}.first(nso_header.segments[i].size),
|
||||
std::span<const u8>{compressed_data}.first(nso_header.segments_compressed_size[i])
|
||||
);
|
||||
ASSERT(r > 0);
|
||||
} else {
|
||||
// LZ4 compression
|
||||
int r = Common::Compression::DecompressDataLZ4(
|
||||
decompressed_size.data(),
|
||||
nso_header.segments[i].size,
|
||||
compressed_data.data(),
|
||||
nso_header.segments_compressed_size[i]
|
||||
);
|
||||
ASSERT(r == int(nso_header.segments[i].size));
|
||||
}
|
||||
|
||||
std::memcpy(
|
||||
codeset.memory.data() + module_start + nso_header.segments[i].location,
|
||||
decompressed_size.data(),
|
||||
nso_header.segments[i].size
|
||||
);
|
||||
} else {
|
||||
std::memcpy(codeset.memory.data() + module_start + nso_header.segments[i].location, compressed_data.data(), nso_header.segments[i].size);
|
||||
// Not compressed
|
||||
std::memcpy(
|
||||
codeset.memory.data() + module_start + nso_header.segments[i].location,
|
||||
compressed_data.data(),
|
||||
nso_header.segments[i].size
|
||||
);
|
||||
}
|
||||
codeset.segments[i].addr = module_start + nso_header.segments[i].location;
|
||||
codeset.segments[i].offset = module_start + nso_header.segments[i].location;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -58,6 +61,9 @@ struct NSOHeader {
|
||||
std::array<SHA256Hash, 3> segment_hashes;
|
||||
|
||||
bool IsSegmentCompressed(size_t segment_num) const;
|
||||
bool IsZBICCompressed() const {
|
||||
return ((flags >> 7) & 1) != 0;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size.");
|
||||
static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable.");
|
||||
|
||||
@@ -201,7 +201,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
||||
|
||||
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||
ir_block.Reset(descriptor);
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
Optimization::Optimize(ir_block, conf, {});
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,8 @@ A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf)
|
||||
|
||||
void A64AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||
ir_block.Reset(descriptor);
|
||||
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, conf);
|
||||
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
||||
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
||||
Optimization::Optimize(ir_block, conf, {});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
||||
}
|
||||
|
||||
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
Optimization::Optimize(ir_block, conf, {.sha256 = true});
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ A32AddressSpace::A32AddressSpace(const A32::UserConfig& conf)
|
||||
}
|
||||
|
||||
void A32AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
|
||||
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
|
||||
Optimization::Optimize(ir_block, conf, {});
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ private:
|
||||
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||
auto const arch_descriptor = A32::LocationDescriptor{descriptor};
|
||||
ir_block.Reset(arch_descriptor);
|
||||
A32::Translate(ir_block, arch_descriptor, conf);
|
||||
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);
|
||||
return emitter.Emit(ir_block);
|
||||
}
|
||||
|
||||
@@ -254,10 +254,11 @@ private:
|
||||
block_of_code.EnsureMemoryCommitted(MINIMUM_REMAINING_CODESIZE);
|
||||
|
||||
// JIT Compile
|
||||
const auto get_code = [this](u64 vaddr) { return conf.callbacks->MemoryReadCode(vaddr); };
|
||||
// LocationDescriptor ctor() does important ops (like tflags) do not skip
|
||||
auto const arch_descriptor = A64::LocationDescriptor{descriptor};
|
||||
ir_block.Reset(arch_descriptor);
|
||||
A64::Translate(ir_block, arch_descriptor, conf);
|
||||
A64::Translate(ir_block, arch_descriptor, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
|
||||
Optimization::Optimize(ir_block, conf, polyfill_options);
|
||||
return emitter.Emit(ir_block).entrypoint;
|
||||
}
|
||||
|
||||
@@ -9,16 +9,15 @@
|
||||
#include "dynarmic/frontend/A32/translate/a32_translate.h"
|
||||
|
||||
#include "dynarmic/frontend/A32/a32_location_descriptor.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
|
||||
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
|
||||
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
|
||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, conf);
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options);
|
||||
}
|
||||
|
||||
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "dynarmic/interface/A32/arch_version.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
|
||||
namespace Dynarmic::IR {
|
||||
class Block;
|
||||
@@ -21,14 +20,28 @@ namespace Dynarmic::A32 {
|
||||
class LocationDescriptor;
|
||||
struct TranslateCallbacks;
|
||||
|
||||
struct TranslationOptions {
|
||||
ArchVersion arch_version;
|
||||
|
||||
/// This changes what IR we emit when we translate an unpredictable instruction.
|
||||
/// If this is false, the ExceptionRaised IR instruction is emitted.
|
||||
/// If this is true, we define some behaviour for some instructions.
|
||||
bool define_unpredictable_behaviour = false;
|
||||
|
||||
/// This changes what IR we emit when we translate a hint instruction.
|
||||
/// If this is false, we treat the instruction as a NOP.
|
||||
/// If this is true, we emit an ExceptionRaised instruction.
|
||||
bool hook_hint_instructions = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function translates instructions in memory into our intermediate representation.
|
||||
* @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c.
|
||||
* @param tcb The callbacks we should use to read emulated memory.
|
||||
* @param conf Configures how certain instructions are translated.
|
||||
* @param options Configures how certain instructions are translated.
|
||||
* @return A translated basic block in the intermediate representation.
|
||||
*/
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
|
||||
|
||||
/**
|
||||
* This function translates a single provided instruction into our intermediate representation.
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 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
|
||||
@@ -13,7 +10,7 @@ namespace Dynarmic::A32 {
|
||||
|
||||
// BKPT #<imm16>
|
||||
bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/) {
|
||||
if (cond != Cond::AL && !conf.define_unpredictable_behaviour) {
|
||||
if (cond != Cond::AL && !options.define_unpredictable_behaviour) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
// UNPREDICTABLE: The instruction executes conditionally.
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "dynarmic/interface/A32/config.h"
|
||||
#include "dynarmic/mcl/bit.hpp"
|
||||
|
||||
#include "dynarmic/frontend/A32/a32_ir_emitter.h"
|
||||
@@ -26,14 +25,12 @@ enum class Exception;
|
||||
struct TranslatorVisitor final {
|
||||
using instruction_return_type = bool;
|
||||
|
||||
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf)
|
||||
: ir(block, descriptor, conf.arch_version)
|
||||
, conf(conf)
|
||||
{}
|
||||
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options)
|
||||
: ir(block, descriptor, options.arch_version), options(options) {}
|
||||
|
||||
A32::IREmitter ir;
|
||||
ConditionalState cond_state = ConditionalState::None;
|
||||
A32::UserConfig const& conf;
|
||||
TranslationOptions options;
|
||||
|
||||
size_t current_instruction_size;
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2019 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -12,7 +9,7 @@
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*imm12*/) {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,7 +18,7 @@ bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*i
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*imm5*/, ShiftType /*shift*/, Reg /*m*/) {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,7 +27,7 @@ bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*im
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_SEV() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -38,7 +35,7 @@ bool TranslatorVisitor::arm_SEV() {
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_SEVL() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -46,7 +43,7 @@ bool TranslatorVisitor::arm_SEVL() {
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_WFE() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,7 +51,7 @@ bool TranslatorVisitor::arm_WFE() {
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_WFI() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -62,7 +59,7 @@ bool TranslatorVisitor::arm_WFI() {
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_YIELD() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -642,7 +642,7 @@ bool TranslatorVisitor::thumb16_SUB_sp(Imm<7> imm7) {
|
||||
|
||||
// SEV<c>
|
||||
bool TranslatorVisitor::thumb16_SEV() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::SendEvent);
|
||||
@@ -650,7 +650,7 @@ bool TranslatorVisitor::thumb16_SEV() {
|
||||
|
||||
// SEVL<c>
|
||||
bool TranslatorVisitor::thumb16_SEVL() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::SendEventLocal);
|
||||
@@ -658,7 +658,7 @@ bool TranslatorVisitor::thumb16_SEVL() {
|
||||
|
||||
// WFE<c>
|
||||
bool TranslatorVisitor::thumb16_WFE() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::WaitForEvent);
|
||||
@@ -666,7 +666,7 @@ bool TranslatorVisitor::thumb16_WFE() {
|
||||
|
||||
// WFI<c>
|
||||
bool TranslatorVisitor::thumb16_WFI() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::WaitForInterrupt);
|
||||
@@ -674,7 +674,7 @@ bool TranslatorVisitor::thumb16_WFI() {
|
||||
|
||||
// YIELD<c>
|
||||
bool TranslatorVisitor::thumb16_YIELD() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::Yield);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2021 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -11,7 +8,7 @@
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
static bool PLDHandler(TranslatorVisitor& v, bool W) {
|
||||
if (!v.conf.hook_hint_instructions) {
|
||||
if (!v.options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -21,7 +18,7 @@ static bool PLDHandler(TranslatorVisitor& v, bool W) {
|
||||
}
|
||||
|
||||
static bool PLIHandler(TranslatorVisitor& v) {
|
||||
if (!v.conf.hook_hint_instructions) {
|
||||
if (!v.options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,12 +22,10 @@
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
|
||||
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
const bool single_step = descriptor.SingleStepping();
|
||||
TranslatorVisitor visitor{block, descriptor, conf};
|
||||
TranslatorVisitor visitor{block, descriptor, options};
|
||||
bool should_continue = true;
|
||||
|
||||
auto tcb = conf.callbacks;
|
||||
do {
|
||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||
u64 ticks_for_instruction = 1;
|
||||
|
||||
@@ -103,12 +103,10 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept {
|
||||
|
||||
} // namespace
|
||||
|
||||
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
|
||||
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
|
||||
const bool single_step = descriptor.SingleStepping();
|
||||
TranslatorVisitor visitor{block, descriptor, conf};
|
||||
TranslatorVisitor visitor{block, descriptor, options};
|
||||
bool should_continue = true;
|
||||
|
||||
auto tcb = conf.callbacks;
|
||||
do {
|
||||
const u32 arm_pc = visitor.ir.current_location.PC();
|
||||
u64 ticks_for_instruction = 1;
|
||||
|
||||
@@ -11,20 +11,19 @@
|
||||
#include "dynarmic/frontend/A64/a64_location_descriptor.h"
|
||||
#include "dynarmic/frontend/A64/decoder/a64.h"
|
||||
#include "dynarmic/frontend/A64/translate/impl/impl.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/terminal.h"
|
||||
|
||||
namespace Dynarmic::A64 {
|
||||
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf) {
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
|
||||
const bool single_step = descriptor.SingleStepping();
|
||||
TranslatorVisitor visitor{block, descriptor, conf};
|
||||
TranslatorVisitor visitor{block, descriptor, std::move(options)};
|
||||
|
||||
bool should_continue = true;
|
||||
do {
|
||||
const u64 pc = visitor.ir.current_location->PC();
|
||||
if (const auto instruction = conf.callbacks->MemoryReadCode(pc)) {
|
||||
if (const auto instruction = memory_read_code(pc)) {
|
||||
if (auto decoder = Decode<TranslatorVisitor, bool>(visitor, *instruction)) {
|
||||
should_continue = *decoder;
|
||||
} else {
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <optional>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
|
||||
namespace Dynarmic {
|
||||
|
||||
@@ -23,14 +22,32 @@ namespace A64 {
|
||||
|
||||
class LocationDescriptor;
|
||||
|
||||
using MemoryReadCodeFuncType = std::function<std::optional<u32>(u64 vaddr)>;
|
||||
|
||||
struct TranslationOptions {
|
||||
/// This changes what IR we emit when we translate an unpredictable instruction.
|
||||
/// If this is false, the ExceptionRaised IR instruction is emitted.
|
||||
/// If this is true, we define some behaviour for some instructions.
|
||||
bool define_unpredictable_behaviour = false;
|
||||
|
||||
/// This tells the translator a wall clock will be used, thus allowing it
|
||||
/// to avoid writting certain unnecessary code only needed for cycle timers.
|
||||
bool wall_clock_cntpct = false;
|
||||
|
||||
/// This changes what IR we emit when we translate a hint instruction.
|
||||
/// If this is false, we treat the instruction as a NOP.
|
||||
/// If this is true, we emit an ExceptionRaised instruction.
|
||||
bool hook_hint_instructions = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function translates instructions in memory into our intermediate representation.
|
||||
* @param descriptor The starting location of the basic block. Includes information like PC, FPCR state, &c.
|
||||
* @param memory_read_code The function we should use to read emulated memory.
|
||||
* @param conf Configures how certain instructions are translated.
|
||||
* @param options Configures how certain instructions are translated.
|
||||
* @return A translated basic block in the intermediate representation.
|
||||
*/
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf);
|
||||
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
|
||||
|
||||
/**
|
||||
* This function translates a single provided instruction into our intermediate representation.
|
||||
|
||||
@@ -15,20 +15,17 @@
|
||||
#include "dynarmic/frontend/A64/a64_types.h"
|
||||
#include "dynarmic/frontend/A64/translate/a64_translate.h"
|
||||
#include "dynarmic/frontend/imm.h"
|
||||
#include "dynarmic/interface/A64/config.h"
|
||||
|
||||
namespace Dynarmic::A64 {
|
||||
|
||||
struct TranslatorVisitor final {
|
||||
using instruction_return_type = bool;
|
||||
|
||||
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf)
|
||||
: ir(block, descriptor)
|
||||
, conf(conf)
|
||||
{}
|
||||
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, TranslationOptions options)
|
||||
: ir(block, descriptor), options(std::move(options)) {}
|
||||
|
||||
A64::IREmitter ir;
|
||||
A64::UserConfig const& conf;
|
||||
TranslationOptions options;
|
||||
|
||||
bool UnpredictableInstruction();
|
||||
bool DecodeError();
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2018 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
@@ -28,7 +25,7 @@ static bool ExclusiveSharedDecodeAndOperation(TranslatorVisitor& v, bool pair, s
|
||||
if (memop == IR::MemOp::LOAD && pair && Rt == *Rt2) {
|
||||
return v.UnpredictableInstruction();
|
||||
} else if (memop == IR::MemOp::STORE && (*Rs == Rt || (pair && *Rs == *Rt2))) {
|
||||
if (!v.conf.define_unpredictable_behaviour) {
|
||||
if (!v.options.define_unpredictable_behaviour) {
|
||||
return v.UnpredictableInstruction();
|
||||
}
|
||||
// UNPREDICTABLE: The Constraint_NONE case is executed.
|
||||
|
||||
@@ -42,35 +42,35 @@ bool TranslatorVisitor::NOP() {
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::YIELD() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::Yield);
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::WFE() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::WaitForEvent);
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::WFI() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::WaitForInterrupt);
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::SEV() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::SendEvent);
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::SEVL() {
|
||||
if (!conf.hook_hint_instructions) {
|
||||
if (!options.hook_hint_instructions) {
|
||||
return true;
|
||||
}
|
||||
return RaiseException(Exception::SendEventLocal);
|
||||
@@ -129,7 +129,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
|
||||
return true;
|
||||
case SystemRegisterEncoding::CNTPCT_EL0:
|
||||
// HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date.
|
||||
if (!ir.block.instructions.empty() && !conf.wall_clock_cntpct) {
|
||||
if (!ir.block.instructions.empty() && !options.wall_clock_cntpct) {
|
||||
ir.block.CycleCount()--;
|
||||
ir.SetTerm(IR::Term::LinkBlock{*ir.current_location});
|
||||
return false;
|
||||
|
||||
@@ -180,7 +180,7 @@ static void RunInstance(size_t run_number, ThumbTestEnv& test_env, A32::UserConf
|
||||
while (num_insts < instructions_to_execute_count) {
|
||||
A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, A32::FPSCR{}};
|
||||
ir_block.Reset(descriptor);
|
||||
A32::Translate(ir_block, descriptor, config);
|
||||
A32::Translate(ir_block, descriptor, &test_env, {});
|
||||
Optimization::Optimize(ir_block, config, {});
|
||||
printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str());
|
||||
printf("\n\nx86_64:\n");
|
||||
|
||||
@@ -268,7 +268,7 @@ static void RunTestInstance(Dynarmic::A64::Jit& jit, A64Unicorn& uni, A64TestEnv
|
||||
// const auto get_code = [&jit_env](u64 vaddr) { return jit_env.MemoryReadCode(vaddr); };
|
||||
// const A64::LocationDescriptor location{instructions_start, FP::FPCR{fpcr}};
|
||||
// IR::Block ir_block{location};
|
||||
// A64::Translate(ir_block, location, config);
|
||||
// A64::Translate(ir_block, location, get_code, {});
|
||||
// fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block));
|
||||
// Optimization::Optimize(ir_block, conf, {});
|
||||
// fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block));
|
||||
|
||||
Reference in New Issue
Block a user