Compare commits

..

1 Commits

Author SHA1 Message Date
lizzie 60633c08af 2026-09-26 16:50:55
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-26 16:50:55 +00:00
23 changed files with 89 additions and 98 deletions
@@ -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.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
Optimization::Optimize(ir_block, conf, {});
}
@@ -366,8 +366,7 @@ A64AddressSpace::A64AddressSpace(const A64::UserConfig& conf)
void A64AddressSpace::GenerateIR(IR::Block& ir_block, IR::LocationDescriptor descriptor) const {
ir_block.Reset(descriptor);
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});
A64::Translate(ir_block, A64::LocationDescriptor{descriptor}, conf);
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.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
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.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
A32::Translate(ir_block, A32::LocationDescriptor{descriptor}, conf);
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.callbacks, {conf.arch_version, conf.define_unpredictable_behaviour, conf.hook_hint_instructions});
A32::Translate(ir_block, arch_descriptor, conf);
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block);
}
@@ -254,11 +254,10 @@ 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, get_code, {conf.define_unpredictable_behaviour, conf.wall_clock_cntpct});
A64::Translate(ir_block, arch_descriptor, conf);
Optimization::Optimize(ir_block, conf, polyfill_options);
return emitter.Emit(ir_block).entrypoint;
}
@@ -9,15 +9,16 @@
#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, TranslateCallbacks* tcb, const TranslationOptions& options);
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, tcb, options);
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(block, descriptor, conf);
}
bool TranslateSingleArmInstruction(IR::Block& block, LocationDescriptor descriptor, u32 instruction);
@@ -10,6 +10,7 @@
#include "common/common_types.h"
#include "dynarmic/interface/A32/arch_version.h"
#include "dynarmic/interface/A32/config.h"
namespace Dynarmic::IR {
class Block;
@@ -20,28 +21,14 @@ 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 options Configures how certain instructions are translated.
* @param conf Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
void Translate(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options);
void Translate(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf);
/**
* This function translates a single provided instruction into our intermediate representation.
@@ -1,3 +1,6 @@
// 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
@@ -10,7 +13,7 @@ namespace Dynarmic::A32 {
// BKPT #<imm16>
bool TranslatorVisitor::arm_BKPT(Cond cond, Imm<12> /*imm12*/, Imm<4> /*imm4*/) {
if (cond != Cond::AL && !options.define_unpredictable_behaviour) {
if (cond != Cond::AL && !conf.define_unpredictable_behaviour) {
return UnpredictableInstruction();
}
// UNPREDICTABLE: The instruction executes conditionally.
@@ -9,6 +9,7 @@
#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"
@@ -25,12 +26,14 @@ enum class Exception;
struct TranslatorVisitor final {
using instruction_return_type = bool;
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const TranslationOptions& options)
: ir(block, descriptor, options.arch_version), options(options) {}
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf)
: ir(block, descriptor, conf.arch_version)
, conf(conf)
{}
A32::IREmitter ir;
ConditionalState cond_state = ConditionalState::None;
TranslationOptions options;
A32::UserConfig const& conf;
size_t current_instruction_size;
@@ -1,3 +1,6 @@
// 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
@@ -9,7 +12,7 @@
namespace Dynarmic::A32 {
bool TranslatorVisitor::arm_PLD_imm(bool /*add*/, bool R, Reg /*n*/, Imm<12> /*imm12*/) {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -18,7 +21,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 (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -27,7 +30,7 @@ bool TranslatorVisitor::arm_PLD_reg(bool /*add*/, bool R, Reg /*n*/, Imm<5> /*im
}
bool TranslatorVisitor::arm_SEV() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -35,7 +38,7 @@ bool TranslatorVisitor::arm_SEV() {
}
bool TranslatorVisitor::arm_SEVL() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -43,7 +46,7 @@ bool TranslatorVisitor::arm_SEVL() {
}
bool TranslatorVisitor::arm_WFE() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -51,7 +54,7 @@ bool TranslatorVisitor::arm_WFE() {
}
bool TranslatorVisitor::arm_WFI() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -59,7 +62,7 @@ bool TranslatorVisitor::arm_WFI() {
}
bool TranslatorVisitor::arm_YIELD() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
@@ -642,7 +642,7 @@ bool TranslatorVisitor::thumb16_SUB_sp(Imm<7> imm7) {
// SEV<c>
bool TranslatorVisitor::thumb16_SEV() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEvent);
@@ -650,7 +650,7 @@ bool TranslatorVisitor::thumb16_SEV() {
// SEVL<c>
bool TranslatorVisitor::thumb16_SEVL() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEventLocal);
@@ -658,7 +658,7 @@ bool TranslatorVisitor::thumb16_SEVL() {
// WFE<c>
bool TranslatorVisitor::thumb16_WFE() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForEvent);
@@ -666,7 +666,7 @@ bool TranslatorVisitor::thumb16_WFE() {
// WFI<c>
bool TranslatorVisitor::thumb16_WFI() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForInterrupt);
@@ -674,7 +674,7 @@ bool TranslatorVisitor::thumb16_WFI() {
// YIELD<c>
bool TranslatorVisitor::thumb16_YIELD() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::Yield);
@@ -1,3 +1,6 @@
// 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
@@ -8,7 +11,7 @@
namespace Dynarmic::A32 {
static bool PLDHandler(TranslatorVisitor& v, bool W) {
if (!v.options.hook_hint_instructions) {
if (!v.conf.hook_hint_instructions) {
return true;
}
@@ -18,7 +21,7 @@ static bool PLDHandler(TranslatorVisitor& v, bool W) {
}
static bool PLIHandler(TranslatorVisitor& v) {
if (!v.options.hook_hint_instructions) {
if (!v.conf.hook_hint_instructions) {
return true;
}
@@ -22,10 +22,12 @@
namespace Dynarmic::A32 {
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
void TranslateArm(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, options};
TranslatorVisitor visitor{block, descriptor, conf};
bool should_continue = true;
auto tcb = conf.callbacks;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
u64 ticks_for_instruction = 1;
@@ -103,10 +103,12 @@ inline bool MaybeVFPOrASIMDInstruction(u32 thumb_instruction) noexcept {
} // namespace
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, TranslateCallbacks* tcb, const TranslationOptions& options) {
void TranslateThumb(IR::Block& block, LocationDescriptor descriptor, const A32::UserConfig& conf) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, options};
TranslatorVisitor visitor{block, descriptor, conf};
bool should_continue = true;
auto tcb = conf.callbacks;
do {
const u32 arm_pc = visitor.ir.current_location.PC();
u64 ticks_for_instruction = 1;
@@ -11,19 +11,20 @@
#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, MemoryReadCodeFuncType memory_read_code, TranslationOptions options) {
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf) {
const bool single_step = descriptor.SingleStepping();
TranslatorVisitor visitor{block, descriptor, std::move(options)};
TranslatorVisitor visitor{block, descriptor, conf};
bool should_continue = true;
do {
const u64 pc = visitor.ir.current_location->PC();
if (const auto instruction = memory_read_code(pc)) {
if (const auto instruction = conf.callbacks->MemoryReadCode(pc)) {
if (auto decoder = Decode<TranslatorVisitor, bool>(visitor, *instruction)) {
should_continue = *decoder;
} else {
@@ -11,6 +11,7 @@
#include <optional>
#include "common/common_types.h"
#include "dynarmic/interface/A64/config.h"
namespace Dynarmic {
@@ -22,32 +23,14 @@ 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 options Configures how certain instructions are translated.
* @param conf Configures how certain instructions are translated.
* @return A translated basic block in the intermediate representation.
*/
void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code, TranslationOptions options);
void Translate(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf);
/**
* This function translates a single provided instruction into our intermediate representation.
@@ -15,17 +15,20 @@
#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, TranslationOptions options)
: ir(block, descriptor), options(std::move(options)) {}
explicit TranslatorVisitor(IR::Block& block, LocationDescriptor descriptor, A64::UserConfig const& conf)
: ir(block, descriptor)
, conf(conf)
{}
A64::IREmitter ir;
TranslationOptions options;
A64::UserConfig const& conf;
bool UnpredictableInstruction();
bool DecodeError();
@@ -1,3 +1,6 @@
// 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
@@ -25,7 +28,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.options.define_unpredictable_behaviour) {
if (!v.conf.define_unpredictable_behaviour) {
return v.UnpredictableInstruction();
}
// UNPREDICTABLE: The Constraint_NONE case is executed.
@@ -42,35 +42,35 @@ bool TranslatorVisitor::NOP() {
}
bool TranslatorVisitor::YIELD() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::Yield);
}
bool TranslatorVisitor::WFE() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForEvent);
}
bool TranslatorVisitor::WFI() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::WaitForInterrupt);
}
bool TranslatorVisitor::SEV() {
if (!options.hook_hint_instructions) {
if (!conf.hook_hint_instructions) {
return true;
}
return RaiseException(Exception::SendEvent);
}
bool TranslatorVisitor::SEVL() {
if (!options.hook_hint_instructions) {
if (!conf.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() && !options.wall_clock_cntpct) {
if (!ir.block.instructions.empty() && !conf.wall_clock_cntpct) {
ir.block.CycleCount()--;
ir.SetTerm(IR::Term::LinkBlock{*ir.current_location});
return false;
+1 -1
View File
@@ -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, &test_env, {});
A32::Translate(ir_block, descriptor, config);
Optimization::Optimize(ir_block, config, {});
printf("\n\nIR:\n%s", IR::DumpBlock(ir_block).c_str());
printf("\n\nx86_64:\n");
+1 -1
View File
@@ -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, get_code, {});
// A64::Translate(ir_block, location, config);
// fmt::print("IR:\n{}\n", IR::DumpBlock(ir_block));
// Optimization::Optimize(ir_block, conf, {});
// fmt::print("Optimized IR:\n{}\n", IR::DumpBlock(ir_block));
+12 -13
View File
@@ -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-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -83,21 +83,20 @@ void Joycons::ScanThread(std::stop_token stop_token) {
constexpr u16 nintendo_vendor_id = 0x057e;
Common::SetCurrentThreadName("JoyconScanThread");
auto last_ret = 0u;
do {
auto ret = SDL_hid_device_change_count();
if (last_ret == 0u || last_ret != ret) {
last_ret = ret;
SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0);
for (auto* cur_dev = devs; cur_dev; cur_dev = cur_dev->next) {
if (IsDeviceNew(cur_dev)) {
LOG_DEBUG(Input, "Device Found,type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id);
RegisterNewDevice(cur_dev);
}
cur_dev = cur_dev->next;
SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0);
SDL_hid_device_info* cur_dev = devs;
while (cur_dev) {
if (IsDeviceNew(cur_dev)) {
LOG_DEBUG(Input, "Device Found,type : {:04X} {:04X}", cur_dev->vendor_id,
cur_dev->product_id);
RegisterNewDevice(cur_dev);
}
SDL_hid_free_enumeration(devs);
cur_dev = cur_dev->next;
}
SDL_hid_free_enumeration(devs);
} while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5}));
}