aboutsummaryrefslogtreecommitdiff
path: root/externals/dynarmic/src/dynarmic/interface/A32/config.h
diff options
context:
space:
mode:
Diffstat (limited to 'externals/dynarmic/src/dynarmic/interface/A32/config.h')
-rw-r--r--externals/dynarmic/src/dynarmic/interface/A32/config.h246
1 files changed, 246 insertions, 0 deletions
diff --git a/externals/dynarmic/src/dynarmic/interface/A32/config.h b/externals/dynarmic/src/dynarmic/interface/A32/config.h
new file mode 100644
index 0000000000..a3c2aa159c
--- /dev/null
+++ b/externals/dynarmic/src/dynarmic/interface/A32/config.h
@@ -0,0 +1,246 @@
+/* This file is part of the dynarmic project.
+ * Copyright (c) 2016 MerryMage
+ * SPDX-License-Identifier: 0BSD
+ */
+
+#pragma once
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+#include "dynarmic/frontend/A32/translate/translate_callbacks.h"
+#include "dynarmic/interface/A32/arch_version.h"
+#include "dynarmic/interface/optimization_flags.h"
+
+namespace Dynarmic {
+class ExclusiveMonitor;
+} // namespace Dynarmic
+
+namespace Dynarmic {
+namespace A32 {
+
+using VAddr = std::uint32_t;
+
+class Coprocessor;
+
+enum class Exception {
+ /// An UndefinedFault occured due to executing instruction with an unallocated encoding
+ UndefinedInstruction,
+ /// An unpredictable instruction is to be executed. Implementation-defined behaviour should now happen.
+ /// This behaviour is up to the user of this library to define.
+ UnpredictableInstruction,
+ /// A decode error occurred when decoding this instruction. This should never happen.
+ DecodeError,
+ /// A SEV instruction was executed. The event register of all PEs should be set. (Hint instruction.)
+ SendEvent,
+ /// A SEVL instruction was executed. The event register of the current PE should be set. (Hint instruction.)
+ SendEventLocal,
+ /// A WFI instruction was executed. You may now enter a low-power state. (Hint instruction.)
+ WaitForInterrupt,
+ /// A WFE instruction was executed. You may now enter a low-power state if the event register is clear. (Hint instruction.)
+ WaitForEvent,
+ /// A YIELD instruction was executed. (Hint instruction.)
+ Yield,
+ /// A BKPT instruction was executed.
+ Breakpoint,
+ /// A PLD instruction was executed. (Hint instruction.)
+ PreloadData,
+ /// A PLDW instruction was executed. (Hint instruction.)
+ PreloadDataWithIntentToWrite,
+ /// A PLI instruction was executed. (Hint instruction.)
+ PreloadInstruction,
+ /// Attempted to execute a code block at an address for which MemoryReadCode returned std::nullopt.
+ /// (Intended to be used to emulate memory protection faults.)
+ NoExecuteFault,
+};
+
+/// These function pointers may be inserted into compiled code.
+struct UserCallbacks : public TranslateCallbacks {
+ virtual ~UserCallbacks() = default;
+
+ // All reads through this callback are 4-byte aligned.
+ // Memory must be interpreted as little endian.
+ std::optional<std::uint32_t> MemoryReadCode(VAddr vaddr) override { return MemoryRead32(vaddr); }
+
+ // This function is called before the instruction at pc is read.
+ // IR code can be emitted by the callee prior to instruction handling.
+ // By returning true the callee precludes the translation of the instruction;
+ // in such case the callee is responsible for setting the terminal.
+ bool PreCodeReadHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override { return true; }
+
+ // Thus function is called before the instruction at pc is interpreted.
+ // IR code can be emitted by the callee prior to translation of the instruction.
+ void PreCodeTranslationHook(bool /*is_thumb*/, VAddr /*pc*/, A32::IREmitter& /*ir*/) override {}
+
+ // Reads through these callbacks may not be aligned.
+ // Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT.
+ virtual std::uint8_t MemoryRead8(VAddr vaddr) = 0;
+ virtual std::uint16_t MemoryRead16(VAddr vaddr) = 0;
+ virtual std::uint32_t MemoryRead32(VAddr vaddr) = 0;
+ virtual std::uint64_t MemoryRead64(VAddr vaddr) = 0;
+
+ // Writes through these callbacks may not be aligned.
+ virtual void MemoryWrite8(VAddr vaddr, std::uint8_t value) = 0;
+ virtual void MemoryWrite16(VAddr vaddr, std::uint16_t value) = 0;
+ virtual void MemoryWrite32(VAddr vaddr, std::uint32_t value) = 0;
+ virtual void MemoryWrite64(VAddr vaddr, std::uint64_t value) = 0;
+
+ // Writes through these callbacks may not be aligned.
+ virtual bool MemoryWriteExclusive8(VAddr /*vaddr*/, std::uint8_t /*value*/, std::uint8_t /*expected*/) { return false; }
+ virtual bool MemoryWriteExclusive16(VAddr /*vaddr*/, std::uint16_t /*value*/, std::uint16_t /*expected*/) { return false; }
+ virtual bool MemoryWriteExclusive32(VAddr /*vaddr*/, std::uint32_t /*value*/, std::uint32_t /*expected*/) { return false; }
+ virtual bool MemoryWriteExclusive64(VAddr /*vaddr*/, std::uint64_t /*value*/, std::uint64_t /*expected*/) { return false; }
+
+ // If this callback returns true, the JIT will assume MemoryRead* callbacks will always
+ // return the same value at any point in time for this vaddr. The JIT may use this information
+ // in optimizations.
+ // 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;
+
+ virtual void ExceptionRaised(VAddr pc, Exception exception) = 0;
+
+ virtual void InstructionSynchronizationBarrierRaised() {}
+
+ // Timing-related callbacks
+ // ticks ticks have passed
+ virtual void AddTicks(std::uint64_t ticks) = 0;
+ // How many more ticks am I allowed to execute?
+ virtual std::uint64_t GetTicksRemaining() = 0;
+ // How many ticks should this instruction take to execute?
+ std::uint64_t GetTicksForCode(bool /*is_thumb*/, VAddr /*vaddr*/, std::uint32_t /*instruction*/) override { return 1; }
+};
+
+struct UserConfig {
+ UserCallbacks* callbacks;
+
+ size_t processor_id = 0;
+ ExclusiveMonitor* global_monitor = nullptr;
+
+ /// Select the architecture version to use.
+ /// There are minor behavioural differences between versions.
+ ArchVersion arch_version = ArchVersion::v8;
+
+ /// This selects other optimizations than can't otherwise be disabled by setting other
+ /// configuration options. This includes:
+ /// - IR optimizations
+ /// - Block linking optimizations
+ /// - RSB optimizations
+ /// This is intended to be used for debugging.
+ OptimizationFlag optimizations = all_safe_optimizations;
+
+ bool HasOptimization(OptimizationFlag f) const {
+ if (!unsafe_optimizations) {
+ f &= all_safe_optimizations;
+ }
+ return (f & optimizations) != no_optimizations;
+ }
+
+ /// This enables unsafe optimizations that reduce emulation accuracy in favour of speed.
+ /// For safety, in order to enable unsafe optimizations you have to set BOTH this flag
+ /// AND the appropriate flag bits above.
+ /// The prefered and tested mode for this library is with unsafe optimizations disabled.
+ bool unsafe_optimizations = false;
+
+ // Page Table
+ // The page table is used for faster memory access. If an entry in the table is nullptr,
+ // the JIT will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
+ static constexpr std::size_t PAGE_BITS = 12;
+ static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS);
+ std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>* page_table = nullptr;
+ /// Determines if the pointer in the page_table shall be offseted locally or globally.
+ /// 'false' will access page_table[addr >> bits][addr & mask]
+ /// 'true' will access page_table[addr >> bits][addr]
+ /// Note: page_table[addr >> bits] will still be checked to verify active pages.
+ /// So there might be wrongly faulted pages which maps to nullptr.
+ /// This can be avoided by carefully allocating the memory region.
+ bool absolute_offset_page_table = false;
+ /// Masks out the first N bits in host pointers from the page table.
+ /// The intention behind this is to allow users of Dynarmic to pack attributes in the
+ /// same integer and update the pointer attribute pair atomically.
+ /// If the configured value is 3, all pointers will be forcefully aligned to 8 bytes.
+ int page_table_pointer_mask_bits = 0;
+ /// Determines if we should detect memory accesses via page_table that straddle are
+ /// misaligned. Accesses that straddle page boundaries will fallback to the relevant
+ /// memory callback.
+ /// This value should be the required access sizes this applies to ORed together.
+ /// To detect any access, use: 8 | 16 | 32 | 64.
+ std::uint8_t detect_misaligned_access_via_page_table = 0;
+ /// Determines if the above option only triggers when the misalignment straddles a
+ /// page boundary.
+ bool only_detect_misalignment_via_page_table_on_page_boundary = false;
+
+ // Fastmem Pointer
+ // This should point to the beginning of a 4GB address space which is in arranged just like
+ // what you wish for emulated memory to be. If the host page faults on an address, the JIT
+ // will fallback to calling the MemoryRead*/MemoryWrite* callbacks.
+ void* fastmem_pointer = nullptr;
+ /// Determines if instructions that pagefault should cause recompilation of that block
+ /// with fastmem disabled.
+ /// Recompiled code will use the page_table if this is available, otherwise memory
+ /// accesses will hit the memory callbacks.
+ bool recompile_on_fastmem_failure = true;
+
+ /// Determines if we should use the above fastmem_pointer for exclusive reads and
+ /// writes. On x64, dynarmic currently relies on x64 cmpxchg semantics which may not
+ /// provide fully accurate emulation.
+ bool fastmem_exclusive_access = false;
+ /// Determines if exclusive access instructions that pagefault should cause
+ /// recompilation of that block with fastmem disabled. Recompiled code will use memory
+ /// callbacks.
+ bool recompile_on_exclusive_fastmem_failure = true;
+
+ // Coprocessors
+ std::array<std::shared_ptr<Coprocessor>, 16> coprocessors{};
+
+ /// When set to true, UserCallbacks::InstructionSynchronizationBarrierRaised will be
+ /// called when an ISB instruction is executed.
+ /// When set to false, ISB will be treated as a NOP instruction.
+ bool hook_isb = false;
+
+ /// Hint instructions would cause ExceptionRaised to be called with the appropriate
+ /// argument.
+ bool hook_hint_instructions = false;
+
+ /// This option relates to translation. Generally when we run into an unpredictable
+ /// instruction the ExceptionRaised callback is called. If this is true, we define
+ /// definite behaviour for some unpredictable instructions.
+ bool define_unpredictable_behaviour = false;
+
+ /// HACK:
+ /// 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 allows accurately emulating protection fault handlers. If true, we check
+ /// for exit after every data memory access by the emulated program.
+ bool check_halt_on_memory_access = false;
+
+ /// This option allows you to disable cycle counting. If this is set to false,
+ /// AddTicks and GetTicksRemaining are never called, and no cycle counting is done.
+ bool enable_cycle_counting = true;
+
+ /// This option relates to the CPSR.E flag. Enabling this option disables modification
+ /// of CPSR.E by the emulated program, forcing it to 0.
+ /// NOTE: Calling Jit::SetCpsr with CPSR.E=1 while this option is enabled may result
+ /// in unusual behavior.
+ bool always_little_endian = false;
+
+ // Minimum size is about 8MiB. Maximum size is about 128MiB (arm64 host) or 2GiB (x64 host).
+ // Maximum size is limited by the maximum length of a x86_64 / arm64 jump.
+ size_t code_cache_size = 128 * 1024 * 1024; // bytes
+
+ /// Internal use only
+ bool very_verbose_debugging_output = false;
+};
+
+} // namespace A32
+} // namespace Dynarmic