Compare commits
9 Commits
d06d2a756b
...
538ccacfbf
| Author | SHA1 | Date |
|---|---|---|
|
|
538ccacfbf | |
|
|
8df312d82e | |
|
|
91793d52cd | |
|
|
180941068f | |
|
|
8e373eb714 | |
|
|
75ebfaa090 | |
|
|
e3035ae8f2 | |
|
|
bcd22d9f8b | |
|
|
4e7c036c7e |
|
|
@ -37,7 +37,7 @@ set(GIT_DESC ${BUILD_VERSION})
|
|||
|
||||
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
|
||||
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
|
||||
set(BUILD_AUTO_UPDATE_API "http://api.github.com")
|
||||
set(BUILD_AUTO_UPDATE_API "https://api.github.com")
|
||||
|
||||
if (NIGHTLY_BUILD)
|
||||
set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly")
|
||||
|
|
|
|||
|
|
@ -286,15 +286,6 @@ Exclusive OR (i.e.: XOR)
|
|||
|
||||
Memory access.
|
||||
|
||||
### Terminal: Interpret
|
||||
|
||||
```c++
|
||||
SetTerm(IR::Term::Interpret{next})
|
||||
```
|
||||
|
||||
This terminal instruction calls the interpreter, starting at `next`.
|
||||
The interpreter must interpret exactly one instruction.
|
||||
|
||||
### Terminal: ReturnToDispatch
|
||||
|
||||
```c++
|
||||
|
|
|
|||
|
|
@ -117,11 +117,6 @@ public:
|
|||
MemoryWrite32(vaddr + 4, u32(value >> 32));
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions) override {
|
||||
// This is never called in practice.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
// Do something.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,4 @@ Debugging on physical hardware can get tedious and time consuming. Users are emp
|
|||
|
||||
**Standard key prefix**: Allows to redirect the key manager to a file other than `prod.keys` (for example `other` would redirect to `other.keys`). This is useful for testing multiple keysets. Default is `prod`.
|
||||
|
||||
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as it will be writen in-place (that is, it will be filled with the default serial and then overwrite the serial from the beginning).
|
||||
- Battery serial: `YUZU0EMULATOR14022024`
|
||||
- Board serial: `YUZ10000000001`
|
||||
If the user were to set their board serial as `ABC`, then it will be written in-place and the resulting serial would be `ABC10000000001`. There are no underlying checks to ensure correctness of serials other than a hard limit of 16-characters for both.
|
||||
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accoutned for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console.
|
||||
|
|
|
|||
|
|
@ -534,8 +534,8 @@
|
|||
<item>@string/frame_pacing_mode_target_Auto</item>
|
||||
<item>@string/frame_pacing_mode_target_30</item>
|
||||
<item>@string/frame_pacing_mode_target_60</item>
|
||||
<item>@string/frame_pacing_mode_target_90</item>
|
||||
<item>@string/frame_pacing_mode_target_120</item>
|
||||
<item>@string/frame_pacing_mode_target_240</item>
|
||||
</string-array>
|
||||
<integer-array name="framePacingModeValues">
|
||||
<item>0</item>
|
||||
|
|
|
|||
|
|
@ -1038,8 +1038,8 @@
|
|||
<string name="frame_pacing_mode_target_Auto">Auto</string>
|
||||
<string name="frame_pacing_mode_target_30">30 FPS</string>
|
||||
<string name="frame_pacing_mode_target_60">60 FPS</string>
|
||||
<string name="frame_pacing_mode_target_90">90 FPS</string>
|
||||
<string name="frame_pacing_mode_target_120">120 FPS</string>
|
||||
<string name="frame_pacing_mode_target_240">240 FPS</string>
|
||||
|
||||
<!-- ASTC Decoding Method Choices -->
|
||||
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
|
||||
|
|
|
|||
|
|
@ -462,9 +462,12 @@ struct Values {
|
|||
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
|
||||
FramePacingMode::Target_Auto,
|
||||
FramePacingMode::Target_Auto,
|
||||
FramePacingMode::Target_240,
|
||||
FramePacingMode::Target_120,
|
||||
"frame_pacing_mode",
|
||||
Category::RendererAdvanced};
|
||||
Category::RendererAdvanced,
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
|
||||
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
|
||||
AstcRecompression::Uncompressed,
|
||||
|
|
@ -620,11 +623,11 @@ struct Values {
|
|||
"language_index",
|
||||
Category::System};
|
||||
SwitchableSetting<Region, true> region_index{linkage, Region::Usa, "region_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto,
|
||||
"time_zone_index", Category::System};
|
||||
SwitchableSetting<TimeZone, true> time_zone_index{linkage, TimeZone::Auto, "time_zone_index", Category::System};
|
||||
Setting<u32> serial_battery{linkage, 0, "serial_battery", Category::System};
|
||||
Setting<u32> serial_unit{linkage, 0, "serial_unit", Category::System};
|
||||
// Measured in seconds since epoch
|
||||
SwitchableSetting<bool> custom_rtc_enabled{
|
||||
linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<bool> custom_rtc_enabled{linkage, false, "custom_rtc_enabled", Category::System, Specialization::Paired, true, true};
|
||||
SwitchableSetting<s64> custom_rtc{
|
||||
linkage, 0, "custom_rtc", Category::System, Specialization::Time,
|
||||
false, true, &custom_rtc_enabled};
|
||||
|
|
@ -794,8 +797,6 @@ struct Values {
|
|||
true};
|
||||
|
||||
// Miscellaneous
|
||||
Setting<std::string> serial_battery{linkage, std::string(), "serial_battery", Category::Miscellaneous};
|
||||
Setting<std::string> serial_unit{linkage, std::string(), "serial_unit", Category::Miscellaneous};
|
||||
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
|
||||
Setting<bool> log_flush_line{linkage, false, "flush_line", Category::Miscellaneous, Specialization::Default, true, true};
|
||||
Setting<bool> censor_username{linkage, true, "censor_username", Category::Miscellaneous};
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
|
|||
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16, X32, X64, None);
|
||||
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
|
||||
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
|
||||
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_120, Target_240);
|
||||
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
|
||||
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
|
||||
ENUM(VramUsageMode, Conservative, Aggressive);
|
||||
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
|
||||
|
|
|
|||
|
|
@ -88,13 +88,6 @@ bool DynarmicCallbacks32::MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expec
|
|||
m_memory.WriteExclusive64(vaddr, value, expected);
|
||||
}
|
||||
|
||||
void DynarmicCallbacks32::InterpreterFallback(u32 pc, std::size_t num_instructions) {
|
||||
m_parent.LogBacktrace(m_process);
|
||||
LOG_ERROR(Core_ARM,
|
||||
"Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, m_memory.Read32(pc));
|
||||
}
|
||||
|
||||
void DynarmicCallbacks32::ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) {
|
||||
switch (exception) {
|
||||
case Dynarmic::A32::Exception::NoExecuteFault:
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ public:
|
|||
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
|
||||
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
|
||||
bool MemoryWriteExclusive64(u32 vaddr, u64 value, u64 expected) override;
|
||||
void InterpreterFallback(u32 pc, std::size_t num_instructions) override;
|
||||
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override;
|
||||
void CallSVC(u32 swi) override;
|
||||
void AddTicks(u64 ticks) override;
|
||||
|
|
|
|||
|
|
@ -102,13 +102,6 @@ bool DynarmicCallbacks64::MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vect
|
|||
m_memory.WriteExclusive128(vaddr, value, expected);
|
||||
}
|
||||
|
||||
void DynarmicCallbacks64::InterpreterFallback(u64 pc, std::size_t num_instructions) {
|
||||
m_parent.LogBacktrace(m_process);
|
||||
LOG_ERROR(Core_ARM, "Unimplemented instruction @ {:#X} for {} instructions (instr = {:08X})", pc,
|
||||
num_instructions, m_memory.Read32(pc));
|
||||
ReturnException(pc, PrefetchAbort);
|
||||
}
|
||||
|
||||
void DynarmicCallbacks64::InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) {
|
||||
switch (op) {
|
||||
case Dynarmic::A64::InstructionCacheOperation::InvalidateByVAToPoU: {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ public:
|
|||
bool MemoryWriteExclusive32(u64 vaddr, std::uint32_t value, std::uint32_t expected) override;
|
||||
bool MemoryWriteExclusive64(u64 vaddr, std::uint64_t value, std::uint64_t expected) override;
|
||||
bool MemoryWriteExclusive128(u64 vaddr, Dynarmic::A64::Vector value, Dynarmic::A64::Vector expected) override;
|
||||
void InterpreterFallback(u64 pc, std::size_t num_instructions) override;
|
||||
void InstructionCacheOperationRaised(Dynarmic::A64::InstructionCacheOperation op, u64 value) override;
|
||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
|
||||
void CallSVC(u32 svc) override;
|
||||
|
|
|
|||
|
|
@ -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-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
|
@ -772,12 +772,8 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
|
|||
u32 instruction = memory.Read32(pc);
|
||||
bool was_executed = false;
|
||||
|
||||
if (auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction)) {
|
||||
was_executed = decoder->get().call(visitor, instruction);
|
||||
} else {
|
||||
LOG_ERROR(Core_ARM, "Unallocated encoding: {:#x}", instruction);
|
||||
}
|
||||
|
||||
auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction);
|
||||
was_executed = decoder.get().call(visitor, instruction);
|
||||
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@
|
|||
#include "common/windows/timer_resolution.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(ARCHITECTURE_x86_64) && defined(__MINGW64__)
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#include "common/x64/rdtsc.h"
|
||||
#endif
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hardware_properties.h"
|
||||
|
|
@ -282,8 +287,45 @@ void CoreTiming::ThreadLoop() {
|
|||
const auto next_time = Advance();
|
||||
if (next_time) {
|
||||
// There are more events left in the queue, wait until the next event.
|
||||
auto wait_time = *next_time - GetGlobalTimeNs().count();
|
||||
event.WaitFor(std::chrono::nanoseconds(wait_time));
|
||||
if (auto wait_time = *next_time - GetGlobalTimeNs().count(); wait_time > 0) {
|
||||
#if defined(_WIN32) && defined(ARCHITECTURE_x86_64) && defined(__MINGW64__)
|
||||
while (!paused && !event.IsSet() && wait_time > 0) {
|
||||
wait_time = *next_time - GetGlobalTimeNs().count();
|
||||
if (wait_time >= timer_resolution_ns) {
|
||||
Common::Windows::SleepForOneTick();
|
||||
} else {
|
||||
// 100,000 cycles is a reasonable amount of time to wait to save on CPU resources.
|
||||
// For reference:
|
||||
// At 1 GHz, 100K cycles is 100us
|
||||
// At 2 GHz, 100K cycles is 50us
|
||||
// At 4 GHz, 100K cycles is 25us
|
||||
constexpr auto PauseCycles = 100'000U;
|
||||
auto const& caps = Common::GetCPUCaps();
|
||||
if (caps.waitpkg) {
|
||||
static constexpr auto RequestC02State = 0U;
|
||||
const auto tsc = Common::X64::FencedRDTSC() + PauseCycles;
|
||||
const auto eax = u32(tsc & 0xFFFFFFFF);
|
||||
const auto edx = u32(tsc >> 32);
|
||||
asm volatile("tpause %0" : : "r"(RequestC02State), "d"(edx), "a"(eax));
|
||||
} else if (caps.monitorx) {
|
||||
static constexpr auto EnableWaitTimeFlag = 1U << 1;
|
||||
static constexpr auto RequestC1State = 0U;
|
||||
// monitor_var should be aligned to a cache line.
|
||||
alignas(64) u64 monitor_var{};
|
||||
asm volatile("monitorx" : : "a"(&monitor_var), "c"(0), "d"(0));
|
||||
asm volatile("mwaitx" : : "a"(RequestC1State), "b"(PauseCycles), "c"(EnableWaitTimeFlag));
|
||||
} else {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.IsSet()) {
|
||||
event.Reset();
|
||||
}
|
||||
#else
|
||||
event.WaitFor(std::chrono::nanoseconds(wait_time));
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
// Queue is empty, wait until another event is scheduled and signals us to
|
||||
// continue.
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ public:
|
|||
|
||||
void CallSVC(u32 swi) override;
|
||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override;
|
||||
void InterpreterFallback(u64 pc, size_t num_instructions) override;
|
||||
|
||||
void AddTicks(u64 ticks) override {}
|
||||
u64 GetTicksRemaining() override {
|
||||
|
|
@ -432,11 +431,6 @@ void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception excep
|
|||
parent.jit->HaltExecution();
|
||||
}
|
||||
|
||||
void DynarmicCallbacks64::InterpreterFallback(u64 pc, size_t num_instructions) {
|
||||
LOG_CRITICAL(Service_JIT, "Unimplemented instruction PC @ {:08x}", pc);
|
||||
parent.jit->HaltExecution();
|
||||
}
|
||||
|
||||
JITContext::JITContext(Core::Memory::Memory& memory)
|
||||
: impl{std::make_unique<JITContextImpl>(memory)} {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
|
|
@ -980,25 +980,82 @@ Result ISystemSettingsServer::SetPrimaryAlbumStorage(PrimaryAlbumStorage primary
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
static void Fill3DS_CRC(u32 d, char* data) {
|
||||
std::array<u8, 10> digits = {
|
||||
u8((d / 1000000000) % 100),
|
||||
u8((d / 100000000) % 10),
|
||||
u8((d / 10000000) % 10),
|
||||
u8((d / 1000000) % 10),
|
||||
u8((d / 100000) % 10),
|
||||
u8((d / 10000) % 10),
|
||||
u8((d / 1000) % 10),
|
||||
u8((d / 100) % 10),
|
||||
u8((d / 10) % 10),
|
||||
u8(d % 10),
|
||||
};
|
||||
// Normalize to retail values
|
||||
std::array<u8, 4> retail_digits = { 1, 4, 5, 7 };
|
||||
digits[0] = retail_digits[(d % 10) % 4];
|
||||
digits[1] = 0;
|
||||
//
|
||||
for (size_t i = 0; i < sizeof(digits); ++i)
|
||||
data[i] = char(digits[i] + '0');
|
||||
u8 sum_odd = 0, sum_even = 0;
|
||||
for (size_t i = 0; i < sizeof(digits); i += 2) {
|
||||
sum_odd += digits[i + 0];
|
||||
sum_even += digits[i + 1];
|
||||
}
|
||||
u8 sum_digit = u8(((sum_even * 3) + sum_odd) % 10);
|
||||
if (sum_digit != 0)
|
||||
sum_digit = 10 - sum_digit;
|
||||
data[sizeof(digits)] = char(sum_digit + '0');
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetBatteryLot(Out<BatteryLot> out_battery_lot) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
*out_battery_lot = {"YUZU0EMULATOR14022024"};
|
||||
if (auto const s = ::Settings::values.serial_battery.GetValue(); !s.empty()) {
|
||||
auto const max_size = out_battery_lot->lot_number.size();
|
||||
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
|
||||
std::copy(s.begin(), end, out_battery_lot->lot_number.begin());
|
||||
}
|
||||
*out_battery_lot = []{
|
||||
u32 d = ::Settings::values.serial_battery.GetValue();
|
||||
BatteryLot c{};
|
||||
c.lot_number[0] = 'B';
|
||||
c.lot_number[1] = 'H';
|
||||
c.lot_number[2] = 'A';
|
||||
c.lot_number[3] = 'C';
|
||||
// TODO: I have no fucking idea what the letters mean
|
||||
c.lot_number[4] = 'H';
|
||||
c.lot_number[5] = 'Z';
|
||||
c.lot_number[6] = 'Z';
|
||||
c.lot_number[7] = 'A';
|
||||
c.lot_number[8] = 'D';
|
||||
c.lot_number[9] = char(((d / 100000) % 26) + 'A');
|
||||
Fill3DS_CRC(d, c.lot_number.data() + 10);
|
||||
return c;
|
||||
}();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ISystemSettingsServer::GetSerialNumber(Out<SerialNumber> out_console_serial) {
|
||||
LOG_INFO(Service_SET, "called");
|
||||
*out_console_serial = {"YUZ10000000001"};
|
||||
if (auto const s = ::Settings::values.serial_unit.GetValue(); !s.empty()) {
|
||||
auto const max_size = out_console_serial->serial_number.size();
|
||||
auto const end = s.size() > max_size ? s.begin() + max_size : s.end();
|
||||
std::copy(s.begin(), end, out_console_serial->serial_number.begin());
|
||||
}
|
||||
*out_console_serial = []{
|
||||
u32 d = ::Settings::values.serial_unit.GetValue();
|
||||
SerialNumber c{};
|
||||
c.serial_number[0] = 'X';
|
||||
c.serial_number[1] = 'A';
|
||||
c.serial_number[2] = [] {
|
||||
// Adding another setting would be tedious so... let's just reuse region_index :)
|
||||
switch (::Settings::values.region_index.GetValue()) {
|
||||
case ::Settings::Region::Japan: return 'J';
|
||||
case ::Settings::Region::Usa: return 'W';
|
||||
case ::Settings::Region::Europe: return 'E';
|
||||
case ::Settings::Region::Australia: return 'M'; //pretend its Malaysia
|
||||
case ::Settings::Region::China:
|
||||
case ::Settings::Region::Taiwan: return 'C';
|
||||
case ::Settings::Region::Korea: return 'K';
|
||||
default: return 'W';
|
||||
}
|
||||
}();
|
||||
Fill3DS_CRC(d, c.serial_number.data() + 3);
|
||||
return c;
|
||||
}();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
|
|
@ -178,7 +178,7 @@ void LoopProcess(Core::System& system) {
|
|||
auto module = std::make_shared<Module>();
|
||||
|
||||
server_manager->RegisterNamedService("csrng", std::make_shared<CSRNG>(system, module));
|
||||
server_manager->RegisterNamedService("spl", std::make_shared<SPL>(system, module));
|
||||
server_manager->RegisterNamedService("spl:", std::make_shared<SPL>(system, module));
|
||||
server_manager->RegisterNamedService("spl:mig", std::make_shared<SPL_MIG>(system, module));
|
||||
server_manager->RegisterNamedService("spl:fs", std::make_shared<SPL_FS>(system, module));
|
||||
server_manager->RegisterNamedService("spl:ssl", std::make_shared<SPL_SSL>(system, module));
|
||||
|
|
|
|||
|
|
@ -36,10 +36,6 @@ oaknut::Label EmitA32Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
|
|||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void EmitA32Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -35,10 +35,6 @@ oaknut::Label EmitA64Cond(oaknut::CodeGenerator& code, EmitContext&, IR::Cond co
|
|||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void EmitA64Terminal(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
EmitRelocation(code, ctx, LinkTarget::ReturnToDispatcher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -114,10 +114,6 @@ void EmitA32Cond(biscuit::Assembler& as, EmitContext&, IR::Cond cond, biscuit::L
|
|||
|
||||
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::Terminal terminal, IR::LocationDescriptor initial_location, bool is_single_step);
|
||||
|
||||
void EmitA32Terminal(biscuit::Assembler&, EmitContext&, IR::Term::Interpret, IR::LocationDescriptor, bool) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void EmitA32Terminal(biscuit::Assembler& as, EmitContext& ctx, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
EmitRelocation(as, ctx, LinkTarget::ReturnFromRunCode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1135,19 +1135,6 @@ void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_locat
|
|||
}
|
||||
|
||||
namespace {
|
||||
void EmitTerminalImpl(A32EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor initial_location, bool) {
|
||||
ASSERT(A32::LocationDescriptor{terminal.next}.TFlag() == A32::LocationDescriptor{initial_location}.TFlag() && "Unimplemented");
|
||||
ASSERT(A32::LocationDescriptor{terminal.next}.EFlag() == A32::LocationDescriptor{initial_location}.EFlag() && "Unimplemented");
|
||||
ASSERT(terminal.num_instructions == 1 && "Unimplemented");
|
||||
|
||||
e.code.mov(e.code.ABI_PARAM2.cvt32(), A32::LocationDescriptor{terminal.next}.PC());
|
||||
e.code.mov(e.code.ABI_PARAM3.cvt32(), 1);
|
||||
e.code.mov(MJitStateReg(A32::Reg::PC), e.code.ABI_PARAM2.cvt32());
|
||||
e.code.SwitchMxcsrOnExit();
|
||||
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code);
|
||||
e.code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
||||
void EmitTerminalImpl(A32EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
e.code.ReturnFromRunCode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -619,16 +619,6 @@ std::string A64EmitX64::LocationDescriptorToFriendlyName(const IR::LocationDescr
|
|||
}
|
||||
|
||||
namespace {
|
||||
void EmitTerminalImpl(A64EmitX64& e, IR::Term::Interpret terminal, IR::LocationDescriptor, bool) {
|
||||
e.code.SwitchMxcsrOnExit();
|
||||
Devirtualize<&A64::UserCallbacks::InterpreterFallback>(e.conf.callbacks).EmitCall(e.code, [&](RegList param) {
|
||||
e.code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC());
|
||||
e.code.mov(qword[e.code.ABI_JIT_PTR + offsetof(A64JitState, pc)], param[0]);
|
||||
e.code.mov(param[1].cvt32(), terminal.num_instructions);
|
||||
});
|
||||
e.code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
||||
void EmitTerminalImpl(A64EmitX64& e, IR::Term::ReturnToDispatch, IR::LocationDescriptor, bool) {
|
||||
e.code.ReturnFromRunCode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -35,11 +35,6 @@ bool TranslatorVisitor::VFPConditionPassed(Cond cond) {
|
|||
return ArmConditionPassed(cond);
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::InterpretThisInstruction() {
|
||||
ir.SetTerm(IR::Term::Interpret(ir.current_location));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::UnpredictableInstruction() {
|
||||
return RaiseException(Exception::UnpredictableInstruction);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -39,7 +39,6 @@ struct TranslatorVisitor final {
|
|||
bool ThumbConditionPassed();
|
||||
bool VFPConditionPassed(Cond cond);
|
||||
|
||||
bool InterpretThisInstruction();
|
||||
bool UnpredictableInstruction();
|
||||
bool UndefinedInstruction();
|
||||
bool DecodeError();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -871,11 +871,11 @@ bool TranslatorVisitor::arm_LDMIB(Cond cond, bool W, Reg n, RegList list) {
|
|||
}
|
||||
|
||||
bool TranslatorVisitor::arm_LDM_usr() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::arm_LDM_eret() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, RegList list, IR::U32 start_address, IR::U32 writeback_address) {
|
||||
|
|
@ -956,7 +956,7 @@ bool TranslatorVisitor::arm_STMIB(Cond cond, bool W, Reg n, RegList list) {
|
|||
}
|
||||
|
||||
bool TranslatorVisitor::arm_STM_usr() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -15,7 +15,7 @@ namespace Dynarmic::A32 {
|
|||
// CPS<effect> <iflags>{, #<mode>}
|
||||
// CPS #<mode>
|
||||
bool TranslatorVisitor::arm_CPS() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// MRS<c> <Rd>, <spec_reg>
|
||||
|
|
@ -107,7 +107,7 @@ bool TranslatorVisitor::arm_MSR_reg(Cond cond, unsigned mask, Reg n) {
|
|||
|
||||
// RFE{<amode>} <Rn>{!}
|
||||
bool TranslatorVisitor::arm_RFE() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// SETEND <endian_specifier>
|
||||
|
|
@ -118,7 +118,7 @@ bool TranslatorVisitor::arm_SETEND(bool E) {
|
|||
|
||||
// SRS{<amode>} SP{!}, #<mode>
|
||||
bool TranslatorVisitor::arm_SRS() {
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -68,14 +68,16 @@ constexpr DecodeTable<V> GetDecodeTable() {
|
|||
return table;
|
||||
}
|
||||
|
||||
/// In practice it must always suceed, otherwise something else unrelated would have gone awry
|
||||
template<typename V>
|
||||
std::optional<std::reference_wrapper<const Matcher<V>>> Decode(u32 instruction) {
|
||||
std::reference_wrapper<const Matcher<V>> Decode(u32 instruction) {
|
||||
alignas(64) static const auto table = GetDecodeTable<V>();
|
||||
const auto& subtable = table[detail::ToFastLookupIndex(instruction)];
|
||||
auto iter = std::find_if(subtable.begin(), subtable.end(), [instruction](const auto& matcher) {
|
||||
return matcher.Matches(instruction);
|
||||
});
|
||||
return iter != subtable.end() ? std::optional<std::reference_wrapper<const Matcher<V>>>(*iter) : std::nullopt;
|
||||
DEBUG_ASSERT(iter != subtable.end());
|
||||
return std::reference_wrapper<const Matcher<V>>(*iter);
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
|
|
|
|||
|
|
@ -23,17 +23,12 @@ void Translate(IR::Block& block, LocationDescriptor descriptor, MemoryReadCodeFu
|
|||
bool should_continue = true;
|
||||
do {
|
||||
const u64 pc = visitor.ir.current_location->PC();
|
||||
|
||||
if (const auto instruction = memory_read_code(pc)) {
|
||||
if (auto decoder = Decode<TranslatorVisitor>(*instruction)) {
|
||||
should_continue = decoder->get().call(visitor, *instruction);
|
||||
} else {
|
||||
should_continue = visitor.InterpretThisInstruction();
|
||||
}
|
||||
auto decoder = Decode<TranslatorVisitor>(*instruction);
|
||||
should_continue = decoder.get().call(visitor, *instruction);
|
||||
} else {
|
||||
should_continue = visitor.RaiseException(Exception::NoExecuteFault);
|
||||
}
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
||||
block.CycleCount()++;
|
||||
} while (should_continue && !single_step);
|
||||
|
|
@ -49,11 +44,8 @@ bool TranslateSingleInstruction(IR::Block& block, LocationDescriptor descriptor,
|
|||
TranslatorVisitor visitor{block, descriptor, {}};
|
||||
|
||||
bool should_continue = true;
|
||||
if (auto decoder = Decode<TranslatorVisitor>(instruction)) {
|
||||
should_continue = decoder->get().call(visitor, instruction);
|
||||
} else {
|
||||
should_continue = visitor.InterpretThisInstruction();
|
||||
}
|
||||
auto const decoder = Decode<TranslatorVisitor>(instruction);
|
||||
should_continue = decoder.get().call(visitor, instruction);
|
||||
|
||||
visitor.ir.current_location = visitor.ir.current_location->AdvancePC(4);
|
||||
block.CycleCount()++;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -16,11 +16,6 @@
|
|||
|
||||
namespace Dynarmic::A64 {
|
||||
|
||||
bool TranslatorVisitor::InterpretThisInstruction() {
|
||||
ir.SetTerm(IR::Term::Interpret(*ir.current_location));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::UnpredictableInstruction() {
|
||||
return RaiseException(Exception::UnpredictableInstruction);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -24,7 +27,6 @@ struct TranslatorVisitor final {
|
|||
A64::IREmitter ir;
|
||||
TranslationOptions options;
|
||||
|
||||
bool InterpretThisInstruction();
|
||||
bool UnpredictableInstruction();
|
||||
bool DecodeError();
|
||||
bool ReservedValue();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -63,9 +66,7 @@ bool TranslatorVisitor::FCMLA_vec(bool Q, Imm<2> size, Vec Vm, Imm<2> rot, Vec V
|
|||
const size_t esize = 8U << size.ZeroExtend();
|
||||
|
||||
// TODO: Currently we don't support half-precision floating point
|
||||
if (esize == 16) {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
ASSERT(esize != 16);
|
||||
|
||||
const size_t datasize = Q ? 128 : 64;
|
||||
const size_t num_elements = datasize / esize;
|
||||
|
|
@ -134,9 +135,7 @@ bool TranslatorVisitor::FCADD_vec(bool Q, Imm<2> size, Vec Vm, Imm<1> rot, Vec V
|
|||
const size_t esize = 8U << size.ZeroExtend();
|
||||
|
||||
// TODO: Currently we don't support half-precision floating point
|
||||
if (esize == 16) {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
ASSERT(esize != 16);
|
||||
|
||||
const size_t datasize = Q ? 128 : 64;
|
||||
const size_t num_elements = datasize / esize;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -223,9 +223,7 @@ bool TranslatorVisitor::FCMLA_elt(bool Q, Imm<2> size, Imm<1> L, Imm<1> M, Imm<4
|
|||
const size_t esize = 8U << size.ZeroExtend();
|
||||
|
||||
// TODO: We don't support the half-precision floating point variant yet.
|
||||
if (esize == 16) {
|
||||
return InterpretThisInstruction();
|
||||
}
|
||||
ASSERT(esize != 16);
|
||||
|
||||
const size_t index = [=] {
|
||||
if (size == 0b01) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, I
|
|||
default:
|
||||
break;
|
||||
}
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
|
||||
|
|
@ -158,7 +158,7 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
|
|||
X(64, Rt, ir.GetTPIDRRO());
|
||||
return true;
|
||||
}
|
||||
return InterpretThisInstruction();
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A64
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -103,9 +103,6 @@ struct UserCallbacks : public TranslateCallbacks {
|
|||
// A conservative implementation that always returns false is safe.
|
||||
virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; }
|
||||
|
||||
/// The interpreter must execute exactly num_instructions starting from PC.
|
||||
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
|
||||
|
||||
// This callback is called whenever a SVC instruction is executed.
|
||||
virtual void CallSVC(std::uint32_t swi) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -118,9 +118,6 @@ struct UserCallbacks {
|
|||
// A conservative implementation that always returns false is safe.
|
||||
virtual bool IsReadOnlyMemory(VAddr /*vaddr*/) { return false; }
|
||||
|
||||
/// The interpreter must execute exactly num_instructions starting from PC.
|
||||
virtual void InterpreterFallback(VAddr pc, size_t num_instructions) = 0;
|
||||
|
||||
// This callback is called whenever a SVC instruction is executed.
|
||||
virtual void CallSVC(std::uint32_t swi) = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -77,9 +77,6 @@ static std::string TerminalToString(const Terminal& terminal_variant) noexcept {
|
|||
std::string operator()(const Term::Invalid&) const {
|
||||
return "<invalid terminal>";
|
||||
}
|
||||
std::string operator()(const Term::Interpret& terminal) const {
|
||||
return fmt::format("Interpret{{{}}}", terminal.next);
|
||||
}
|
||||
std::string operator()(const Term::ReturnToDispatch&) const {
|
||||
return "ReturnToDispatch{}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -638,43 +638,6 @@ static void A64GetSetElimination(IR::Block& block) {
|
|||
}
|
||||
}
|
||||
|
||||
static void A64MergeInterpretBlocksPass(IR::Block& block, A64::UserCallbacks* cb) {
|
||||
const auto is_interpret_instruction = [cb](A64::LocationDescriptor location) {
|
||||
const auto instruction = cb->MemoryReadCode(location.PC());
|
||||
if (!instruction)
|
||||
return false;
|
||||
|
||||
IR::Block new_block{location};
|
||||
A64::TranslateSingleInstruction(new_block, location, *instruction);
|
||||
|
||||
if (!new_block.Instructions().empty())
|
||||
return false;
|
||||
|
||||
const IR::Terminal terminal = new_block.GetTerminal();
|
||||
if (auto term = boost::get<IR::Term::Interpret>(&terminal)) {
|
||||
return term->next == location;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
IR::Terminal terminal = block.GetTerminal();
|
||||
auto term = boost::get<IR::Term::Interpret>(&terminal);
|
||||
if (!term)
|
||||
return;
|
||||
|
||||
A64::LocationDescriptor location{term->next};
|
||||
size_t num_instructions = 1;
|
||||
|
||||
while (is_interpret_instruction(location.AdvancePC(static_cast<int>(num_instructions * 4)))) {
|
||||
num_instructions++;
|
||||
}
|
||||
|
||||
term->num_instructions = num_instructions;
|
||||
block.ReplaceTerminal(terminal);
|
||||
block.CycleCount() += num_instructions - 1;
|
||||
}
|
||||
|
||||
using Op = Dynarmic::IR::Opcode;
|
||||
|
||||
static IR::Value Value(bool is_32_bit, u64 value) {
|
||||
|
|
@ -1504,9 +1467,6 @@ void Optimize(IR::Block& block, const A64::UserConfig& conf, const Optimization:
|
|||
Optimization::ConstantPropagation(block);
|
||||
Optimization::DeadCodeElimination(block);
|
||||
}
|
||||
if (conf.HasOptimization(OptimizationFlag::MiscIROpt)) {
|
||||
Optimization::A64MergeInterpretBlocksPass(block, conf.callbacks);
|
||||
}
|
||||
Optimization::IdentityRemovalPass(block);
|
||||
if (!conf.HasOptimization(OptimizationFlag::DisableVerification)) {
|
||||
Optimization::VerificationPass(block);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -19,17 +19,6 @@ namespace Term {
|
|||
|
||||
struct Invalid {};
|
||||
|
||||
/**
|
||||
* This terminal instruction calls the interpreter, starting at `next`.
|
||||
* The interpreter must interpret exactly `num_instructions` instructions.
|
||||
*/
|
||||
struct Interpret {
|
||||
explicit Interpret(const LocationDescriptor& next_)
|
||||
: next(next_) {}
|
||||
LocationDescriptor next; ///< Location at which interpretation starts.
|
||||
size_t num_instructions = 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* This terminal instruction returns control to the dispatcher.
|
||||
* The dispatcher will use the current cpu state to determine what comes next.
|
||||
|
|
@ -83,7 +72,6 @@ struct CheckHalt;
|
|||
/// A Terminal is the terminal instruction in a MicroBlock.
|
||||
using Terminal = boost::variant<
|
||||
Invalid,
|
||||
Interpret,
|
||||
ReturnToDispatch,
|
||||
LinkBlock,
|
||||
LinkBlockFast,
|
||||
|
|
|
|||
|
|
@ -59,8 +59,6 @@ bool AnyLocationDescriptorForTerminalHas(IR::Terminal terminal, Fn fn) {
|
|||
return fn(t.next);
|
||||
} else if constexpr (std::is_same_v<T, IR::Term::PopRSBHint>) {
|
||||
return false;
|
||||
} else if constexpr (std::is_same_v<T, IR::Term::Interpret>) {
|
||||
return fn(t.next);
|
||||
} else if constexpr (std::is_same_v<T, IR::Term::FastDispatchHint>) {
|
||||
return false;
|
||||
} else if constexpr (std::is_same_v<T, IR::Term::If>) {
|
||||
|
|
@ -85,10 +83,6 @@ bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A
|
|||
return false;
|
||||
}
|
||||
|
||||
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AnyLocationDescriptorForTerminalHas(block.GetTerminal(), [&](IR::LocationDescriptor ld) { return A32::LocationDescriptor{ld}.PC() <= pc; })) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -97,10 +97,6 @@ public:
|
|||
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions) override {
|
||||
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:08x} && {}) code = {:08x}", pc, num_instructions, *MemoryReadCode(pc));
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
|
||||
}
|
||||
|
|
@ -190,10 +186,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void InterpreterFallback(std::uint32_t pc, size_t num_instructions) override {
|
||||
UNREACHABLE(); //ASSERT(false && "InterpreterFallback({:016x} && {})", pc, num_instructions);
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,11 +69,6 @@ public:
|
|||
MemoryWrite64(vaddr + 8, value[1]);
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64, size_t) override {
|
||||
// This is never called in practice.
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
void CallSVC(u32) override {
|
||||
// Do something.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ static bool ShouldTestInst(u32 instruction, u64 pc, bool is_last_inst) {
|
|||
bool should_continue = A64::TranslateSingleInstruction(block, location, instruction);
|
||||
if (!should_continue && !is_last_inst)
|
||||
return false;
|
||||
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal))
|
||||
return false;
|
||||
for (const auto& ir_inst : block.instructions) {
|
||||
switch (ir_inst.GetOpcode()) {
|
||||
case IR::Opcode::A64ExceptionRaised:
|
||||
|
|
|
|||
|
|
@ -105,10 +105,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, size_t num_instructions) override {
|
||||
UNREACHABLE(); // ASSERT(false&& "InterpreterFallback({:016x} && {})", pc, num_instructions);
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
|
||||
}
|
||||
|
|
@ -208,10 +204,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
void InterpreterFallback(u64 pc, size_t num_instructions) override {
|
||||
ASSERT(ignore_invalid_insn && "InterpreterFallback");
|
||||
}
|
||||
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
UNREACHABLE(); //ASSERT(false && "CallSVC({})", swi);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
|
|
@ -153,9 +153,6 @@ public:
|
|||
MemoryWrite32(vaddr + 4, static_cast<u32>(value >> 32));
|
||||
}
|
||||
|
||||
void InterpreterFallback(u32 pc, size_t num_instructions) override {
|
||||
fmt::print("> InterpreterFallback({:08x}, {}) code = {:08x}\n", pc, num_instructions, *MemoryReadCode(pc));
|
||||
}
|
||||
void CallSVC(std::uint32_t swi) override {
|
||||
fmt::print("> CallSVC({})\n", swi);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,10 +50,6 @@ namespace {
|
|||
using namespace Dynarmic;
|
||||
|
||||
bool ShouldTestInst(IR::Block& block) {
|
||||
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& ir_inst : block.instructions) {
|
||||
switch (ir_inst.GetOpcode()) {
|
||||
// A32
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@ namespace FrontendCommon {
|
|||
void GenerateSettings() {
|
||||
static std::random_device rd;
|
||||
|
||||
// Web Token //
|
||||
auto &token_setting = Settings::values.eden_token;
|
||||
if (token_setting.GetValue().empty()) {
|
||||
// Web Token
|
||||
if (Settings::values.eden_token.GetValue().empty()) {
|
||||
static constexpr const size_t token_length = 48;
|
||||
static constexpr const frozen::string token_set = "abcdefghijklmnopqrstuvwxyz";
|
||||
static std::uniform_int_distribution<int> token_dist(0, token_set.size() - 1);
|
||||
|
|
@ -23,9 +22,18 @@ void GenerateSettings() {
|
|||
size_t idx = token_dist(rd);
|
||||
result += token_set[idx];
|
||||
}
|
||||
|
||||
token_setting.SetValue(result);
|
||||
Settings::values.eden_token.SetValue(result);
|
||||
}
|
||||
|
||||
// Randomly generated number because, well, we fill the rest automagically ;)
|
||||
// Other serial parts are filled by Region_Index
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u32> distribution(1, (std::numeric_limits<u32>::max)());
|
||||
if (Settings::values.serial_unit.GetValue() == 0)
|
||||
Settings::values.serial_unit.SetValue(distribution(gen));
|
||||
if (Settings::values.serial_battery.GetValue() == 0)
|
||||
Settings::values.serial_battery.SetValue(distribution(gen));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -517,8 +517,8 @@ std::unique_ptr<ComboboxTranslationMap> ComboboxEnumeration(QObject* parent)
|
|||
PAIR(FramePacingMode, Target_Auto, tr("Auto")),
|
||||
PAIR(FramePacingMode, Target_30, tr("30 FPS")),
|
||||
PAIR(FramePacingMode, Target_60, tr("60 FPS")),
|
||||
PAIR(FramePacingMode, Target_90, tr("90 FPS")),
|
||||
PAIR(FramePacingMode, Target_120, tr("120 FPS")),
|
||||
PAIR(FramePacingMode, Target_240, tr("240 FPS")),
|
||||
}});
|
||||
translations->insert({Settings::EnumMetadata<Settings::VramUsageMode>::Index(),
|
||||
{
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ void Scheduler::EndRenderPass()
|
|||
Record([num_images = num_renderpass_images,
|
||||
images = renderpass_images,
|
||||
ranges = renderpass_image_ranges](vk::CommandBuffer cmdbuf) {
|
||||
std::vector<VkImageMemoryBarrier> barriers(num_images);
|
||||
std::array<VkImageMemoryBarrier, 9> barriers;
|
||||
VkPipelineStageFlags src_stages = 0;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
const VkImageSubresourceRange& range = ranges[i];
|
||||
|
|
|
|||
|
|
@ -115,28 +115,27 @@ public:
|
|||
/// Waits for the given GPU tick, optionally pacing frames.
|
||||
void Wait(u64 tick, double target_fps = 0.0) {
|
||||
if (Settings::values.use_speed_limit.GetValue() && target_fps > 0.0) {
|
||||
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (now < next_frame_time) {
|
||||
std::this_thread::sleep_until(next_frame_time);
|
||||
next_frame_time += frame_duration;
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
if (start_time == std::chrono::steady_clock::time_point{} || current_target_fps != target_fps) {
|
||||
start_time = now;
|
||||
frame_counter = 0;
|
||||
current_target_fps = target_fps;
|
||||
}
|
||||
frame_counter++;
|
||||
std::chrono::duration<double> frame_interval(1.0 / current_target_fps);
|
||||
auto target_time = start_time + frame_interval * frame_counter;
|
||||
if (target_time > now) {
|
||||
std::this_thread::sleep_until(target_time);
|
||||
} else {
|
||||
next_frame_time = now + frame_duration;
|
||||
start_time = now;
|
||||
frame_counter = 0;
|
||||
}
|
||||
}
|
||||
if (tick > master_semaphore->CurrentTick() && !chunk->Empty()) {
|
||||
Flush();
|
||||
}
|
||||
master_semaphore->Wait(tick);
|
||||
}
|
||||
|
||||
/// Resets the frame pacing state by setting the next frame time.
|
||||
void ResetFramePacing(double target_fps = 0.0) {
|
||||
if (target_fps > 0.0) {
|
||||
auto frame_duration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(1.0 / target_fps));
|
||||
next_frame_time = std::chrono::steady_clock::now() + frame_duration;
|
||||
} else {
|
||||
next_frame_time = std::chrono::steady_clock::time_point{};
|
||||
if (tick > 0) {
|
||||
if (tick >= master_semaphore->CurrentTick()) {
|
||||
Flush();
|
||||
}
|
||||
master_semaphore->Wait(tick);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,7 +281,9 @@ private:
|
|||
std::condition_variable_any event_cv;
|
||||
std::jthread worker_thread;
|
||||
|
||||
std::chrono::steady_clock::time_point next_frame_time{};
|
||||
std::chrono::steady_clock::time_point start_time{};
|
||||
u64 frame_counter{};
|
||||
double current_target_fps{};
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
|
|
|||
|
|
@ -146,25 +146,6 @@ void Swapchain::Create(
|
|||
{
|
||||
is_outdated = false;
|
||||
is_suboptimal = false;
|
||||
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.ResetFramePacing();
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.ResetFramePacing(30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.ResetFramePacing(60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.ResetFramePacing(120.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_240:
|
||||
scheduler.ResetFramePacing(240.0);
|
||||
break;
|
||||
}
|
||||
|
||||
width = width_;
|
||||
height = height_;
|
||||
#ifdef ANDROID
|
||||
|
|
@ -213,24 +194,22 @@ bool Swapchain::AcquireNextImage() {
|
|||
break;
|
||||
}
|
||||
|
||||
if (resource_ticks[image_index] != 0 && !scheduler.IsFree(resource_ticks[image_index])) {
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.Wait(resource_ticks[image_index], 30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.Wait(resource_ticks[image_index], 60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.Wait(resource_ticks[image_index], 120.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_240:
|
||||
scheduler.Wait(resource_ticks[image_index], 240.0);
|
||||
break;
|
||||
}
|
||||
switch (Settings::values.frame_pacing_mode.GetValue()) {
|
||||
case Settings::FramePacingMode::Target_Auto:
|
||||
scheduler.Wait(resource_ticks[image_index]);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_30:
|
||||
scheduler.Wait(resource_ticks[image_index], 30.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_60:
|
||||
scheduler.Wait(resource_ticks[image_index], 60.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_90:
|
||||
scheduler.Wait(resource_ticks[image_index], 90.0);
|
||||
break;
|
||||
case Settings::FramePacingMode::Target_120:
|
||||
scheduler.Wait(resource_ticks[image_index], 120.0);
|
||||
break;
|
||||
}
|
||||
|
||||
resource_ticks[image_index] = scheduler.CurrentTick();
|
||||
|
|
|
|||
|
|
@ -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-FileCopyrightText: 2016 Citra Emulator Project
|
||||
|
|
@ -57,10 +57,6 @@ void ConfigureDebug::SetConfiguration() {
|
|||
#endif
|
||||
|
||||
// Immutable after starting
|
||||
ui->serial_battery_edit->setEnabled(runtime_lock);
|
||||
ui->serial_battery_edit->setText(QString::fromStdString(Settings::values.serial_battery.GetValue()));
|
||||
ui->serial_board_edit->setEnabled(runtime_lock);
|
||||
ui->serial_board_edit->setText(QString::fromStdString(Settings::values.serial_unit.GetValue()));
|
||||
ui->homebrew_args_edit->setEnabled(runtime_lock);
|
||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args.GetValue()));
|
||||
ui->toggle_console->setEnabled(runtime_lock);
|
||||
|
|
|
|||
Loading…
Reference in New Issue