Backend/A64: Add Dolphin's ARM emitter
This commit is contained in:
parent
78653d475e
commit
71d1f55eec
@ -325,6 +325,13 @@ if (ARCHITECTURE_x86_64)
|
|||||||
else()
|
else()
|
||||||
target_sources(dynarmic PRIVATE backend/x64/exception_handler_generic.cpp)
|
target_sources(dynarmic PRIVATE backend/x64/exception_handler_generic.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
elseif(ARCHITECTURE_Aarch64)
|
||||||
|
target_sources(dynarmic PRIVATE
|
||||||
|
backend/A64/emitter/a64_emitter.cpp
|
||||||
|
backend/A64/emitter/a64_emitter.h
|
||||||
|
backend/A64/emitter/arm_common.h
|
||||||
|
backend/A64/emitter/code_block.h
|
||||||
|
)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Unsupported architecture")
|
message(FATAL_ERROR "Unsupported architecture")
|
||||||
endif()
|
endif()
|
||||||
|
3726
src/backend/A64/emitter/a64_emitter.cpp
Normal file
3726
src/backend/A64/emitter/a64_emitter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1128
src/backend/A64/emitter/a64_emitter.h
Normal file
1128
src/backend/A64/emitter/a64_emitter.h
Normal file
File diff suppressed because it is too large
Load Diff
28
src/backend/A64/emitter/arm_common.h
Normal file
28
src/backend/A64/emitter/arm_common.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project / 2018 dynarmic project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Dynarmic::BackendA64 {
|
||||||
|
enum CCFlags {
|
||||||
|
CC_EQ = 0, // Equal
|
||||||
|
CC_NEQ, // Not equal
|
||||||
|
CC_CS, // Carry Set
|
||||||
|
CC_CC, // Carry Clear
|
||||||
|
CC_MI, // Minus (Negative)
|
||||||
|
CC_PL, // Plus
|
||||||
|
CC_VS, // Overflow
|
||||||
|
CC_VC, // No Overflow
|
||||||
|
CC_HI, // Unsigned higher
|
||||||
|
CC_LS, // Unsigned lower or same
|
||||||
|
CC_GE, // Signed greater than or equal
|
||||||
|
CC_LT, // Signed less than
|
||||||
|
CC_GT, // Signed greater than
|
||||||
|
CC_LE, // Signed less than or equal
|
||||||
|
CC_AL, // Always (unconditional) 14
|
||||||
|
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
|
||||||
|
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
|
||||||
|
};
|
||||||
|
const u32 NO_COND = 0xE0000000;
|
||||||
|
} // namespace Dynarmic::BackendA64
|
126
src/backend/A64/emitter/code_block.h
Normal file
126
src/backend/A64/emitter/code_block.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2014 Dolphin Emulator Project / 2018 dynarmic project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Dynarmic::BackendA64 {
|
||||||
|
// Everything that needs to generate code should inherit from this.
|
||||||
|
// You get memory management for free, plus, you can use all emitter functions
|
||||||
|
// without having to prefix them with gen-> or something similar. Example
|
||||||
|
// implementation: class JIT : public CodeBlock<ARMXEmitter> {}
|
||||||
|
template <class T>
|
||||||
|
class CodeBlock : public T {
|
||||||
|
private:
|
||||||
|
// A privately used function to set the executable RAM space to something
|
||||||
|
// invalid. For debugging usefulness it should be used to set the RAM to a
|
||||||
|
// host specific breakpoint instruction
|
||||||
|
virtual void PoisonMemory() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
u8* region = nullptr;
|
||||||
|
// Size of region we can use.
|
||||||
|
size_t region_size = 0;
|
||||||
|
// Original size of the region we allocated.
|
||||||
|
size_t total_region_size = 0;
|
||||||
|
|
||||||
|
bool m_is_child = false;
|
||||||
|
std::vector<CodeBlock*> m_children;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CodeBlock() = default;
|
||||||
|
virtual ~CodeBlock() {
|
||||||
|
if (region)
|
||||||
|
FreeCodeSpace();
|
||||||
|
}
|
||||||
|
CodeBlock(const CodeBlock&) = delete;
|
||||||
|
CodeBlock& operator=(const CodeBlock&) = delete;
|
||||||
|
CodeBlock(CodeBlock&&) = delete;
|
||||||
|
CodeBlock& operator=(CodeBlock&&) = delete;
|
||||||
|
|
||||||
|
// Call this before you generate any code.
|
||||||
|
void AllocCodeSpace(size_t size) {
|
||||||
|
region_size = size;
|
||||||
|
total_region_size = size;
|
||||||
|
void* ptr =
|
||||||
|
mmap(nullptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
|
if (ptr == MAP_FAILED)
|
||||||
|
ptr = nullptr;
|
||||||
|
region = static_cast<u8*>(ptr);
|
||||||
|
T::SetCodePtr(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always clear code space with breakpoints, so that if someone accidentally
|
||||||
|
// executes uninitialized, it just breaks into the debugger.
|
||||||
|
void ClearCodeSpace() {
|
||||||
|
PoisonMemory();
|
||||||
|
ResetCodePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call this when shutting down. Don't rely on the destructor, even though
|
||||||
|
// it'll do the job.
|
||||||
|
void FreeCodeSpace() {
|
||||||
|
ASSERT(!m_is_child);
|
||||||
|
ASSERT(munmap(region, total_region_size) != 0);
|
||||||
|
region = nullptr;
|
||||||
|
region_size = 0;
|
||||||
|
total_region_size = 0;
|
||||||
|
for (CodeBlock* child : m_children) {
|
||||||
|
child->region = nullptr;
|
||||||
|
child->region_size = 0;
|
||||||
|
child->total_region_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInSpace(const u8* ptr) const {
|
||||||
|
return ptr >= region && ptr < (region + region_size);
|
||||||
|
}
|
||||||
|
// Cannot currently be undone. Will write protect the entire code region.
|
||||||
|
// Start over if you need to change the code (call FreeCodeSpace(),
|
||||||
|
// AllocCodeSpace()).
|
||||||
|
void WriteProtect() {
|
||||||
|
ASSERT(mprotect(region, region_size, PROT_READ | PROT_EXEC) != 0);
|
||||||
|
}
|
||||||
|
void ResetCodePtr() {
|
||||||
|
T::SetCodePtr(region);
|
||||||
|
}
|
||||||
|
size_t GetSpaceLeft() const {
|
||||||
|
ASSERT(static_cast<size_t>(T::GetCodePtr() - region) < region_size);
|
||||||
|
return region_size - (T::GetCodePtr() - region);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsAlmostFull() const {
|
||||||
|
// This should be bigger than the biggest block ever.
|
||||||
|
return GetSpaceLeft() < 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasChildren() const {
|
||||||
|
return region_size != total_region_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* AllocChildCodeSpace(size_t child_size) {
|
||||||
|
ASSERT_MSG(child_size < GetSpaceLeft(), "Insufficient space for child allocation.");
|
||||||
|
u8* child_region = region + region_size - child_size;
|
||||||
|
region_size -= child_size;
|
||||||
|
return child_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddChildCodeSpace(CodeBlock* child, size_t child_size) {
|
||||||
|
u8* child_region = AllocChildCodeSpace(child_size);
|
||||||
|
child->m_is_child = true;
|
||||||
|
child->region = child_region;
|
||||||
|
child->region_size = child_size;
|
||||||
|
child->total_region_size = child_size;
|
||||||
|
child->ResetCodePtr();
|
||||||
|
m_children.emplace_back(child);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Dynarmic::BackendA64
|
@ -44,4 +44,9 @@ u8 RecipEstimate(u64 a);
|
|||||||
*/
|
*/
|
||||||
u8 RecipSqrtEstimate(u64 a);
|
u8 RecipSqrtEstimate(u64 a);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool IsPow2(T imm){
|
||||||
|
return imm > 0 && (imm & (imm - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Dynarmic::Common
|
} // namespace Dynarmic::Common
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
* SPDX-License-Identifier: 0BSD
|
* SPDX-License-Identifier: 0BSD
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "frontend/A64/translate/impl/impl.h"
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "frontend/ir/terminal.h"
|
#include "frontend/ir/terminal.h"
|
||||||
#include "frontend/A64/translate/impl/impl.h"
|
|
||||||
|
|
||||||
namespace Dynarmic::A64 {
|
namespace Dynarmic::A64 {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user