Label A32 specific code appropriately
This commit is contained in:
parent
89e9ce8aff
commit
b3c73e2622
58 changed files with 938 additions and 831 deletions
|
@ -21,7 +21,7 @@ class Coprocessor {
|
||||||
public:
|
public:
|
||||||
virtual ~Coprocessor() = default;
|
virtual ~Coprocessor() = default;
|
||||||
|
|
||||||
using CoprocReg = Arm::CoprocReg;
|
using CoprocReg = A32::CoprocReg;
|
||||||
|
|
||||||
struct Callback {
|
struct Callback {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
enum class CoprocReg {
|
enum class CoprocReg {
|
||||||
C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15
|
C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
|
@ -1,39 +1,4 @@
|
||||||
add_library(dynarmic
|
add_library(dynarmic
|
||||||
# Source files
|
|
||||||
common/memory_pool.cpp
|
|
||||||
frontend/arm/types.cpp
|
|
||||||
frontend/disassembler/disassembler_arm.cpp
|
|
||||||
frontend/disassembler/disassembler_thumb.cpp
|
|
||||||
frontend/ir/basic_block.cpp
|
|
||||||
frontend/ir/ir_emitter.cpp
|
|
||||||
frontend/ir/location_descriptor.cpp
|
|
||||||
frontend/ir/microinstruction.cpp
|
|
||||||
frontend/ir/opcodes.cpp
|
|
||||||
frontend/ir/value.cpp
|
|
||||||
frontend/translate/translate.cpp
|
|
||||||
frontend/translate/translate_arm.cpp
|
|
||||||
frontend/translate/translate_arm/branch.cpp
|
|
||||||
frontend/translate/translate_arm/coprocessor.cpp
|
|
||||||
frontend/translate/translate_arm/data_processing.cpp
|
|
||||||
frontend/translate/translate_arm/exception_generating.cpp
|
|
||||||
frontend/translate/translate_arm/extension.cpp
|
|
||||||
frontend/translate/translate_arm/load_store.cpp
|
|
||||||
frontend/translate/translate_arm/misc.cpp
|
|
||||||
frontend/translate/translate_arm/multiply.cpp
|
|
||||||
frontend/translate/translate_arm/packing.cpp
|
|
||||||
frontend/translate/translate_arm/parallel.cpp
|
|
||||||
frontend/translate/translate_arm/reversal.cpp
|
|
||||||
frontend/translate/translate_arm/saturated.cpp
|
|
||||||
frontend/translate/translate_arm/status_register_access.cpp
|
|
||||||
frontend/translate/translate_arm/synchronization.cpp
|
|
||||||
frontend/translate/translate_arm/vfp2.cpp
|
|
||||||
frontend/translate/translate_thumb.cpp
|
|
||||||
ir_opt/constant_propagation_pass.cpp
|
|
||||||
ir_opt/dead_code_elimination_pass.cpp
|
|
||||||
ir_opt/get_set_elimination_pass.cpp
|
|
||||||
ir_opt/verification_pass.cpp
|
|
||||||
|
|
||||||
# Header files
|
|
||||||
../include/dynarmic/callbacks.h
|
../include/dynarmic/callbacks.h
|
||||||
../include/dynarmic/coprocessor.h
|
../include/dynarmic/coprocessor.h
|
||||||
../include/dynarmic/coprocessor_util.h
|
../include/dynarmic/coprocessor_util.h
|
||||||
|
@ -45,53 +10,84 @@ add_library(dynarmic
|
||||||
common/common_types.h
|
common/common_types.h
|
||||||
common/intrusive_list.h
|
common/intrusive_list.h
|
||||||
common/iterator_util.h
|
common/iterator_util.h
|
||||||
|
common/memory_pool.cpp
|
||||||
common/memory_pool.h
|
common/memory_pool.h
|
||||||
common/mp.h
|
common/mp.h
|
||||||
common/scope_exit.h
|
common/scope_exit.h
|
||||||
common/string_util.h
|
common/string_util.h
|
||||||
common/variant_util.h
|
common/variant_util.h
|
||||||
frontend/arm/FPSCR.h
|
frontend/A32/decoder/arm.h
|
||||||
frontend/arm/PSR.h
|
frontend/A32/decoder/thumb16.h
|
||||||
frontend/arm/types.h
|
frontend/A32/decoder/thumb32.h
|
||||||
frontend/decoder/arm.h
|
frontend/A32/decoder/vfp2.h
|
||||||
|
frontend/A32/disassembler/disassembler.h
|
||||||
|
frontend/A32/disassembler/disassembler_arm.cpp
|
||||||
|
frontend/A32/disassembler/disassembler_thumb.cpp
|
||||||
|
frontend/A32/FPSCR.h
|
||||||
|
frontend/A32/location_descriptor.cpp
|
||||||
|
frontend/A32/location_descriptor.h
|
||||||
|
frontend/A32/PSR.h
|
||||||
|
frontend/A32/translate/translate.cpp
|
||||||
|
frontend/A32/translate/translate.h
|
||||||
|
frontend/A32/translate/translate_arm.cpp
|
||||||
|
frontend/A32/translate/translate_arm/branch.cpp
|
||||||
|
frontend/A32/translate/translate_arm/coprocessor.cpp
|
||||||
|
frontend/A32/translate/translate_arm/data_processing.cpp
|
||||||
|
frontend/A32/translate/translate_arm/exception_generating.cpp
|
||||||
|
frontend/A32/translate/translate_arm/extension.cpp
|
||||||
|
frontend/A32/translate/translate_arm/load_store.cpp
|
||||||
|
frontend/A32/translate/translate_arm/misc.cpp
|
||||||
|
frontend/A32/translate/translate_arm/multiply.cpp
|
||||||
|
frontend/A32/translate/translate_arm/packing.cpp
|
||||||
|
frontend/A32/translate/translate_arm/parallel.cpp
|
||||||
|
frontend/A32/translate/translate_arm/reversal.cpp
|
||||||
|
frontend/A32/translate/translate_arm/saturated.cpp
|
||||||
|
frontend/A32/translate/translate_arm/status_register_access.cpp
|
||||||
|
frontend/A32/translate/translate_arm/synchronization.cpp
|
||||||
|
frontend/A32/translate/translate_arm/translate_arm.h
|
||||||
|
frontend/A32/translate/translate_arm/vfp2.cpp
|
||||||
|
frontend/A32/translate/translate_thumb.cpp
|
||||||
|
frontend/A32/types.cpp
|
||||||
|
frontend/A32/types.h
|
||||||
frontend/decoder/decoder_detail.h
|
frontend/decoder/decoder_detail.h
|
||||||
frontend/decoder/matcher.h
|
frontend/decoder/matcher.h
|
||||||
frontend/decoder/thumb16.h
|
frontend/ir/basic_block.cpp
|
||||||
frontend/decoder/thumb32.h
|
|
||||||
frontend/decoder/vfp2.h
|
|
||||||
frontend/disassembler/disassembler.h
|
|
||||||
frontend/ir/basic_block.h
|
frontend/ir/basic_block.h
|
||||||
|
frontend/ir/ir_emitter.cpp
|
||||||
frontend/ir/ir_emitter.h
|
frontend/ir/ir_emitter.h
|
||||||
|
frontend/ir/location_descriptor.cpp
|
||||||
frontend/ir/location_descriptor.h
|
frontend/ir/location_descriptor.h
|
||||||
|
frontend/ir/microinstruction.cpp
|
||||||
frontend/ir/microinstruction.h
|
frontend/ir/microinstruction.h
|
||||||
|
frontend/ir/opcodes.cpp
|
||||||
frontend/ir/opcodes.h
|
frontend/ir/opcodes.h
|
||||||
frontend/ir/terminal.h
|
frontend/ir/terminal.h
|
||||||
|
frontend/ir/value.cpp
|
||||||
frontend/ir/value.h
|
frontend/ir/value.h
|
||||||
frontend/translate/translate.h
|
ir_opt/constant_propagation_pass.cpp
|
||||||
frontend/translate/translate_arm/translate_arm.h
|
ir_opt/dead_code_elimination_pass.cpp
|
||||||
|
ir_opt/get_set_elimination_pass.cpp
|
||||||
ir_opt/passes.h
|
ir_opt/passes.h
|
||||||
|
ir_opt/verification_pass.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86_64)
|
||||||
target_sources(dynarmic PRIVATE
|
target_sources(dynarmic PRIVATE
|
||||||
# Source files
|
|
||||||
backend_x64/abi.cpp
|
backend_x64/abi.cpp
|
||||||
|
backend_x64/abi.h
|
||||||
backend_x64/block_of_code.cpp
|
backend_x64/block_of_code.cpp
|
||||||
|
backend_x64/block_of_code.h
|
||||||
backend_x64/constant_pool.cpp
|
backend_x64/constant_pool.cpp
|
||||||
|
backend_x64/constant_pool.h
|
||||||
backend_x64/emit_x64.cpp
|
backend_x64/emit_x64.cpp
|
||||||
|
backend_x64/emit_x64.h
|
||||||
backend_x64/hostloc.cpp
|
backend_x64/hostloc.cpp
|
||||||
|
backend_x64/hostloc.h
|
||||||
backend_x64/interface_x64.cpp
|
backend_x64/interface_x64.cpp
|
||||||
backend_x64/jitstate.cpp
|
backend_x64/jitstate.cpp
|
||||||
backend_x64/reg_alloc.cpp
|
|
||||||
|
|
||||||
# Headers
|
|
||||||
backend_x64/abi.h
|
|
||||||
backend_x64/block_of_code.h
|
|
||||||
backend_x64/constant_pool.h
|
|
||||||
backend_x64/emit_x64.h
|
|
||||||
backend_x64/hostloc.h
|
|
||||||
backend_x64/jitstate.h
|
backend_x64/jitstate.h
|
||||||
backend_x64/oparg.h
|
backend_x64/oparg.h
|
||||||
|
backend_x64/reg_alloc.cpp
|
||||||
backend_x64/reg_alloc.h
|
backend_x64/reg_alloc.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,7 @@
|
||||||
#include "backend_x64/reg_alloc.h"
|
#include "backend_x64/reg_alloc.h"
|
||||||
#include "common/address_range.h"
|
#include "common/address_range.h"
|
||||||
#include "dynarmic/callbacks.h"
|
#include "dynarmic/callbacks.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/A32/location_descriptor.h"
|
||||||
#include "frontend/ir/terminal.h"
|
#include "frontend/ir/terminal.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
|
@ -34,17 +34,17 @@ namespace BackendX64 {
|
||||||
|
|
||||||
class BlockOfCode;
|
class BlockOfCode;
|
||||||
|
|
||||||
class EmitX64 final {
|
class A32EmitX64 final {
|
||||||
public:
|
public:
|
||||||
struct BlockDescriptor {
|
struct BlockDescriptor {
|
||||||
CodePtr entrypoint; // Entrypoint of emitted code
|
CodePtr entrypoint; // Entrypoint of emitted code
|
||||||
size_t size; // Length in bytes of emitted code
|
size_t size; // Length in bytes of emitted code
|
||||||
|
|
||||||
IR::LocationDescriptor start_location;
|
A32::LocationDescriptor start_location;
|
||||||
u32 end_location_pc;
|
boost::icl::discrete_interval<u32> range;
|
||||||
};
|
};
|
||||||
|
|
||||||
EmitX64(BlockOfCode* code, UserCallbacks cb, Jit* jit_interface);
|
A32EmitX64(BlockOfCode* code, UserCallbacks cb, Jit* jit_interface);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit host machine code for a basic block with intermediate representation `ir`.
|
* Emit host machine code for a basic block with intermediate representation `ir`.
|
||||||
|
@ -53,7 +53,7 @@ public:
|
||||||
BlockDescriptor Emit(IR::Block& ir);
|
BlockDescriptor Emit(IR::Block& ir);
|
||||||
|
|
||||||
/// Looks up an emitted host block in the cache.
|
/// Looks up an emitted host block in the cache.
|
||||||
boost::optional<BlockDescriptor> GetBasicBlock(IR::LocationDescriptor descriptor) const;
|
boost::optional<BlockDescriptor> GetBasicBlock(A32::LocationDescriptor descriptor) const;
|
||||||
|
|
||||||
/// Empties the entire cache.
|
/// Empties the entire cache.
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
@ -76,14 +76,14 @@ private:
|
||||||
void PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, u64 target_hash);
|
void PushRSBHelper(Xbyak::Reg64 loc_desc_reg, Xbyak::Reg64 index_reg, u64 target_hash);
|
||||||
|
|
||||||
// Terminal instruction emitters
|
// Terminal instruction emitters
|
||||||
void EmitTerminal(IR::Terminal terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Terminal terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::Interpret terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::ReturnToDispatch terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::LinkBlock terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::LinkBlockFast terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::PopRSBHint terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::PopRSBHint terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::If terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::If terminal, A32::LocationDescriptor initial_location);
|
||||||
void EmitTerminal(IR::Term::CheckHalt terminal, IR::LocationDescriptor initial_location);
|
void EmitTerminal(IR::Term::CheckHalt terminal, A32::LocationDescriptor initial_location);
|
||||||
|
|
||||||
// Patching
|
// Patching
|
||||||
struct PatchInformation {
|
struct PatchInformation {
|
||||||
|
@ -91,16 +91,16 @@ private:
|
||||||
std::vector<CodePtr> jmp;
|
std::vector<CodePtr> jmp;
|
||||||
std::vector<CodePtr> mov_rcx;
|
std::vector<CodePtr> mov_rcx;
|
||||||
};
|
};
|
||||||
void Patch(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr);
|
void Patch(const A32::LocationDescriptor& target_desc, CodePtr target_code_ptr);
|
||||||
void Unpatch(const IR::LocationDescriptor& target_desc);
|
void Unpatch(const A32::LocationDescriptor& target_desc);
|
||||||
void EmitPatchJg(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr = nullptr);
|
void EmitPatchJg(const A32::LocationDescriptor& target_desc, CodePtr target_code_ptr = nullptr);
|
||||||
void EmitPatchJmp(const IR::LocationDescriptor& target_desc, CodePtr target_code_ptr = nullptr);
|
void EmitPatchJmp(const A32::LocationDescriptor& target_desc, CodePtr target_code_ptr = nullptr);
|
||||||
void EmitPatchMovRcx(CodePtr target_code_ptr = nullptr);
|
void EmitPatchMovRcx(CodePtr target_code_ptr = nullptr);
|
||||||
|
|
||||||
// State
|
// State
|
||||||
BlockOfCode* code;
|
BlockOfCode* code;
|
||||||
UserCallbacks cb;
|
UserCallbacks cb;
|
||||||
boost::icl::interval_map<u32, std::set<IR::LocationDescriptor>> block_ranges;
|
boost::icl::interval_map<u32, std::set<A32::LocationDescriptor>> block_ranges;
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
std::unordered_map<u64, BlockDescriptor> block_descriptors;
|
std::unordered_map<u64, BlockDescriptor> block_descriptors;
|
||||||
std::unordered_map<u64, PatchInformation> patch_information;
|
std::unordered_map<u64, PatchInformation> patch_information;
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "dynarmic/context.h"
|
#include "dynarmic/context.h"
|
||||||
#include "dynarmic/dynarmic.h"
|
#include "dynarmic/dynarmic.h"
|
||||||
|
#include "frontend/A32/translate/translate.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
#include "ir_opt/passes.h"
|
#include "ir_opt/passes.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
|
@ -42,7 +42,7 @@ struct Jit::Impl {
|
||||||
|
|
||||||
BlockOfCode block_of_code;
|
BlockOfCode block_of_code;
|
||||||
JitState jit_state;
|
JitState jit_state;
|
||||||
EmitX64 emitter;
|
A32EmitX64 emitter;
|
||||||
const UserCallbacks callbacks;
|
const UserCallbacks callbacks;
|
||||||
|
|
||||||
// Requests made during execution to invalidate the cache are queued up here.
|
// Requests made during execution to invalidate the cache are queued up here.
|
||||||
|
@ -131,14 +131,14 @@ private:
|
||||||
JitState& jit_state = this_.jit_state;
|
JitState& jit_state = this_.jit_state;
|
||||||
|
|
||||||
u32 pc = jit_state.Reg[15];
|
u32 pc = jit_state.Reg[15];
|
||||||
Arm::PSR cpsr{jit_state.Cpsr()};
|
A32::PSR cpsr{jit_state.Cpsr()};
|
||||||
Arm::FPSCR fpscr{jit_state.FPSCR_mode};
|
A32::FPSCR fpscr{jit_state.FPSCR_mode};
|
||||||
IR::LocationDescriptor descriptor{pc, cpsr, fpscr};
|
A32::LocationDescriptor descriptor{pc, cpsr, fpscr};
|
||||||
|
|
||||||
return this_.GetBasicBlock(descriptor).entrypoint;
|
return this_.GetBasicBlock(descriptor).entrypoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
A32EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
||||||
auto block = emitter.GetBasicBlock(descriptor);
|
auto block = emitter.GetBasicBlock(descriptor);
|
||||||
if (block)
|
if (block)
|
||||||
return *block;
|
return *block;
|
||||||
|
@ -149,7 +149,7 @@ private:
|
||||||
PerformCacheInvalidation();
|
PerformCacheInvalidation();
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block ir_block = Arm::Translate(descriptor, callbacks.memory.ReadCode);
|
IR::Block ir_block = A32::Translate(descriptor, callbacks.memory.ReadCode);
|
||||||
Optimization::GetSetElimination(ir_block);
|
Optimization::GetSetElimination(ir_block);
|
||||||
Optimization::DeadCodeElimination(ir_block);
|
Optimization::DeadCodeElimination(ir_block);
|
||||||
Optimization::ConstantPropagation(ir_block, callbacks.memory);
|
Optimization::ConstantPropagation(ir_block, callbacks.memory);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace BackendX64 {
|
namespace BackendX64 {
|
||||||
|
@ -150,7 +150,7 @@ void JitState::ResetRSB() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// NZCV; QC (ASMID only), AHP; DN, FZ, RMode, Stride; SBZP; Len; trap enables; cumulative bits
|
// NZCV; QC (ASMID only), AHP; DN, FZ, RMode, Stride; SBZP; Len; trap enables; cumulative bits
|
||||||
constexpr u32 FPSCR_MODE_MASK = IR::LocationDescriptor::FPSCR_MODE_MASK;
|
constexpr u32 FPSCR_MODE_MASK = A32::LocationDescriptor::FPSCR_MODE_MASK;
|
||||||
constexpr u32 FPSCR_NZCV_MASK = 0xF0000000;
|
constexpr u32 FPSCR_NZCV_MASK = 0xF0000000;
|
||||||
|
|
||||||
u32 JitState::Fpscr() const {
|
u32 JitState::Fpscr() const {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of the Floating-Point Status and Control Register.
|
* Representation of the Floating-Point Status and Control Register.
|
||||||
|
@ -195,5 +195,5 @@ inline bool operator!=(FPSCR lhs, FPSCR rhs) {
|
||||||
return !operator==(lhs, rhs);
|
return !operator==(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -10,7 +10,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program Status Register
|
* Program Status Register
|
||||||
|
@ -221,5 +221,5 @@ inline bool operator!=(PSR lhs, PSR rhs) {
|
||||||
return !operator==(lhs, rhs);
|
return !operator==(lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -20,16 +20,16 @@
|
||||||
#include "frontend/decoder/matcher.h"
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
using ArmMatcher = Matcher<Visitor, u32>;
|
using ArmMatcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template <typename V>
|
template <typename V>
|
||||||
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
std::vector<ArmMatcher<V>> GetArmDecodeTable() {
|
||||||
std::vector<ArmMatcher<V>> table = {
|
std::vector<ArmMatcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<ArmMatcher<V>>::GetMatcher(fn, name, bitstring)
|
#define INST(fn, name, bitstring) Decoder::detail::detail<ArmMatcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Branch instructions
|
// Branch instructions
|
||||||
INST(&V::arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv"), // v5
|
INST(&V::arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv"), // v5
|
||||||
|
@ -330,5 +330,5 @@ boost::optional<const ArmMatcher<V>&> DecodeArm(u32 instruction) {
|
||||||
return iter != table.end() ? boost::optional<const ArmMatcher<V>&>(*iter) : boost::none;
|
return iter != table.end() ? boost::optional<const ArmMatcher<V>&>(*iter) : boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -15,16 +15,16 @@
|
||||||
#include "frontend/decoder/matcher.h"
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
using Thumb16Matcher = Matcher<Visitor, u16>;
|
using Thumb16Matcher = Decoder::Matcher<Visitor, u16>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
||||||
static const std::vector<Thumb16Matcher<V>> table = {
|
static const std::vector<Thumb16Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<Thumb16Matcher<V>>::GetMatcher(fn, name, bitstring)
|
#define INST(fn, name, bitstring) Decoder::detail::detail<Thumb16Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Shift (immediate), add, subtract, move and compare instructions
|
// Shift (immediate), add, subtract, move and compare instructions
|
||||||
INST(&V::thumb16_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd"),
|
INST(&V::thumb16_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd"),
|
||||||
|
@ -123,5 +123,5 @@ boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
||||||
return iter != table.end() ? boost::optional<const Thumb16Matcher<V>&>(*iter) : boost::none;
|
return iter != table.end() ? boost::optional<const Thumb16Matcher<V>&>(*iter) : boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -15,16 +15,16 @@
|
||||||
#include "frontend/decoder/matcher.h"
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
using Thumb32Matcher = Matcher<Visitor, u32>;
|
using Thumb32Matcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const Thumb32Matcher<V>&> DecodeThumb32(u32 instruction) {
|
boost::optional<const Thumb32Matcher<V>&> DecodeThumb32(u32 instruction) {
|
||||||
static const std::vector<Thumb32Matcher<V>> table = {
|
static const std::vector<Thumb32Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<Thumb32Matcher<V>>::GetMatcher(fn, name, bitstring)
|
#define INST(fn, name, bitstring) Decoder::detail::detail<Thumb32Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// Branch instructions
|
// Branch instructions
|
||||||
INST(&V::thumb32_BL_imm, "BL (imm)", "11110vvvvvvvvvvv11111vvvvvvvvvvv"), // v4T
|
INST(&V::thumb32_BL_imm, "BL (imm)", "11110vvvvvvvvvvv11111vvvvvvvvvvv"), // v4T
|
||||||
|
@ -43,5 +43,5 @@ boost::optional<const Thumb32Matcher<V>&> DecodeThumb32(u32 instruction) {
|
||||||
return iter != table.end() ? boost::optional<const Thumb32Matcher<V>&>(*iter) : boost::none;
|
return iter != table.end() ? boost::optional<const Thumb32Matcher<V>&>(*iter) : boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -15,16 +15,16 @@
|
||||||
#include "frontend/decoder/matcher.h"
|
#include "frontend/decoder/matcher.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
template <typename Visitor>
|
template <typename Visitor>
|
||||||
using VFP2Matcher = Matcher<Visitor, u32>;
|
using VFP2Matcher = Decoder::Matcher<Visitor, u32>;
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
||||||
static const std::vector<VFP2Matcher<V>> table = {
|
static const std::vector<VFP2Matcher<V>> table = {
|
||||||
|
|
||||||
#define INST(fn, name, bitstring) detail::detail<VFP2Matcher<V>>::GetMatcher(fn, name, bitstring)
|
#define INST(fn, name, bitstring) Decoder::detail::detail<VFP2Matcher<V>>::GetMatcher(fn, name, bitstring)
|
||||||
|
|
||||||
// cccc1110________----101-__-0----
|
// cccc1110________----101-__-0----
|
||||||
|
|
||||||
|
@ -88,5 +88,5 @@ boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
||||||
return iter != table.end() ? boost::optional<const VFP2Matcher<V>&>(*iter) : boost::none;
|
return iter != table.end() ? boost::optional<const VFP2Matcher<V>&>(*iter) : boost::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -11,10 +11,10 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
std::string DisassembleArm(u32 instruction);
|
std::string DisassembleArm(u32 instruction);
|
||||||
std::string DisassembleThumb16(u16 instruction);
|
std::string DisassembleThumb16(u16 instruction);
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -12,13 +12,13 @@
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/decoder/arm.h"
|
||||||
#include "frontend/decoder/arm.h"
|
#include "frontend/A32/decoder/vfp2.h"
|
||||||
#include "frontend/decoder/vfp2.h"
|
#include "frontend/A32/disassembler/disassembler.h"
|
||||||
#include "frontend/disassembler/disassembler.h"
|
#include "frontend/A32/types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
class DisassemblerVisitor {
|
||||||
public:
|
public:
|
||||||
|
@ -1079,5 +1079,5 @@ std::string DisassembleArm(u32 instruction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -12,12 +12,12 @@
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/decoder/thumb16.h"
|
||||||
#include "frontend/decoder/thumb16.h"
|
#include "frontend/A32/disassembler/disassembler.h"
|
||||||
#include "frontend/disassembler/disassembler.h"
|
#include "frontend/A32/types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
class DisassemblerVisitor {
|
class DisassemblerVisitor {
|
||||||
public:
|
public:
|
||||||
|
@ -332,5 +332,5 @@ std::string DisassembleThumb16(u16 instruction) {
|
||||||
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->call(visitor, instruction);
|
return !decoder ? fmt::format("UNKNOWN: {:x}", instruction) : decoder->call(visitor, instruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
24
src/frontend/A32/location_descriptor.cpp
Normal file
24
src/frontend/A32/location_descriptor.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace A32 {
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& loc) {
|
||||||
|
o << fmt::format("{{{},{},{},{}}}",
|
||||||
|
loc.PC(),
|
||||||
|
loc.TFlag() ? "T" : "!T",
|
||||||
|
loc.EFlag() ? "E" : "!E",
|
||||||
|
loc.FPSCR().Value());
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace A32
|
||||||
|
} // namespace Dynarmic
|
127
src/frontend/A32/location_descriptor.h
Normal file
127
src/frontend/A32/location_descriptor.h
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <tuple>
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "frontend/A32/FPSCR.h"
|
||||||
|
#include "frontend/A32/PSR.h"
|
||||||
|
#include "frontend/ir/location_descriptor.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace A32 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LocationDescriptor describes the location of a basic block.
|
||||||
|
* The location is not solely based on the PC because other flags influence the way
|
||||||
|
* instructions should be translated. The CPSR.T flag is most notable since it
|
||||||
|
* tells us if the processor is in Thumb or Arm mode.
|
||||||
|
*/
|
||||||
|
class LocationDescriptor {
|
||||||
|
public:
|
||||||
|
// Indicates bits that should be preserved within descriptors.
|
||||||
|
static constexpr u32 CPSR_MODE_MASK = 0x00000220;
|
||||||
|
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
||||||
|
|
||||||
|
LocationDescriptor(u32 arm_pc, PSR cpsr, FPSCR fpscr)
|
||||||
|
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
||||||
|
|
||||||
|
/*implict*/ LocationDescriptor(const IR::LocationDescriptor& o) {
|
||||||
|
arm_pc = o.value >> 32;
|
||||||
|
cpsr.T(o.value & 1);
|
||||||
|
cpsr.E(o.value & 2);
|
||||||
|
fpscr = o.value & FPSCR_MODE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 PC() const { return arm_pc; }
|
||||||
|
bool TFlag() const { return cpsr.T(); }
|
||||||
|
bool EFlag() const { return cpsr.E(); }
|
||||||
|
|
||||||
|
PSR CPSR() const { return cpsr; }
|
||||||
|
FPSCR FPSCR() const { return fpscr; }
|
||||||
|
|
||||||
|
bool operator == (const LocationDescriptor& o) const {
|
||||||
|
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (const LocationDescriptor& o) const {
|
||||||
|
return !operator==(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
||||||
|
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor AdvancePC(int amount) const {
|
||||||
|
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor SetTFlag(bool new_tflag) const {
|
||||||
|
PSR new_cpsr = cpsr;
|
||||||
|
new_cpsr.T(new_tflag);
|
||||||
|
|
||||||
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor SetEFlag(bool new_eflag) const {
|
||||||
|
PSR new_cpsr = cpsr;
|
||||||
|
new_cpsr.E(new_eflag);
|
||||||
|
|
||||||
|
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
||||||
|
return LocationDescriptor(arm_pc, cpsr, A32::FPSCR{new_fpscr & FPSCR_MODE_MASK});
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 UniqueHash() const {
|
||||||
|
// This value MUST BE UNIQUE.
|
||||||
|
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||||
|
u64 pc_u64 = u64(arm_pc) << 32;
|
||||||
|
u64 fpscr_u64 = u64(fpscr.Value());
|
||||||
|
u64 t_u64 = cpsr.T() ? 1 : 0;
|
||||||
|
u64 e_u64 = cpsr.E() ? 2 : 0;
|
||||||
|
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator IR::LocationDescriptor() const {
|
||||||
|
return IR::LocationDescriptor{UniqueHash()};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32 arm_pc; ///< Current program counter value.
|
||||||
|
PSR cpsr; ///< Current program status register.
|
||||||
|
A32::FPSCR fpscr; ///< Floating point status control register.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a string representation of a LocationDescriptor.
|
||||||
|
*
|
||||||
|
* @param o Output stream
|
||||||
|
* @param descriptor The descriptor to get a string representation of
|
||||||
|
*/
|
||||||
|
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
|
} // namespace A32
|
||||||
|
} // namespace Dynarmic
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct less<Dynarmic::A32::LocationDescriptor> {
|
||||||
|
bool operator()(const Dynarmic::A32::LocationDescriptor& x, const Dynarmic::A32::LocationDescriptor& y) const {
|
||||||
|
return x.UniqueHash() < y.UniqueHash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
struct hash<Dynarmic::A32::LocationDescriptor> {
|
||||||
|
size_t operator()(const Dynarmic::A32::LocationDescriptor& x) const {
|
||||||
|
return std::hash<u64>()(x.UniqueHash());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace std
|
22
src/frontend/A32/translate/translate.cpp
Normal file
22
src/frontend/A32/translate/translate.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
#include "frontend/A32/translate/translate.h"
|
||||||
|
#include "frontend/ir/basic_block.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace A32 {
|
||||||
|
|
||||||
|
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
||||||
|
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
||||||
|
|
||||||
|
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
||||||
|
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace A32
|
||||||
|
} // namespace Dynarmic
|
|
@ -11,12 +11,11 @@ namespace Dynarmic {
|
||||||
|
|
||||||
namespace IR {
|
namespace IR {
|
||||||
class Block;
|
class Block;
|
||||||
class LocationDescriptor;
|
|
||||||
} // namespace IR
|
} // namespace IR
|
||||||
|
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
struct LocationDescriptor;
|
class LocationDescriptor;
|
||||||
|
|
||||||
using MemoryReadCodeFuncType = u32 (*)(u32 vaddr);
|
using MemoryReadCodeFuncType = u32 (*)(u32 vaddr);
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ using MemoryReadCodeFuncType = u32 (*)(u32 vaddr);
|
||||||
* @param memory_read_code The function we should use to read emulated memory.
|
* @param memory_read_code The function we should use to read emulated memory.
|
||||||
* @return A translated basic block in the intermediate representation.
|
* @return A translated basic block in the intermediate representation.
|
||||||
*/
|
*/
|
||||||
IR::Block Translate(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
IR::Block Translate(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,18 +7,18 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/decoder/arm.h"
|
||||||
#include "frontend/decoder/arm.h"
|
#include "frontend/A32/decoder/vfp2.h"
|
||||||
#include "frontend/decoder/vfp2.h"
|
#include "frontend/A32/translate/translate.h"
|
||||||
|
#include "frontend/A32/translate/translate_arm/translate_arm.h"
|
||||||
|
#include "frontend/A32/types.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
#include "frontend/translate/translate_arm/translate_arm.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
static bool CondCanContinue(ConditionalState cond_state, const IR::IREmitter& ir) {
|
static bool CondCanContinue(ConditionalState cond_state, const IR::A32IREmitter& ir) {
|
||||||
ASSERT_MSG(cond_state != ConditionalState::Break, "Should never happen.");
|
ASSERT_MSG(cond_state != ConditionalState::Break, "Should never happen.");
|
||||||
|
|
||||||
if (cond_state == ConditionalState::None)
|
if (cond_state == ConditionalState::None)
|
||||||
|
@ -28,7 +28,7 @@ static bool CondCanContinue(ConditionalState cond_state, const IR::IREmitter& ir
|
||||||
return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); });
|
return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
||||||
ArmTranslatorVisitor visitor{descriptor};
|
ArmTranslatorVisitor visitor{descriptor};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
|
@ -75,7 +75,7 @@ bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
||||||
cond_state = ConditionalState::Trailing;
|
cond_state = ConditionalState::Trailing;
|
||||||
} else {
|
} else {
|
||||||
if (cond == ir.block.GetCondition()) {
|
if (cond == ir.block.GetCondition()) {
|
||||||
ir.block.SetConditionFailedLocation({ ir.current_location.AdvancePC(4) });
|
ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(4));
|
||||||
ir.block.ConditionFailedCycleCount()++;
|
ir.block.ConditionFailedCycleCount()++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ bool ArmTranslatorVisitor::ConditionPassed(Cond cond) {
|
||||||
|
|
||||||
cond_state = ConditionalState::Translating;
|
cond_state = ConditionalState::Translating;
|
||||||
ir.block.SetCondition(cond);
|
ir.block.SetCondition(cond);
|
||||||
ir.block.SetConditionFailedLocation({ ir.current_location.AdvancePC(4) });
|
ir.block.SetConditionFailedLocation(ir.current_location.AdvancePC(4));
|
||||||
ir.block.ConditionFailedCycleCount() = 1;
|
ir.block.ConditionFailedCycleCount() = 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ bool ArmTranslatorVisitor::UnpredictableInstruction() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in) {
|
IR::A32IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ShiftType::LSL:
|
case ShiftType::LSL:
|
||||||
return ir.LogicalShiftLeft(value, ir.Imm8(imm5), carry_in);
|
return ir.LogicalShiftLeft(value, ir.Imm8(imm5), carry_in);
|
||||||
|
@ -141,7 +141,7 @@ IR::IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitImmShift(IR::Value value
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in) {
|
IR::A32IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ShiftType::LSL:
|
case ShiftType::LSL:
|
||||||
return ir.LogicalShiftLeft(value, amount, carry_in);
|
return ir.LogicalShiftLeft(value, amount, carry_in);
|
||||||
|
@ -156,5 +156,5 @@ IR::IREmitter::ResultAndCarry ArmTranslatorVisitor::EmitRegShift(IR::Value value
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -9,7 +9,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24) {
|
bool ArmTranslatorVisitor::arm_B(Cond cond, Imm24 imm24) {
|
||||||
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
u32 imm32 = Common::SignExtend<26, u32>(imm24 << 2) + 8;
|
||||||
|
@ -77,5 +77,5 @@ bool ArmTranslatorVisitor::arm_BXJ(Cond cond, Reg m) {
|
||||||
return arm_BX(cond, m);
|
return arm_BX(cond, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) {
|
bool ArmTranslatorVisitor::arm_CDP(Cond cond, size_t opc1, CoprocReg CRn, CoprocReg CRd, size_t coproc_no, size_t opc2, CoprocReg CRm) {
|
||||||
if ((coproc_no & 0b1110) == 0b1010)
|
if ((coproc_no & 0b1110) == 0b1010)
|
||||||
|
@ -146,5 +146,5 @@ bool ArmTranslatorVisitor::arm_STC(Cond cond, bool p, bool u, bool d, bool w, Re
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
|
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
|
||||||
// ADC{S}<c> <Rd>, <Rn>, #<imm>
|
// ADC{S}<c> <Rd>, <Rn>, #<imm>
|
||||||
|
@ -889,5 +889,5 @@ bool ArmTranslatorVisitor::arm_TST_rsr(Cond cond, Reg n, Reg s, ShiftType shift,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_BKPT(Cond /*cond*/, Imm12 /*imm12*/, Imm4 /*imm4*/) {
|
bool ArmTranslatorVisitor::arm_BKPT(Cond /*cond*/, Imm12 /*imm12*/, Imm4 /*imm4*/) {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
|
@ -30,5 +30,5 @@ bool ArmTranslatorVisitor::arm_UDF() {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,9 +7,9 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
static IR::Value Rotate(IR::IREmitter& ir, Reg m, SignExtendRotation rotate) {
|
static IR::Value Rotate(IR::A32IREmitter& ir, Reg m, SignExtendRotation rotate) {
|
||||||
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
|
const u8 rotate_by = static_cast<u8>(static_cast<size_t>(rotate) * 8);
|
||||||
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
|
return ir.RotateRight(ir.GetRegister(m), ir.Imm8(rotate_by), ir.Imm1(0)).result;
|
||||||
}
|
}
|
||||||
|
@ -181,5 +181,5 @@ bool ArmTranslatorVisitor::arm_UXTH(Cond cond, Reg d, SignExtendRotation rotate,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_LDRBT() {
|
bool ArmTranslatorVisitor::arm_LDRBT() {
|
||||||
ASSERT_MSG(false, "System instructions unimplemented");
|
ASSERT_MSG(false, "System instructions unimplemented");
|
||||||
|
@ -41,7 +41,7 @@ bool ArmTranslatorVisitor::arm_STRT() {
|
||||||
ASSERT_MSG(false, "System instructions unimplemented");
|
ASSERT_MSG(false, "System instructions unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
static IR::Value GetAddress(IR::IREmitter& ir, bool P, bool U, bool W, Reg n, IR::Value offset) {
|
static IR::Value GetAddress(IR::A32IREmitter& ir, bool P, bool U, bool W, Reg n, IR::Value offset) {
|
||||||
const bool index = P;
|
const bool index = P;
|
||||||
const bool add = U;
|
const bool add = U;
|
||||||
const bool wback = !P || W;
|
const bool wback = !P || W;
|
||||||
|
@ -608,7 +608,7 @@ bool ArmTranslatorVisitor::arm_STRH_reg(Cond cond, bool P, bool U, bool W, Reg n
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool LDMHelper(IR::IREmitter& ir, bool W, Reg n, RegList list, IR::Value start_address, IR::Value writeback_address) {
|
static bool LDMHelper(IR::A32IREmitter& ir, bool W, Reg n, RegList list, IR::Value start_address, IR::Value writeback_address) {
|
||||||
auto address = start_address;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
if (Common::Bit(i, list)) {
|
||||||
|
@ -686,7 +686,7 @@ bool ArmTranslatorVisitor::arm_LDM_eret() {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool STMHelper(IR::IREmitter& ir, bool W, Reg n, RegList list, IR::Value start_address, IR::Value writeback_address) {
|
static bool STMHelper(IR::A32IREmitter& ir, bool W, Reg n, RegList list, IR::Value start_address, IR::Value writeback_address) {
|
||||||
auto address = start_address;
|
auto address = start_address;
|
||||||
for (size_t i = 0; i <= 14; i++) {
|
for (size_t i = 0; i <= 14; i++) {
|
||||||
if (Common::Bit(i, list)) {
|
if (Common::Bit(i, list)) {
|
||||||
|
@ -755,5 +755,5 @@ bool ArmTranslatorVisitor::arm_STM_usr() {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_CLZ(Cond cond, Reg d, Reg m) {
|
bool ArmTranslatorVisitor::arm_CLZ(Cond cond, Reg d, Reg m) {
|
||||||
if (d == Reg::PC || m == Reg::PC)
|
if (d == Reg::PC || m == Reg::PC)
|
||||||
|
@ -32,5 +32,5 @@ bool ArmTranslatorVisitor::arm_SEL(Cond cond, Reg n, Reg d, Reg m) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
// Multiply (Normal) instructions
|
// Multiply (Normal) instructions
|
||||||
bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
bool ArmTranslatorVisitor::arm_MLA(Cond cond, bool S, Reg d, Reg a, Reg m, Reg n) {
|
||||||
|
@ -430,5 +430,5 @@ bool ArmTranslatorVisitor::arm_SMUSD(Cond cond, Reg d, Reg m, bool M, Reg n) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_PKHBT(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) {
|
bool ArmTranslatorVisitor::arm_PKHBT(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m) {
|
||||||
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
if (n == Reg::PC || d == Reg::PC || m == Reg::PC)
|
||||||
|
@ -37,5 +37,5 @@ bool ArmTranslatorVisitor::arm_PKHTB(Cond cond, Reg n, Reg d, Imm5 imm5, Reg m)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
// Parallel Add/Subtract (Modulo arithmetic) instructions
|
// Parallel Add/Subtract (Modulo arithmetic) instructions
|
||||||
bool ArmTranslatorVisitor::arm_SADD8(Cond cond, Reg n, Reg d, Reg m) {
|
bool ArmTranslatorVisitor::arm_SADD8(Cond cond, Reg n, Reg d, Reg m) {
|
||||||
|
@ -365,5 +365,5 @@ bool ArmTranslatorVisitor::arm_UHSUB16(Cond cond, Reg n, Reg d, Reg m) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) {
|
bool ArmTranslatorVisitor::arm_REV(Cond cond, Reg d, Reg m) {
|
||||||
// REV<c> <Rd>, <Rm>
|
// REV<c> <Rd>, <Rm>
|
||||||
|
@ -47,5 +47,5 @@ bool ArmTranslatorVisitor::arm_REVSH(Cond cond, Reg d, Reg m) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,13 +7,13 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
static IR::Value Pack2x16To1x32(IR::IREmitter& ir, IR::Value lo, IR::Value hi) {
|
static IR::Value Pack2x16To1x32(IR::A32IREmitter& ir, IR::Value lo, IR::Value hi) {
|
||||||
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
|
return ir.Or(ir.And(lo, ir.Imm32(0xFFFF)), ir.LogicalShiftLeft(hi, ir.Imm8(16), ir.Imm1(0)).result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static IR::Value MostSignificantHalf(IR::IREmitter& ir, IR::Value value) {
|
static IR::Value MostSignificantHalf(IR::A32IREmitter& ir, IR::Value value) {
|
||||||
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
|
return ir.LeastSignificantHalf(ir.LogicalShiftRight(value, ir.Imm8(16), ir.Imm1(0)).result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,5 +240,5 @@ bool ArmTranslatorVisitor::arm_UQSAX(Cond cond, Reg n, Reg d, Reg m) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -9,7 +9,7 @@
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_CPS() {
|
bool ArmTranslatorVisitor::arm_CPS() {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
|
@ -76,5 +76,5 @@ bool ArmTranslatorVisitor::arm_SRS() {
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::arm_CLREX() {
|
bool ArmTranslatorVisitor::arm_CLREX() {
|
||||||
// CLREX
|
// CLREX
|
||||||
|
@ -158,5 +158,5 @@ bool ArmTranslatorVisitor::arm_SWPB(Cond cond, Reg n, Reg t, Reg t2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -10,7 +10,7 @@
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
enum class ConditionalState {
|
enum class ConditionalState {
|
||||||
/// We haven't met any conditional instructions yet.
|
/// We haven't met any conditional instructions yet.
|
||||||
|
@ -26,11 +26,11 @@ enum class ConditionalState {
|
||||||
struct ArmTranslatorVisitor final {
|
struct ArmTranslatorVisitor final {
|
||||||
using instruction_return_type = bool;
|
using instruction_return_type = bool;
|
||||||
|
|
||||||
explicit ArmTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
explicit ArmTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||||
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::IREmitter ir;
|
IR::A32IREmitter ir;
|
||||||
ConditionalState cond_state = ConditionalState::None;
|
ConditionalState cond_state = ConditionalState::None;
|
||||||
|
|
||||||
bool ConditionPassed(Cond cond);
|
bool ConditionPassed(Cond cond);
|
||||||
|
@ -62,8 +62,8 @@ struct ArmTranslatorVisitor final {
|
||||||
return {imm32, carry_out};
|
return {imm32, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::IREmitter::ResultAndCarry EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in);
|
IR::A32IREmitter::ResultAndCarry EmitImmShift(IR::Value value, ShiftType type, Imm5 imm5, IR::Value carry_in);
|
||||||
IR::IREmitter::ResultAndCarry EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in);
|
IR::A32IREmitter::ResultAndCarry EmitRegShift(IR::Value value, ShiftType type, IR::Value amount, IR::Value carry_in);
|
||||||
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg n, ExtReg m, const FnT& fn);
|
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg n, ExtReg m, const FnT& fn);
|
||||||
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg m, const FnT& fn);
|
template <typename FnT> bool EmitVfpVectorOperation(bool sz, ExtReg d, ExtReg m, const FnT& fn);
|
||||||
|
|
||||||
|
@ -384,5 +384,5 @@ struct ArmTranslatorVisitor final {
|
||||||
bool vfp2_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm8 imm8);
|
bool vfp2_VLDM_a2(Cond cond, bool p, bool u, bool D, bool w, Reg n, size_t Vd, Imm8 imm8);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -7,7 +7,7 @@
|
||||||
#include "translate_arm.h"
|
#include "translate_arm.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
static ExtReg ToExtReg(bool sz, size_t base, bool bit) {
|
static ExtReg ToExtReg(bool sz, size_t base, bool bit) {
|
||||||
if (sz) {
|
if (sz) {
|
||||||
|
@ -672,7 +672,7 @@ bool ArmTranslatorVisitor::vfp2_VSTM_a1(Cond cond, bool p, bool u, bool D, bool
|
||||||
u32 imm32 = imm8 << 2;
|
u32 imm32 = imm8 << 2;
|
||||||
size_t regs = imm8 / 2;
|
size_t regs = imm8 / 2;
|
||||||
|
|
||||||
if (regs == 0 || regs > 16 || Arm::RegNumber(d)+regs > 32)
|
if (regs == 0 || regs > 16 || A32::RegNumber(d)+regs > 32)
|
||||||
return UnpredictableInstruction();
|
return UnpredictableInstruction();
|
||||||
|
|
||||||
// VSTM<mode>.F64 <Rn>{!}, <list of double registers>
|
// VSTM<mode>.F64 <Rn>{!}, <list of double registers>
|
||||||
|
@ -708,7 +708,7 @@ bool ArmTranslatorVisitor::vfp2_VSTM_a2(Cond cond, bool p, bool u, bool D, bool
|
||||||
u32 imm32 = imm8 << 2;
|
u32 imm32 = imm8 << 2;
|
||||||
size_t regs = imm8;
|
size_t regs = imm8;
|
||||||
|
|
||||||
if (regs == 0 || Arm::RegNumber(d)+regs > 32)
|
if (regs == 0 || A32::RegNumber(d)+regs > 32)
|
||||||
return UnpredictableInstruction();
|
return UnpredictableInstruction();
|
||||||
|
|
||||||
// VSTM<mode>.F32 <Rn>{!}, <list of single registers>
|
// VSTM<mode>.F32 <Rn>{!}, <list of single registers>
|
||||||
|
@ -739,7 +739,7 @@ bool ArmTranslatorVisitor::vfp2_VLDM_a1(Cond cond, bool p, bool u, bool D, bool
|
||||||
u32 imm32 = imm8 << 2;
|
u32 imm32 = imm8 << 2;
|
||||||
size_t regs = imm8 / 2;
|
size_t regs = imm8 / 2;
|
||||||
|
|
||||||
if (regs == 0 || regs > 16 || Arm::RegNumber(d)+regs > 32)
|
if (regs == 0 || regs > 16 || A32::RegNumber(d)+regs > 32)
|
||||||
return UnpredictableInstruction();
|
return UnpredictableInstruction();
|
||||||
|
|
||||||
// VLDM<mode>.F64 <Rn>{!}, <list of double registers>
|
// VLDM<mode>.F64 <Rn>{!}, <list of double registers>
|
||||||
|
@ -773,7 +773,7 @@ bool ArmTranslatorVisitor::vfp2_VLDM_a2(Cond cond, bool p, bool u, bool D, bool
|
||||||
u32 imm32 = imm8 << 2;
|
u32 imm32 = imm8 << 2;
|
||||||
size_t regs = imm8;
|
size_t regs = imm8;
|
||||||
|
|
||||||
if (regs == 0 || Arm::RegNumber(d)+regs > 32)
|
if (regs == 0 || A32::RegNumber(d)+regs > 32)
|
||||||
return UnpredictableInstruction();
|
return UnpredictableInstruction();
|
||||||
|
|
||||||
// VLDM<mode>.F32 <Rn>{!}, <list of single registers>
|
// VLDM<mode>.F32 <Rn>{!}, <list of single registers>
|
||||||
|
@ -790,5 +790,5 @@ bool ArmTranslatorVisitor::vfp2_VLDM_a2(Cond cond, bool p, bool u, bool D, bool
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -8,26 +8,26 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/decoder/thumb16.h"
|
||||||
#include "frontend/decoder/thumb16.h"
|
#include "frontend/A32/decoder/thumb32.h"
|
||||||
#include "frontend/decoder/thumb32.h"
|
#include "frontend/A32/translate/translate.h"
|
||||||
|
#include "frontend/A32/types.h"
|
||||||
#include "frontend/ir/ir_emitter.h"
|
#include "frontend/ir/ir_emitter.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct ThumbTranslatorVisitor final {
|
struct ThumbTranslatorVisitor final {
|
||||||
using instruction_return_type = bool;
|
using instruction_return_type = bool;
|
||||||
|
|
||||||
explicit ThumbTranslatorVisitor(IR::LocationDescriptor descriptor) : ir(descriptor) {
|
explicit ThumbTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
|
||||||
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
IR::IREmitter ir;
|
IR::A32IREmitter ir;
|
||||||
|
|
||||||
bool InterpretThisInstruction() {
|
bool InterpretThisInstruction() {
|
||||||
ir.SetTerm(IR::Term::Interpret(ir.current_location));
|
ir.SetTerm(IR::Term::Interpret(ir.current_location));
|
||||||
|
@ -877,7 +877,7 @@ std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFu
|
||||||
|
|
||||||
} // local namespace
|
} // local namespace
|
||||||
|
|
||||||
IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
||||||
ThumbTranslatorVisitor visitor{descriptor};
|
ThumbTranslatorVisitor visitor{descriptor};
|
||||||
|
|
||||||
bool should_continue = true;
|
bool should_continue = true;
|
||||||
|
@ -914,5 +914,5 @@ IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryReadCodeFuncTy
|
||||||
return std::move(visitor.ir.block);
|
return std::move(visitor.ir.block);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namepsace Dynarmic
|
} // namepsace Dynarmic
|
|
@ -8,10 +8,10 @@
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
const char* CondToString(Cond cond, bool explicit_al) {
|
const char* CondToString(Cond cond, bool explicit_al) {
|
||||||
constexpr std::array<const char*, 15> cond_strs = {
|
constexpr std::array<const char*, 15> cond_strs = {
|
||||||
|
@ -78,5 +78,5 @@ std::ostream& operator<<(std::ostream& o, RegList reg_list) {
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -14,13 +14,12 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "frontend/ir/cond.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace A32 {
|
||||||
|
|
||||||
enum class Cond {
|
using Cond = IR::Cond;
|
||||||
EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Reg {
|
enum class Reg {
|
||||||
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
|
R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
|
||||||
|
@ -119,5 +118,5 @@ inline ExtReg operator+(ExtReg reg, size_t number) {
|
||||||
return new_reg;
|
return new_reg;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
|
@ -15,7 +15,7 @@
|
||||||
#include "common/mp.h"
|
#include "common/mp.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Decoder {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,5 +163,5 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace Arm
|
} // namespace Decoder
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace Arm {
|
namespace Decoder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic instruction handling construct.
|
* Generic instruction handling construct.
|
||||||
|
@ -75,5 +75,5 @@ private:
|
||||||
handler_function fn;
|
handler_function fn;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Arm
|
} // namespace Decoder
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "frontend/A32/types.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/ir/opcodes.h"
|
#include "frontend/ir/opcodes.h"
|
||||||
|
|
||||||
|
@ -43,11 +44,11 @@ void Block::SetEndLocation(const LocationDescriptor& descriptor) {
|
||||||
end_location = descriptor;
|
end_location = descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arm::Cond Block::GetCondition() const {
|
Cond Block::GetCondition() const {
|
||||||
return cond;
|
return cond;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Block::SetCondition(Arm::Cond condition) {
|
void Block::SetCondition(Cond condition) {
|
||||||
cond = condition;
|
cond = condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ static std::string TerminalToString(const Terminal& terminal_variant) {
|
||||||
}
|
}
|
||||||
case 6: {
|
case 6: {
|
||||||
auto terminal = boost::get<IR::Term::If>(terminal_variant);
|
auto terminal = boost::get<IR::Term::If>(terminal_variant);
|
||||||
return fmt::format("If{{{}, {}, {}}}", CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
|
return fmt::format("If{{{}, {}, {}}}", A32::CondToString(terminal.if_), TerminalToString(terminal.then_), TerminalToString(terminal.else_));
|
||||||
}
|
}
|
||||||
case 7: {
|
case 7: {
|
||||||
auto terminal = boost::get<IR::Term::CheckHalt>(terminal_variant);
|
auto terminal = boost::get<IR::Term::CheckHalt>(terminal_variant);
|
||||||
|
@ -138,8 +139,8 @@ std::string DumpBlock(const IR::Block& block) {
|
||||||
|
|
||||||
ret += fmt::format("Block: location={}\n", block.Location());
|
ret += fmt::format("Block: location={}\n", block.Location());
|
||||||
ret += fmt::format("cycles={}", block.CycleCount());
|
ret += fmt::format("cycles={}", block.CycleCount());
|
||||||
ret += fmt::format(", entry_cond={}", Arm::CondToString(block.GetCondition(), true));
|
ret += fmt::format(", entry_cond={}", A32::CondToString(block.GetCondition(), true));
|
||||||
if (block.GetCondition() != Arm::Cond::AL) {
|
if (block.GetCondition() != Cond::AL) {
|
||||||
ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation());
|
ret += fmt::format(", cond_fail={}", block.ConditionFailedLocation());
|
||||||
}
|
}
|
||||||
ret += '\n';
|
ret += '\n';
|
||||||
|
@ -161,9 +162,9 @@ std::string DumpBlock(const IR::Block& block) {
|
||||||
case Type::U32:
|
case Type::U32:
|
||||||
return fmt::format("#{:#x}", arg.GetU32());
|
return fmt::format("#{:#x}", arg.GetU32());
|
||||||
case Type::RegRef:
|
case Type::RegRef:
|
||||||
return Arm::RegToString(arg.GetRegRef());
|
return A32::RegToString(arg.GetA32RegRef());
|
||||||
case Type::ExtRegRef:
|
case Type::ExtRegRef:
|
||||||
return Arm::ExtRegToString(arg.GetExtRegRef());
|
return A32::ExtRegToString(arg.GetA32ExtRegRef());
|
||||||
default:
|
default:
|
||||||
return "<unknown immediate type>";
|
return "<unknown immediate type>";
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/intrusive_list.h"
|
#include "common/intrusive_list.h"
|
||||||
#include "common/memory_pool.h"
|
#include "common/memory_pool.h"
|
||||||
|
#include "frontend/ir/cond.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/ir/microinstruction.h"
|
#include "frontend/ir/microinstruction.h"
|
||||||
#include "frontend/ir/terminal.h"
|
#include "frontend/ir/terminal.h"
|
||||||
|
@ -85,9 +86,9 @@ public:
|
||||||
void SetEndLocation(const LocationDescriptor& descriptor);
|
void SetEndLocation(const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
/// Gets the condition required to pass in order to execute this block.
|
/// Gets the condition required to pass in order to execute this block.
|
||||||
Arm::Cond GetCondition() const;
|
Cond GetCondition() const;
|
||||||
/// Sets the condition required to pass in order to execute this block.
|
/// Sets the condition required to pass in order to execute this block.
|
||||||
void SetCondition(Arm::Cond condition);
|
void SetCondition(Cond condition);
|
||||||
|
|
||||||
/// Gets the location of the block to execute if the predicated condition fails.
|
/// Gets the location of the block to execute if the predicated condition fails.
|
||||||
LocationDescriptor ConditionFailedLocation() const;
|
LocationDescriptor ConditionFailedLocation() const;
|
||||||
|
@ -124,7 +125,7 @@ private:
|
||||||
/// Description of the end location of this block
|
/// Description of the end location of this block
|
||||||
LocationDescriptor end_location;
|
LocationDescriptor end_location;
|
||||||
/// Conditional to pass in order to execute this block
|
/// Conditional to pass in order to execute this block
|
||||||
Arm::Cond cond = Arm::Cond::AL;
|
Cond cond = Cond::AL;
|
||||||
/// Block to execute next if `cond` did not pass.
|
/// Block to execute next if `cond` did not pass.
|
||||||
boost::optional<LocationDescriptor> cond_failed = {};
|
boost::optional<LocationDescriptor> cond_failed = {};
|
||||||
/// Number of cycles this block takes to execute if the conditional fails.
|
/// Number of cycles this block takes to execute if the conditional fails.
|
||||||
|
|
24
src/frontend/ir/cond.h
Normal file
24
src/frontend/ir/cond.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/* This file is part of the dynarmic project.
|
||||||
|
* Copyright (c) 2016 MerryMage
|
||||||
|
* This software may be used and distributed according to the terms of the GNU
|
||||||
|
* General Public License version 2 or any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Dynarmic {
|
||||||
|
namespace IR {
|
||||||
|
|
||||||
|
enum class Cond {
|
||||||
|
EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
|
||||||
|
HS = CS, LO = CC,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Cond invert(Cond c) {
|
||||||
|
return static_cast<Cond>(static_cast<size_t>(c) ^ 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace IR
|
||||||
|
} // namespace Dynarmic
|
|
@ -11,256 +11,256 @@
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace IR {
|
namespace IR {
|
||||||
|
|
||||||
void IREmitter::Unimplemented() {
|
void A32IREmitter::Unimplemented() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 IREmitter::PC() {
|
u32 A32IREmitter::PC() {
|
||||||
u32 offset = current_location.TFlag() ? 4 : 8;
|
u32 offset = current_location.TFlag() ? 4 : 8;
|
||||||
return current_location.PC() + offset;
|
return current_location.PC() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 IREmitter::AlignPC(size_t alignment) {
|
u32 A32IREmitter::AlignPC(size_t alignment) {
|
||||||
u32 pc = PC();
|
u32 pc = PC();
|
||||||
return static_cast<u32>(pc - pc % alignment);
|
return static_cast<u32>(pc - pc % alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Imm1(bool imm1) {
|
Value A32IREmitter::Imm1(bool imm1) {
|
||||||
return Value(imm1);
|
return Value(imm1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Imm8(u8 imm8) {
|
Value A32IREmitter::Imm8(u8 imm8) {
|
||||||
return Value(imm8);
|
return Value(imm8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Imm32(u32 imm32) {
|
Value A32IREmitter::Imm32(u32 imm32) {
|
||||||
return Value(imm32);
|
return Value(imm32);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Imm64(u64 imm64) {
|
Value A32IREmitter::Imm64(u64 imm64) {
|
||||||
return Value(imm64);
|
return Value(imm64);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetRegister(Arm::Reg reg) {
|
Value A32IREmitter::GetRegister(A32::Reg reg) {
|
||||||
if (reg == Arm::Reg::PC) {
|
if (reg == A32::Reg::PC) {
|
||||||
return Imm32(PC());
|
return Imm32(PC());
|
||||||
}
|
}
|
||||||
return Inst(Opcode::GetRegister, { Value(reg) });
|
return Inst(Opcode::GetRegister, { Value(reg) });
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetExtendedRegister(Arm::ExtReg reg) {
|
Value A32IREmitter::GetExtendedRegister(A32::ExtReg reg) {
|
||||||
if (Arm::IsSingleExtReg(reg)) {
|
if (A32::IsSingleExtReg(reg)) {
|
||||||
return Inst(Opcode::GetExtendedRegister32, {Value(reg)});
|
return Inst(Opcode::GetExtendedRegister32, {Value(reg)});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Arm::IsDoubleExtReg(reg)) {
|
if (A32::IsDoubleExtReg(reg)) {
|
||||||
return Inst(Opcode::GetExtendedRegister64, {Value(reg)});
|
return Inst(Opcode::GetExtendedRegister64, {Value(reg)});
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_MSG(false, "Invalid reg.");
|
ASSERT_MSG(false, "Invalid reg.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetRegister(const Arm::Reg reg, const Value& value) {
|
void A32IREmitter::SetRegister(const A32::Reg reg, const Value& value) {
|
||||||
ASSERT(reg != Arm::Reg::PC);
|
ASSERT(reg != A32::Reg::PC);
|
||||||
Inst(Opcode::SetRegister, { Value(reg), value });
|
Inst(Opcode::SetRegister, { Value(reg), value });
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetExtendedRegister(const Arm::ExtReg reg, const Value& value) {
|
void A32IREmitter::SetExtendedRegister(const A32::ExtReg reg, const Value& value) {
|
||||||
if (Arm::IsSingleExtReg(reg)) {
|
if (A32::IsSingleExtReg(reg)) {
|
||||||
Inst(Opcode::SetExtendedRegister32, {Value(reg), value});
|
Inst(Opcode::SetExtendedRegister32, {Value(reg), value});
|
||||||
} else if (Arm::IsDoubleExtReg(reg)) {
|
} else if (A32::IsDoubleExtReg(reg)) {
|
||||||
Inst(Opcode::SetExtendedRegister64, {Value(reg), value});
|
Inst(Opcode::SetExtendedRegister64, {Value(reg), value});
|
||||||
} else {
|
} else {
|
||||||
ASSERT_MSG(false, "Invalid reg.");
|
ASSERT_MSG(false, "Invalid reg.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::ALUWritePC(const Value& value) {
|
void A32IREmitter::ALUWritePC(const Value& value) {
|
||||||
// This behaviour is ARM version-dependent.
|
// This behaviour is ARM version-dependent.
|
||||||
// The below implementation is for ARMv6k
|
// The below implementation is for ARMv6k
|
||||||
BranchWritePC(value);
|
BranchWritePC(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::BranchWritePC(const Value& value) {
|
void A32IREmitter::BranchWritePC(const Value& value) {
|
||||||
if (!current_location.TFlag()) {
|
if (!current_location.TFlag()) {
|
||||||
auto new_pc = And(value, Imm32(0xFFFFFFFC));
|
auto new_pc = And(value, Imm32(0xFFFFFFFC));
|
||||||
Inst(Opcode::SetRegister, { Value(Arm::Reg::PC), new_pc });
|
Inst(Opcode::SetRegister, { Value(A32::Reg::PC), new_pc });
|
||||||
} else {
|
} else {
|
||||||
auto new_pc = And(value, Imm32(0xFFFFFFFE));
|
auto new_pc = And(value, Imm32(0xFFFFFFFE));
|
||||||
Inst(Opcode::SetRegister, { Value(Arm::Reg::PC), new_pc });
|
Inst(Opcode::SetRegister, { Value(A32::Reg::PC), new_pc });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::BXWritePC(const Value& value) {
|
void A32IREmitter::BXWritePC(const Value& value) {
|
||||||
Inst(Opcode::BXWritePC, {value});
|
Inst(Opcode::BXWritePC, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::LoadWritePC(const Value& value) {
|
void A32IREmitter::LoadWritePC(const Value& value) {
|
||||||
// This behaviour is ARM version-dependent.
|
// This behaviour is ARM version-dependent.
|
||||||
// The below implementation is for ARMv6k
|
// The below implementation is for ARMv6k
|
||||||
BXWritePC(value);
|
BXWritePC(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CallSupervisor(const Value& value) {
|
void A32IREmitter::CallSupervisor(const Value& value) {
|
||||||
Inst(Opcode::CallSupervisor, {value});
|
Inst(Opcode::CallSupervisor, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::PushRSB(const LocationDescriptor& return_location) {
|
void A32IREmitter::PushRSB(const A32::LocationDescriptor& return_location) {
|
||||||
Inst(Opcode::PushRSB, {Value(return_location.UniqueHash())});
|
Inst(Opcode::PushRSB, {Value(return_location.UniqueHash())});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetCpsr() {
|
Value A32IREmitter::GetCpsr() {
|
||||||
return Inst(Opcode::GetCpsr, {});
|
return Inst(Opcode::GetCpsr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetCpsr(const Value& value) {
|
void A32IREmitter::SetCpsr(const Value& value) {
|
||||||
Inst(Opcode::SetCpsr, {value});
|
Inst(Opcode::SetCpsr, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetCpsrNZCV(const Value& value) {
|
void A32IREmitter::SetCpsrNZCV(const Value& value) {
|
||||||
Inst(Opcode::SetCpsrNZCV, {value});
|
Inst(Opcode::SetCpsrNZCV, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetCpsrNZCVQ(const Value& value) {
|
void A32IREmitter::SetCpsrNZCVQ(const Value& value) {
|
||||||
Inst(Opcode::SetCpsrNZCVQ, {value});
|
Inst(Opcode::SetCpsrNZCVQ, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetCFlag() {
|
Value A32IREmitter::GetCFlag() {
|
||||||
return Inst(Opcode::GetCFlag, {});
|
return Inst(Opcode::GetCFlag, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetNFlag(const Value& value) {
|
void A32IREmitter::SetNFlag(const Value& value) {
|
||||||
Inst(Opcode::SetNFlag, {value});
|
Inst(Opcode::SetNFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetZFlag(const Value& value) {
|
void A32IREmitter::SetZFlag(const Value& value) {
|
||||||
Inst(Opcode::SetZFlag, {value});
|
Inst(Opcode::SetZFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetCFlag(const Value& value) {
|
void A32IREmitter::SetCFlag(const Value& value) {
|
||||||
Inst(Opcode::SetCFlag, {value});
|
Inst(Opcode::SetCFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetVFlag(const Value& value) {
|
void A32IREmitter::SetVFlag(const Value& value) {
|
||||||
Inst(Opcode::SetVFlag, {value});
|
Inst(Opcode::SetVFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::OrQFlag(const Value& value) {
|
void A32IREmitter::OrQFlag(const Value& value) {
|
||||||
Inst(Opcode::OrQFlag, {value});
|
Inst(Opcode::OrQFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetGEFlags() {
|
Value A32IREmitter::GetGEFlags() {
|
||||||
return Inst(Opcode::GetGEFlags, {});
|
return Inst(Opcode::GetGEFlags, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetGEFlags(const Value& value) {
|
void A32IREmitter::SetGEFlags(const Value& value) {
|
||||||
Inst(Opcode::SetGEFlags, {value});
|
Inst(Opcode::SetGEFlags, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetGEFlagsCompressed(const Value& value) {
|
void A32IREmitter::SetGEFlagsCompressed(const Value& value) {
|
||||||
Inst(Opcode::SetGEFlagsCompressed, {value});
|
Inst(Opcode::SetGEFlagsCompressed, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetFpscr() {
|
Value A32IREmitter::GetFpscr() {
|
||||||
return Inst(Opcode::GetFpscr, {});
|
return Inst(Opcode::GetFpscr, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetFpscr(const Value& new_fpscr) {
|
void A32IREmitter::SetFpscr(const Value& new_fpscr) {
|
||||||
Inst(Opcode::SetFpscr, {new_fpscr});
|
Inst(Opcode::SetFpscr, {new_fpscr});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::GetFpscrNZCV() {
|
Value A32IREmitter::GetFpscrNZCV() {
|
||||||
return Inst(Opcode::GetFpscrNZCV, {});
|
return Inst(Opcode::GetFpscrNZCV, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetFpscrNZCV(const Value& new_fpscr_nzcv) {
|
void A32IREmitter::SetFpscrNZCV(const Value& new_fpscr_nzcv) {
|
||||||
Inst(Opcode::SetFpscrNZCV, {new_fpscr_nzcv});
|
Inst(Opcode::SetFpscrNZCV, {new_fpscr_nzcv});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Pack2x32To1x64(const Value& lo, const Value& hi) {
|
Value A32IREmitter::Pack2x32To1x64(const Value& lo, const Value& hi) {
|
||||||
return Inst(Opcode::Pack2x32To1x64, {lo, hi});
|
return Inst(Opcode::Pack2x32To1x64, {lo, hi});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::LeastSignificantWord(const Value& value) {
|
Value A32IREmitter::LeastSignificantWord(const Value& value) {
|
||||||
return Inst(Opcode::LeastSignificantWord, {value});
|
return Inst(Opcode::LeastSignificantWord, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::MostSignificantWord(const Value& value) {
|
A32IREmitter::ResultAndCarry A32IREmitter::MostSignificantWord(const Value& value) {
|
||||||
auto result = Inst(Opcode::MostSignificantWord, {value});
|
auto result = Inst(Opcode::MostSignificantWord, {value});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::LeastSignificantHalf(const Value& value) {
|
Value A32IREmitter::LeastSignificantHalf(const Value& value) {
|
||||||
return Inst(Opcode::LeastSignificantHalf, {value});
|
return Inst(Opcode::LeastSignificantHalf, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::LeastSignificantByte(const Value& value) {
|
Value A32IREmitter::LeastSignificantByte(const Value& value) {
|
||||||
return Inst(Opcode::LeastSignificantByte, {value});
|
return Inst(Opcode::LeastSignificantByte, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::MostSignificantBit(const Value& value) {
|
Value A32IREmitter::MostSignificantBit(const Value& value) {
|
||||||
return Inst(Opcode::MostSignificantBit, {value});
|
return Inst(Opcode::MostSignificantBit, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::IsZero(const Value& value) {
|
Value A32IREmitter::IsZero(const Value& value) {
|
||||||
return Inst(Opcode::IsZero, {value});
|
return Inst(Opcode::IsZero, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::IsZero64(const Value& value) {
|
Value A32IREmitter::IsZero64(const Value& value) {
|
||||||
return Inst(Opcode::IsZero64, {value});
|
return Inst(Opcode::IsZero64, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::LogicalShiftLeft(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
A32IREmitter::ResultAndCarry A32IREmitter::LogicalShiftLeft(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::LogicalShiftLeft, {value_in, shift_amount, carry_in});
|
auto result = Inst(Opcode::LogicalShiftLeft, {value_in, shift_amount, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::LogicalShiftRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
A32IREmitter::ResultAndCarry A32IREmitter::LogicalShiftRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::LogicalShiftRight, {value_in, shift_amount, carry_in});
|
auto result = Inst(Opcode::LogicalShiftRight, {value_in, shift_amount, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::LogicalShiftRight64(const Value& value_in, const Value& shift_amount) {
|
Value A32IREmitter::LogicalShiftRight64(const Value& value_in, const Value& shift_amount) {
|
||||||
return Inst(Opcode::LogicalShiftRight64, {value_in, shift_amount});
|
return Inst(Opcode::LogicalShiftRight64, {value_in, shift_amount});
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::ArithmeticShiftRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
A32IREmitter::ResultAndCarry A32IREmitter::ArithmeticShiftRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::ArithmeticShiftRight, {value_in, shift_amount, carry_in});
|
auto result = Inst(Opcode::ArithmeticShiftRight, {value_in, shift_amount, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::RotateRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
A32IREmitter::ResultAndCarry A32IREmitter::RotateRight(const Value& value_in, const Value& shift_amount, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::RotateRight, {value_in, shift_amount, carry_in});
|
auto result = Inst(Opcode::RotateRight, {value_in, shift_amount, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarry IREmitter::RotateRightExtended(const Value& value_in, const Value& carry_in) {
|
A32IREmitter::ResultAndCarry A32IREmitter::RotateRightExtended(const Value& value_in, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::RotateRightExtended, {value_in, carry_in});
|
auto result = Inst(Opcode::RotateRightExtended, {value_in, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
return {result, carry_out};
|
return {result, carry_out};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarryAndOverflow IREmitter::AddWithCarry(const Value& a, const Value& b, const Value& carry_in) {
|
A32IREmitter::ResultAndCarryAndOverflow A32IREmitter::AddWithCarry(const Value& a, const Value& b, const Value& carry_in) {
|
||||||
auto result = Inst(Opcode::AddWithCarry, {a, b, carry_in});
|
auto result = Inst(Opcode::AddWithCarry, {a, b, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
||||||
return {result, carry_out, overflow};
|
return {result, carry_out, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Add(const Value& a, const Value& b) {
|
Value A32IREmitter::Add(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::AddWithCarry, {a, b, Imm1(0)});
|
return Inst(Opcode::AddWithCarry, {a, b, Imm1(0)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Add64(const Value& a, const Value& b) {
|
Value A32IREmitter::Add64(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Add64, {a, b});
|
return Inst(Opcode::Add64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(const Value& a, const Value& b, const Value& carry_in) {
|
A32IREmitter::ResultAndCarryAndOverflow A32IREmitter::SubWithCarry(const Value& a, const Value& b, const Value& carry_in) {
|
||||||
// This is equivalent to AddWithCarry(a, Not(b), carry_in).
|
// This is equivalent to AddWithCarry(a, Not(b), carry_in).
|
||||||
auto result = Inst(Opcode::SubWithCarry, {a, b, carry_in});
|
auto result = Inst(Opcode::SubWithCarry, {a, b, carry_in});
|
||||||
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
auto carry_out = Inst(Opcode::GetCarryFromOp, {result});
|
||||||
|
@ -268,437 +268,437 @@ IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(const Value& a, con
|
||||||
return {result, carry_out, overflow};
|
return {result, carry_out, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Sub(const Value& a, const Value& b) {
|
Value A32IREmitter::Sub(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::SubWithCarry, {a, b, Imm1(1)});
|
return Inst(Opcode::SubWithCarry, {a, b, Imm1(1)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Sub64(const Value& a, const Value& b) {
|
Value A32IREmitter::Sub64(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Sub64, {a, b});
|
return Inst(Opcode::Sub64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Mul(const Value& a, const Value& b) {
|
Value A32IREmitter::Mul(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Mul, {a, b});
|
return Inst(Opcode::Mul, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Mul64(const Value& a, const Value& b) {
|
Value A32IREmitter::Mul64(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Mul64, {a, b});
|
return Inst(Opcode::Mul64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::And(const Value& a, const Value& b) {
|
Value A32IREmitter::And(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::And, {a, b});
|
return Inst(Opcode::And, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Eor(const Value& a, const Value& b) {
|
Value A32IREmitter::Eor(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Eor, {a, b});
|
return Inst(Opcode::Eor, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Or(const Value& a, const Value& b) {
|
Value A32IREmitter::Or(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::Or, {a, b});
|
return Inst(Opcode::Or, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Not(const Value& a) {
|
Value A32IREmitter::Not(const Value& a) {
|
||||||
return Inst(Opcode::Not, {a});
|
return Inst(Opcode::Not, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::SignExtendWordToLong(const Value& a) {
|
Value A32IREmitter::SignExtendWordToLong(const Value& a) {
|
||||||
return Inst(Opcode::SignExtendWordToLong, {a});
|
return Inst(Opcode::SignExtendWordToLong, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::SignExtendHalfToWord(const Value& a) {
|
Value A32IREmitter::SignExtendHalfToWord(const Value& a) {
|
||||||
return Inst(Opcode::SignExtendHalfToWord, {a});
|
return Inst(Opcode::SignExtendHalfToWord, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::SignExtendByteToWord(const Value& a) {
|
Value A32IREmitter::SignExtendByteToWord(const Value& a) {
|
||||||
return Inst(Opcode::SignExtendByteToWord, {a});
|
return Inst(Opcode::SignExtendByteToWord, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ZeroExtendWordToLong(const Value& a) {
|
Value A32IREmitter::ZeroExtendWordToLong(const Value& a) {
|
||||||
return Inst(Opcode::ZeroExtendWordToLong, {a});
|
return Inst(Opcode::ZeroExtendWordToLong, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ZeroExtendHalfToWord(const Value& a) {
|
Value A32IREmitter::ZeroExtendHalfToWord(const Value& a) {
|
||||||
return Inst(Opcode::ZeroExtendHalfToWord, {a});
|
return Inst(Opcode::ZeroExtendHalfToWord, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ZeroExtendByteToWord(const Value& a) {
|
Value A32IREmitter::ZeroExtendByteToWord(const Value& a) {
|
||||||
return Inst(Opcode::ZeroExtendByteToWord, {a});
|
return Inst(Opcode::ZeroExtendByteToWord, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ByteReverseWord(const Value& a) {
|
Value A32IREmitter::ByteReverseWord(const Value& a) {
|
||||||
return Inst(Opcode::ByteReverseWord, {a});
|
return Inst(Opcode::ByteReverseWord, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ByteReverseHalf(const Value& a) {
|
Value A32IREmitter::ByteReverseHalf(const Value& a) {
|
||||||
return Inst(Opcode::ByteReverseHalf, {a});
|
return Inst(Opcode::ByteReverseHalf, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ByteReverseDual(const Value& a) {
|
Value A32IREmitter::ByteReverseDual(const Value& a) {
|
||||||
return Inst(Opcode::ByteReverseDual, {a});
|
return Inst(Opcode::ByteReverseDual, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::CountLeadingZeros(const Value& a) {
|
Value A32IREmitter::CountLeadingZeros(const Value& a) {
|
||||||
return Inst(Opcode::CountLeadingZeros, {a});
|
return Inst(Opcode::CountLeadingZeros, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndOverflow IREmitter::SignedSaturatedAdd(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndOverflow A32IREmitter::SignedSaturatedAdd(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::SignedSaturatedAdd, {a, b});
|
auto result = Inst(Opcode::SignedSaturatedAdd, {a, b});
|
||||||
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
||||||
return {result, overflow};
|
return {result, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndOverflow IREmitter::SignedSaturatedSub(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndOverflow A32IREmitter::SignedSaturatedSub(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::SignedSaturatedSub, {a, b});
|
auto result = Inst(Opcode::SignedSaturatedSub, {a, b});
|
||||||
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
||||||
return {result, overflow};
|
return {result, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndOverflow IREmitter::UnsignedSaturation(const Value& a, size_t bit_size_to_saturate_to) {
|
A32IREmitter::ResultAndOverflow A32IREmitter::UnsignedSaturation(const Value& a, size_t bit_size_to_saturate_to) {
|
||||||
ASSERT(bit_size_to_saturate_to <= 31);
|
ASSERT(bit_size_to_saturate_to <= 31);
|
||||||
auto result = Inst(Opcode::UnsignedSaturation, {a, Imm8(static_cast<u8>(bit_size_to_saturate_to))});
|
auto result = Inst(Opcode::UnsignedSaturation, {a, Imm8(static_cast<u8>(bit_size_to_saturate_to))});
|
||||||
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
||||||
return {result, overflow};
|
return {result, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndOverflow IREmitter::SignedSaturation(const Value& a, size_t bit_size_to_saturate_to) {
|
A32IREmitter::ResultAndOverflow A32IREmitter::SignedSaturation(const Value& a, size_t bit_size_to_saturate_to) {
|
||||||
ASSERT(bit_size_to_saturate_to >= 1 && bit_size_to_saturate_to <= 32);
|
ASSERT(bit_size_to_saturate_to >= 1 && bit_size_to_saturate_to <= 32);
|
||||||
auto result = Inst(Opcode::SignedSaturation, {a, Imm8(static_cast<u8>(bit_size_to_saturate_to))});
|
auto result = Inst(Opcode::SignedSaturation, {a, Imm8(static_cast<u8>(bit_size_to_saturate_to))});
|
||||||
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
auto overflow = Inst(Opcode::GetOverflowFromOp, {result});
|
||||||
return {result, overflow};
|
return {result, overflow};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddU8(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddU8(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddU8, {a, b});
|
auto result = Inst(Opcode::PackedAddU8, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddS8(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddS8(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddS8, {a, b});
|
auto result = Inst(Opcode::PackedAddS8, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddU16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddU16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddU16, {a, b});
|
auto result = Inst(Opcode::PackedAddU16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddS16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddS16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddS16, {a, b});
|
auto result = Inst(Opcode::PackedAddS16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubU8(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubU8(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubU8, {a, b});
|
auto result = Inst(Opcode::PackedSubU8, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubS8(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubS8(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubS8, {a, b});
|
auto result = Inst(Opcode::PackedSubS8, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubU16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubU16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubU16, {a, b});
|
auto result = Inst(Opcode::PackedSubU16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubS16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubS16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubS16, {a, b});
|
auto result = Inst(Opcode::PackedSubS16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddSubU16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddSubU16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddSubU16, {a, b});
|
auto result = Inst(Opcode::PackedAddSubU16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedAddSubS16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedAddSubS16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedAddSubS16, {a, b});
|
auto result = Inst(Opcode::PackedAddSubS16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubAddU16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubAddU16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubAddU16, {a, b});
|
auto result = Inst(Opcode::PackedSubAddU16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
IREmitter::ResultAndGE IREmitter::PackedSubAddS16(const Value& a, const Value& b) {
|
A32IREmitter::ResultAndGE A32IREmitter::PackedSubAddS16(const Value& a, const Value& b) {
|
||||||
auto result = Inst(Opcode::PackedSubAddS16, {a, b});
|
auto result = Inst(Opcode::PackedSubAddS16, {a, b});
|
||||||
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
auto ge = Inst(Opcode::GetGEFromOp, {result});
|
||||||
return {result, ge};
|
return {result, ge};
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddU8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddU8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddU8, {a, b});
|
return Inst(Opcode::PackedHalvingAddU8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddS8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddS8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddS8, {a, b});
|
return Inst(Opcode::PackedHalvingAddS8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubU8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubU8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubU8, {a, b});
|
return Inst(Opcode::PackedHalvingSubU8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubS8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubS8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubS8, {a, b});
|
return Inst(Opcode::PackedHalvingSubS8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddU16, {a, b});
|
return Inst(Opcode::PackedHalvingAddU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddS16, {a, b});
|
return Inst(Opcode::PackedHalvingAddS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubU16, {a, b});
|
return Inst(Opcode::PackedHalvingSubU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubS16, {a, b});
|
return Inst(Opcode::PackedHalvingSubS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddSubU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddSubU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddSubU16, {a, b});
|
return Inst(Opcode::PackedHalvingAddSubU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingAddSubS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingAddSubS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingAddSubS16, {a, b});
|
return Inst(Opcode::PackedHalvingAddSubS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubAddU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubAddU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubAddU16, {a, b});
|
return Inst(Opcode::PackedHalvingSubAddU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedHalvingSubAddS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedHalvingSubAddS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedHalvingSubAddS16, {a, b});
|
return Inst(Opcode::PackedHalvingSubAddS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedAddU8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedAddU8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedAddU8, {a, b});
|
return Inst(Opcode::PackedSaturatedAddU8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedAddS8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedAddS8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedAddS8, {a, b});
|
return Inst(Opcode::PackedSaturatedAddS8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedSubU8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedSubU8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedSubU8, {a, b});
|
return Inst(Opcode::PackedSaturatedSubU8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedSubS8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedSubS8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedSubS8, {a, b});
|
return Inst(Opcode::PackedSaturatedSubS8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedAddU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedAddU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedAddU16, {a, b});
|
return Inst(Opcode::PackedSaturatedAddU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedAddS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedAddS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedAddS16, {a, b});
|
return Inst(Opcode::PackedSaturatedAddS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedSubU16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedSubU16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedSubU16, {a, b});
|
return Inst(Opcode::PackedSaturatedSubU16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSaturatedSubS16(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSaturatedSubS16(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSaturatedSubS16, {a, b});
|
return Inst(Opcode::PackedSaturatedSubS16, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedAbsDiffSumS8(const Value& a, const Value& b) {
|
Value A32IREmitter::PackedAbsDiffSumS8(const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedAbsDiffSumS8, {a, b});
|
return Inst(Opcode::PackedAbsDiffSumS8, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::PackedSelect(const Value& ge, const Value& a, const Value& b) {
|
Value A32IREmitter::PackedSelect(const Value& ge, const Value& a, const Value& b) {
|
||||||
return Inst(Opcode::PackedSelect, {ge, a, b});
|
return Inst(Opcode::PackedSelect, {ge, a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::TransferToFP32(const Value& a) {
|
Value A32IREmitter::TransferToFP32(const Value& a) {
|
||||||
return Inst(Opcode::TransferToFP32, {a});
|
return Inst(Opcode::TransferToFP32, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::TransferToFP64(const Value& a) {
|
Value A32IREmitter::TransferToFP64(const Value& a) {
|
||||||
return Inst(Opcode::TransferToFP64, {a});
|
return Inst(Opcode::TransferToFP64, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::TransferFromFP32(const Value& a) {
|
Value A32IREmitter::TransferFromFP32(const Value& a) {
|
||||||
return Inst(Opcode::TransferFromFP32, {a});
|
return Inst(Opcode::TransferFromFP32, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::TransferFromFP64(const Value& a) {
|
Value A32IREmitter::TransferFromFP64(const Value& a) {
|
||||||
return Inst(Opcode::TransferFromFP64, {a});
|
return Inst(Opcode::TransferFromFP64, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPAbs32(const Value& a) {
|
Value A32IREmitter::FPAbs32(const Value& a) {
|
||||||
return Inst(Opcode::FPAbs32, {a});
|
return Inst(Opcode::FPAbs32, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPAbs64(const Value& a) {
|
Value A32IREmitter::FPAbs64(const Value& a) {
|
||||||
return Inst(Opcode::FPAbs64, {a});
|
return Inst(Opcode::FPAbs64, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPAdd32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPAdd32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPAdd32, {a, b});
|
return Inst(Opcode::FPAdd32, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPAdd64(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPAdd64(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPAdd64, {a, b});
|
return Inst(Opcode::FPAdd64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::FPCompare32(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
void A32IREmitter::FPCompare32(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
Inst(Opcode::FPCompare32, {a, b, Imm1(exc_on_qnan)});
|
Inst(Opcode::FPCompare32, {a, b, Imm1(exc_on_qnan)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::FPCompare64(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
void A32IREmitter::FPCompare64(const Value& a, const Value& b, bool exc_on_qnan, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
Inst(Opcode::FPCompare64, {a, b, Imm1(exc_on_qnan)});
|
Inst(Opcode::FPCompare64, {a, b, Imm1(exc_on_qnan)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPDiv32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDiv32, {a, b});
|
return Inst(Opcode::FPDiv32, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDiv64(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPDiv64(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDiv64, {a, b});
|
return Inst(Opcode::FPDiv64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPMul32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPMul32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPMul32, {a, b});
|
return Inst(Opcode::FPMul32, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPMul64(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPMul64(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPMul64, {a, b});
|
return Inst(Opcode::FPMul64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPNeg32(const Value& a) {
|
Value A32IREmitter::FPNeg32(const Value& a) {
|
||||||
return Inst(Opcode::FPNeg32, {a});
|
return Inst(Opcode::FPNeg32, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPNeg64(const Value& a) {
|
Value A32IREmitter::FPNeg64(const Value& a) {
|
||||||
return Inst(Opcode::FPNeg64, {a});
|
return Inst(Opcode::FPNeg64, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSqrt32(const Value& a) {
|
Value A32IREmitter::FPSqrt32(const Value& a) {
|
||||||
return Inst(Opcode::FPSqrt32, {a});
|
return Inst(Opcode::FPSqrt32, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSqrt64(const Value& a) {
|
Value A32IREmitter::FPSqrt64(const Value& a) {
|
||||||
return Inst(Opcode::FPSqrt64, {a});
|
return Inst(Opcode::FPSqrt64, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSub32(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPSub32(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPSub32, {a, b});
|
return Inst(Opcode::FPSub32, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSub64(const Value& a, const Value& b, bool fpscr_controlled) {
|
Value A32IREmitter::FPSub64(const Value& a, const Value& b, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPSub64, {a, b});
|
return Inst(Opcode::FPSub64, {a, b});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDoubleToSingle(const Value& a, bool fpscr_controlled) {
|
Value A32IREmitter::FPDoubleToSingle(const Value& a, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDoubleToSingle, {a});
|
return Inst(Opcode::FPDoubleToSingle, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSingleToDouble(const Value& a, bool fpscr_controlled) {
|
Value A32IREmitter::FPSingleToDouble(const Value& a, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPSingleToDouble, {a});
|
return Inst(Opcode::FPSingleToDouble, {a});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSingleToS32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
Value A32IREmitter::FPSingleToS32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPSingleToS32, {a, Imm1(round_towards_zero)});
|
return Inst(Opcode::FPSingleToS32, {a, Imm1(round_towards_zero)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPSingleToU32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
Value A32IREmitter::FPSingleToU32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPSingleToU32, {a, Imm1(round_towards_zero)});
|
return Inst(Opcode::FPSingleToU32, {a, Imm1(round_towards_zero)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDoubleToS32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
Value A32IREmitter::FPDoubleToS32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDoubleToS32, {a, Imm1(round_towards_zero)});
|
return Inst(Opcode::FPDoubleToS32, {a, Imm1(round_towards_zero)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPDoubleToU32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
Value A32IREmitter::FPDoubleToU32(const Value& a, bool round_towards_zero, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPDoubleToU32, {a, Imm1(round_towards_zero)});
|
return Inst(Opcode::FPDoubleToU32, {a, Imm1(round_towards_zero)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPS32ToSingle(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
Value A32IREmitter::FPS32ToSingle(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPS32ToSingle, {a, Imm1(round_to_nearest)});
|
return Inst(Opcode::FPS32ToSingle, {a, Imm1(round_to_nearest)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPU32ToSingle(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
Value A32IREmitter::FPU32ToSingle(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPU32ToSingle, {a, Imm1(round_to_nearest)});
|
return Inst(Opcode::FPU32ToSingle, {a, Imm1(round_to_nearest)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPS32ToDouble(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
Value A32IREmitter::FPS32ToDouble(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPS32ToDouble, {a, Imm1(round_to_nearest)});
|
return Inst(Opcode::FPS32ToDouble, {a, Imm1(round_to_nearest)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::FPU32ToDouble(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
Value A32IREmitter::FPU32ToDouble(const Value& a, bool round_to_nearest, bool fpscr_controlled) {
|
||||||
ASSERT(fpscr_controlled);
|
ASSERT(fpscr_controlled);
|
||||||
return Inst(Opcode::FPU32ToDouble, {a, Imm1(round_to_nearest)});
|
return Inst(Opcode::FPU32ToDouble, {a, Imm1(round_to_nearest)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::ClearExclusive() {
|
void A32IREmitter::ClearExclusive() {
|
||||||
Inst(Opcode::ClearExclusive, {});
|
Inst(Opcode::ClearExclusive, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetExclusive(const Value& vaddr, size_t byte_size) {
|
void A32IREmitter::SetExclusive(const Value& vaddr, size_t byte_size) {
|
||||||
ASSERT(byte_size == 1 || byte_size == 2 || byte_size == 4 || byte_size == 8 || byte_size == 16);
|
ASSERT(byte_size == 1 || byte_size == 2 || byte_size == 4 || byte_size == 8 || byte_size == 16);
|
||||||
Inst(Opcode::SetExclusive, {vaddr, Imm8(u8(byte_size))});
|
Inst(Opcode::SetExclusive, {vaddr, Imm8(u8(byte_size))});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ReadMemory8(const Value& vaddr) {
|
Value A32IREmitter::ReadMemory8(const Value& vaddr) {
|
||||||
return Inst(Opcode::ReadMemory8, {vaddr});
|
return Inst(Opcode::ReadMemory8, {vaddr});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ReadMemory16(const Value& vaddr) {
|
Value A32IREmitter::ReadMemory16(const Value& vaddr) {
|
||||||
auto value = Inst(Opcode::ReadMemory16, {vaddr});
|
auto value = Inst(Opcode::ReadMemory16, {vaddr});
|
||||||
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
return current_location.EFlag() ? ByteReverseHalf(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ReadMemory32(const Value& vaddr) {
|
Value A32IREmitter::ReadMemory32(const Value& vaddr) {
|
||||||
auto value = Inst(Opcode::ReadMemory32, {vaddr});
|
auto value = Inst(Opcode::ReadMemory32, {vaddr});
|
||||||
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
return current_location.EFlag() ? ByteReverseWord(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ReadMemory64(const Value& vaddr) {
|
Value A32IREmitter::ReadMemory64(const Value& vaddr) {
|
||||||
auto value = Inst(Opcode::ReadMemory64, {vaddr});
|
auto value = Inst(Opcode::ReadMemory64, {vaddr});
|
||||||
return current_location.EFlag() ? ByteReverseDual(value) : value;
|
return current_location.EFlag() ? ByteReverseDual(value) : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory8(const Value& vaddr, const Value& value) {
|
void A32IREmitter::WriteMemory8(const Value& vaddr, const Value& value) {
|
||||||
Inst(Opcode::WriteMemory8, {vaddr, value});
|
Inst(Opcode::WriteMemory8, {vaddr, value});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory16(const Value& vaddr, const Value& value) {
|
void A32IREmitter::WriteMemory16(const Value& vaddr, const Value& value) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto v = ByteReverseHalf(value);
|
auto v = ByteReverseHalf(value);
|
||||||
Inst(Opcode::WriteMemory16, {vaddr, v});
|
Inst(Opcode::WriteMemory16, {vaddr, v});
|
||||||
|
@ -707,7 +707,7 @@ void IREmitter::WriteMemory16(const Value& vaddr, const Value& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory32(const Value& vaddr, const Value& value) {
|
void A32IREmitter::WriteMemory32(const Value& vaddr, const Value& value) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto v = ByteReverseWord(value);
|
auto v = ByteReverseWord(value);
|
||||||
Inst(Opcode::WriteMemory32, {vaddr, v});
|
Inst(Opcode::WriteMemory32, {vaddr, v});
|
||||||
|
@ -716,7 +716,7 @@ void IREmitter::WriteMemory32(const Value& vaddr, const Value& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::WriteMemory64(const Value& vaddr, const Value& value) {
|
void A32IREmitter::WriteMemory64(const Value& vaddr, const Value& value) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto v = ByteReverseDual(value);
|
auto v = ByteReverseDual(value);
|
||||||
Inst(Opcode::WriteMemory64, {vaddr, v});
|
Inst(Opcode::WriteMemory64, {vaddr, v});
|
||||||
|
@ -725,11 +725,11 @@ void IREmitter::WriteMemory64(const Value& vaddr, const Value& value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ExclusiveWriteMemory8(const Value& vaddr, const Value& value) {
|
Value A32IREmitter::ExclusiveWriteMemory8(const Value& vaddr, const Value& value) {
|
||||||
return Inst(Opcode::ExclusiveWriteMemory8, {vaddr, value});
|
return Inst(Opcode::ExclusiveWriteMemory8, {vaddr, value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ExclusiveWriteMemory16(const Value& vaddr, const Value& value) {
|
Value A32IREmitter::ExclusiveWriteMemory16(const Value& vaddr, const Value& value) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto v = ByteReverseHalf(value);
|
auto v = ByteReverseHalf(value);
|
||||||
return Inst(Opcode::ExclusiveWriteMemory16, {vaddr, v});
|
return Inst(Opcode::ExclusiveWriteMemory16, {vaddr, v});
|
||||||
|
@ -738,7 +738,7 @@ Value IREmitter::ExclusiveWriteMemory16(const Value& vaddr, const Value& value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ExclusiveWriteMemory32(const Value& vaddr, const Value& value) {
|
Value A32IREmitter::ExclusiveWriteMemory32(const Value& vaddr, const Value& value) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto v = ByteReverseWord(value);
|
auto v = ByteReverseWord(value);
|
||||||
return Inst(Opcode::ExclusiveWriteMemory32, {vaddr, v});
|
return Inst(Opcode::ExclusiveWriteMemory32, {vaddr, v});
|
||||||
|
@ -747,7 +747,7 @@ Value IREmitter::ExclusiveWriteMemory32(const Value& vaddr, const Value& value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::ExclusiveWriteMemory64(const Value& vaddr, const Value& value_lo, const Value& value_hi) {
|
Value A32IREmitter::ExclusiveWriteMemory64(const Value& vaddr, const Value& value_lo, const Value& value_hi) {
|
||||||
if (current_location.EFlag()) {
|
if (current_location.EFlag()) {
|
||||||
auto vlo = ByteReverseWord(value_lo);
|
auto vlo = ByteReverseWord(value_lo);
|
||||||
auto vhi = ByteReverseWord(value_hi);
|
auto vhi = ByteReverseWord(value_hi);
|
||||||
|
@ -757,7 +757,7 @@ Value IREmitter::ExclusiveWriteMemory64(const Value& vaddr, const Value& value_l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRd, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2) {
|
void A32IREmitter::CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRd, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -769,7 +769,7 @@ void IREmitter::CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1,
|
||||||
Inst(Opcode::CoprocInternalOperation, {Value(coproc_info)});
|
Inst(Opcode::CoprocInternalOperation, {Value(coproc_info)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2, const Value& word) {
|
void A32IREmitter::CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2, const Value& word) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -780,7 +780,7 @@ void IREmitter::CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, Arm::
|
||||||
Inst(Opcode::CoprocSendOneWord, {Value(coproc_info), word});
|
Inst(Opcode::CoprocSendOneWord, {Value(coproc_info), word});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm, const Value& word1, const Value& word2) {
|
void A32IREmitter::CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, A32::CoprocReg CRm, const Value& word1, const Value& word2) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -789,7 +789,7 @@ void IREmitter::CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, Arm::
|
||||||
Inst(Opcode::CoprocSendTwoWords, {Value(coproc_info), word1, word2});
|
Inst(Opcode::CoprocSendTwoWords, {Value(coproc_info), word1, word2});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2) {
|
Value A32IREmitter::CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -800,7 +800,7 @@ Value IREmitter::CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, Arm::
|
||||||
return Inst(Opcode::CoprocGetOneWord, {Value(coproc_info)});
|
return Inst(Opcode::CoprocGetOneWord, {Value(coproc_info)});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm) {
|
Value A32IREmitter::CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, A32::CoprocReg CRm) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -809,7 +809,7 @@ Value IREmitter::CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, Arm::
|
||||||
return Inst(Opcode::CoprocGetTwoWords, {Value(coproc_info)});
|
return Inst(Opcode::CoprocGetTwoWords, {Value(coproc_info)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
void A32IREmitter::CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, A32::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -820,7 +820,7 @@ void IREmitter::CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer,
|
||||||
Inst(Opcode::CoprocLoadWords, {Value(coproc_info), address});
|
Inst(Opcode::CoprocLoadWords, {Value(coproc_info), address});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
void A32IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, A32::CoprocReg CRd, const Value& address, bool has_option, u8 option) {
|
||||||
ASSERT(coproc_no <= 15);
|
ASSERT(coproc_no <= 15);
|
||||||
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
std::array<u8, 8> coproc_info{static_cast<u8>(coproc_no),
|
||||||
static_cast<u8>(two ? 1 : 0),
|
static_cast<u8>(two ? 1 : 0),
|
||||||
|
@ -831,15 +831,15 @@ void IREmitter::CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer,
|
||||||
Inst(Opcode::CoprocStoreWords, {Value(coproc_info), address});
|
Inst(Opcode::CoprocStoreWords, {Value(coproc_info), address});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::Breakpoint() {
|
void A32IREmitter::Breakpoint() {
|
||||||
Inst(Opcode::Breakpoint, {});
|
Inst(Opcode::Breakpoint, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IREmitter::SetTerm(const Terminal& terminal) {
|
void A32IREmitter::SetTerm(const Terminal& terminal) {
|
||||||
block.SetTerminal(terminal);
|
block.SetTerminal(terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Inst(Opcode op, std::initializer_list<Value> args) {
|
Value A32IREmitter::Inst(Opcode op, std::initializer_list<Value> args) {
|
||||||
block.AppendNewInst(op, args);
|
block.AppendNewInst(op, args);
|
||||||
return Value(&block.back());
|
return Value(&block.back());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <dynarmic/coprocessor_util.h>
|
#include <dynarmic/coprocessor_util.h>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
#include "frontend/A32/types.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/ir/terminal.h"
|
#include "frontend/ir/terminal.h"
|
||||||
|
@ -33,12 +35,12 @@ enum class Opcode;
|
||||||
* `block` is the resulting block.
|
* `block` is the resulting block.
|
||||||
* The user of this class updates `current_location` as appropriate.
|
* The user of this class updates `current_location` as appropriate.
|
||||||
*/
|
*/
|
||||||
class IREmitter {
|
class A32IREmitter {
|
||||||
public:
|
public:
|
||||||
explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
explicit A32IREmitter(A32::LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
|
||||||
|
|
||||||
Block block;
|
Block block;
|
||||||
LocationDescriptor current_location;
|
A32::LocationDescriptor current_location;
|
||||||
|
|
||||||
struct ResultAndCarry {
|
struct ResultAndCarry {
|
||||||
Value result;
|
Value result;
|
||||||
|
@ -70,17 +72,17 @@ public:
|
||||||
Value Imm32(u32 value);
|
Value Imm32(u32 value);
|
||||||
Value Imm64(u64 value);
|
Value Imm64(u64 value);
|
||||||
|
|
||||||
Value GetRegister(Arm::Reg source_reg);
|
Value GetRegister(A32::Reg source_reg);
|
||||||
Value GetExtendedRegister(Arm::ExtReg source_reg);
|
Value GetExtendedRegister(A32::ExtReg source_reg);
|
||||||
void SetRegister(const Arm::Reg dest_reg, const Value& value);
|
void SetRegister(const A32::Reg dest_reg, const Value& value);
|
||||||
void SetExtendedRegister(const Arm::ExtReg dest_reg, const Value& value);
|
void SetExtendedRegister(const A32::ExtReg dest_reg, const Value& value);
|
||||||
|
|
||||||
void ALUWritePC(const Value& value);
|
void ALUWritePC(const Value& value);
|
||||||
void BranchWritePC(const Value& value);
|
void BranchWritePC(const Value& value);
|
||||||
void BXWritePC(const Value& value);
|
void BXWritePC(const Value& value);
|
||||||
void LoadWritePC(const Value& value);
|
void LoadWritePC(const Value& value);
|
||||||
void CallSupervisor(const Value& value);
|
void CallSupervisor(const Value& value);
|
||||||
void PushRSB(const LocationDescriptor& return_location);
|
void PushRSB(const A32::LocationDescriptor& return_location);
|
||||||
|
|
||||||
Value GetCpsr();
|
Value GetCpsr();
|
||||||
void SetCpsr(const Value& value);
|
void SetCpsr(const Value& value);
|
||||||
|
@ -225,13 +227,13 @@ public:
|
||||||
Value ExclusiveWriteMemory32(const Value& vaddr, const Value& value);
|
Value ExclusiveWriteMemory32(const Value& vaddr, const Value& value);
|
||||||
Value ExclusiveWriteMemory64(const Value& vaddr, const Value& value_lo, const Value& value_hi);
|
Value ExclusiveWriteMemory64(const Value& vaddr, const Value& value_lo, const Value& value_hi);
|
||||||
|
|
||||||
void CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRd, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2);
|
void CoprocInternalOperation(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRd, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2);
|
||||||
void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2, const Value& word);
|
void CoprocSendOneWord(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2, const Value& word);
|
||||||
void CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm, const Value& word1, const Value& word2);
|
void CoprocSendTwoWords(size_t coproc_no, bool two, size_t opc, A32::CoprocReg CRm, const Value& word1, const Value& word2);
|
||||||
Value CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, Arm::CoprocReg CRn, Arm::CoprocReg CRm, size_t opc2);
|
Value CoprocGetOneWord(size_t coproc_no, bool two, size_t opc1, A32::CoprocReg CRn, A32::CoprocReg CRm, size_t opc2);
|
||||||
Value CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, Arm::CoprocReg CRm);
|
Value CoprocGetTwoWords(size_t coproc_no, bool two, size_t opc, A32::CoprocReg CRm);
|
||||||
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
void CoprocLoadWords(size_t coproc_no, bool two, bool long_transfer, A32::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
||||||
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, Arm::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
void CoprocStoreWords(size_t coproc_no, bool two, bool long_transfer, A32::CoprocReg CRd, const Value& address, bool has_option, u8 option);
|
||||||
|
|
||||||
void Breakpoint();
|
void Breakpoint();
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,14 @@
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace IR {
|
namespace IR {
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& loc) {
|
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor) {
|
||||||
o << fmt::format("{{{},{},{},{}}}",
|
o << fmt::format("{{{{}}}}", descriptor.value);
|
||||||
loc.PC(),
|
|
||||||
loc.TFlag() ? "T" : "!T",
|
|
||||||
loc.EFlag() ? "E" : "!E",
|
|
||||||
loc.FPSCR().Value());
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,110 +6,42 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <tuple>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/arm/FPSCR.h"
|
|
||||||
#include "frontend/arm/PSR.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace IR {
|
namespace IR {
|
||||||
|
|
||||||
/**
|
|
||||||
* LocationDescriptor describes the location of a basic block.
|
|
||||||
* The location is not solely based on the PC because other flags influence the way
|
|
||||||
* instructions should be translated. The CPSR.T flag is most notable since it
|
|
||||||
* tells us if the processor is in Thumb or Arm mode.
|
|
||||||
*/
|
|
||||||
class LocationDescriptor {
|
class LocationDescriptor {
|
||||||
public:
|
public:
|
||||||
// Indicates bits that should be preserved within descriptors.
|
|
||||||
static constexpr u32 CPSR_MODE_MASK = 0x00000220;
|
|
||||||
static constexpr u32 FPSCR_MODE_MASK = 0x03F79F00;
|
|
||||||
|
|
||||||
LocationDescriptor(u32 arm_pc, Arm::PSR cpsr, Arm::FPSCR fpscr)
|
|
||||||
: arm_pc(arm_pc), cpsr(cpsr.Value() & CPSR_MODE_MASK), fpscr(fpscr.Value() & FPSCR_MODE_MASK) {}
|
|
||||||
|
|
||||||
u32 PC() const { return arm_pc; }
|
|
||||||
bool TFlag() const { return cpsr.T(); }
|
|
||||||
bool EFlag() const { return cpsr.E(); }
|
|
||||||
|
|
||||||
Arm::PSR CPSR() const { return cpsr; }
|
|
||||||
Arm::FPSCR FPSCR() const { return fpscr; }
|
|
||||||
|
|
||||||
bool operator == (const LocationDescriptor& o) const {
|
bool operator == (const LocationDescriptor& o) const {
|
||||||
return std::tie(arm_pc, cpsr, fpscr) == std::tie(o.arm_pc, o.cpsr, o.fpscr);
|
return value == o.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator != (const LocationDescriptor& o) const {
|
bool operator != (const LocationDescriptor& o) const {
|
||||||
return !operator==(o);
|
return !operator==(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
LocationDescriptor SetPC(u32 new_arm_pc) const {
|
u64 value;
|
||||||
return LocationDescriptor(new_arm_pc, cpsr, fpscr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationDescriptor AdvancePC(int amount) const {
|
|
||||||
return LocationDescriptor(static_cast<u32>(arm_pc + amount), cpsr, fpscr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationDescriptor SetTFlag(bool new_tflag) const {
|
|
||||||
Arm::PSR new_cpsr = cpsr;
|
|
||||||
new_cpsr.T(new_tflag);
|
|
||||||
|
|
||||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationDescriptor SetEFlag(bool new_eflag) const {
|
|
||||||
Arm::PSR new_cpsr = cpsr;
|
|
||||||
new_cpsr.E(new_eflag);
|
|
||||||
|
|
||||||
return LocationDescriptor(arm_pc, new_cpsr, fpscr);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocationDescriptor SetFPSCR(u32 new_fpscr) const {
|
|
||||||
return LocationDescriptor(arm_pc, cpsr, Arm::FPSCR{new_fpscr & FPSCR_MODE_MASK});
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 UniqueHash() const {
|
|
||||||
// This value MUST BE UNIQUE.
|
|
||||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
|
||||||
u64 pc_u64 = u64(arm_pc) << 32;
|
|
||||||
u64 fpscr_u64 = u64(fpscr.Value());
|
|
||||||
u64 t_u64 = cpsr.T() ? 1 : 0;
|
|
||||||
u64 e_u64 = cpsr.E() ? 2 : 0;
|
|
||||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
u32 arm_pc; ///< Current program counter value.
|
|
||||||
Arm::PSR cpsr; ///< Current program status register.
|
|
||||||
Arm::FPSCR fpscr; ///< Floating point status control register.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a string representation of a LocationDescriptor.
|
|
||||||
*
|
|
||||||
* @param o Output stream
|
|
||||||
* @param descriptor The descriptor to get a string representation of
|
|
||||||
*/
|
|
||||||
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
std::ostream& operator<<(std::ostream& o, const LocationDescriptor& descriptor);
|
||||||
|
|
||||||
} // namespace IR
|
} // namespace A32
|
||||||
} // namespace Dynarmic
|
} // namespace Dynarmic
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
template <>
|
template <>
|
||||||
struct less<Dynarmic::IR::LocationDescriptor> {
|
struct less<Dynarmic::IR::LocationDescriptor> {
|
||||||
bool operator()(const Dynarmic::IR::LocationDescriptor& x, const Dynarmic::IR::LocationDescriptor& y) const {
|
bool operator()(const Dynarmic::IR::LocationDescriptor& x, const Dynarmic::IR::LocationDescriptor& y) const {
|
||||||
return x.UniqueHash() < y.UniqueHash();
|
return x.value < y.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct hash<Dynarmic::IR::LocationDescriptor> {
|
struct hash<Dynarmic::IR::LocationDescriptor> {
|
||||||
size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const {
|
size_t operator()(const Dynarmic::IR::LocationDescriptor& x) const {
|
||||||
return std::hash<u64>()(x.UniqueHash());
|
return std::hash<u64>()(x.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <boost/variant.hpp>
|
#include <boost/variant.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "frontend/ir/cond.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
|
@ -83,8 +84,8 @@ using Terminal = boost::variant<
|
||||||
* on the run-time state of the ARM flags.
|
* on the run-time state of the ARM flags.
|
||||||
*/
|
*/
|
||||||
struct If {
|
struct If {
|
||||||
If(Arm::Cond if_, Terminal then_, Terminal else_) : if_(if_), then_(then_), else_(else_) {}
|
If(Cond if_, Terminal then_, Terminal else_) : if_(if_), then_(then_), else_(else_) {}
|
||||||
Arm::Cond if_;
|
Cond if_;
|
||||||
Terminal then_;
|
Terminal then_;
|
||||||
Terminal else_;
|
Terminal else_;
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,12 +15,12 @@ Value::Value(Inst* value) : type(Type::Opaque) {
|
||||||
inner.inst = value;
|
inner.inst = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(Arm::Reg value) : type(Type::RegRef) {
|
Value::Value(A32::Reg value) : type(Type::RegRef) {
|
||||||
inner.imm_regref = value;
|
inner.imm_a32regref = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(Arm::ExtReg value) : type(Type::ExtRegRef) {
|
Value::Value(A32::ExtReg value) : type(Type::ExtRegRef) {
|
||||||
inner.imm_extregref = value;
|
inner.imm_a32extregref = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Value(bool value) : type(Type::U1) {
|
Value::Value(bool value) : type(Type::U1) {
|
||||||
|
@ -68,14 +68,14 @@ Type Value::GetType() const {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arm::Reg Value::GetRegRef() const {
|
A32::Reg Value::GetA32RegRef() const {
|
||||||
ASSERT(type == Type::RegRef);
|
ASSERT(type == Type::RegRef);
|
||||||
return inner.imm_regref;
|
return inner.imm_a32regref;
|
||||||
}
|
}
|
||||||
|
|
||||||
Arm::ExtReg Value::GetExtRegRef() const {
|
A32::ExtReg Value::GetA32ExtRegRef() const {
|
||||||
ASSERT(type == Type::ExtRegRef);
|
ASSERT(type == Type::ExtRegRef);
|
||||||
return inner.imm_extregref;
|
return inner.imm_a32extregref;
|
||||||
}
|
}
|
||||||
|
|
||||||
Inst* Value::GetInst() const {
|
Inst* Value::GetInst() const {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/arm/types.h"
|
#include "frontend/A32/types.h"
|
||||||
|
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace IR {
|
namespace IR {
|
||||||
|
@ -22,8 +22,8 @@ class Value final {
|
||||||
public:
|
public:
|
||||||
Value() : type(Type::Void) {}
|
Value() : type(Type::Void) {}
|
||||||
explicit Value(Inst* value);
|
explicit Value(Inst* value);
|
||||||
explicit Value(Arm::Reg value);
|
explicit Value(A32::Reg value);
|
||||||
explicit Value(Arm::ExtReg value);
|
explicit Value(A32::ExtReg value);
|
||||||
explicit Value(bool value);
|
explicit Value(bool value);
|
||||||
explicit Value(u8 value);
|
explicit Value(u8 value);
|
||||||
explicit Value(u16 value);
|
explicit Value(u16 value);
|
||||||
|
@ -36,8 +36,8 @@ public:
|
||||||
Type GetType() const;
|
Type GetType() const;
|
||||||
|
|
||||||
Inst* GetInst() const;
|
Inst* GetInst() const;
|
||||||
Arm::Reg GetRegRef() const;
|
A32::Reg GetA32RegRef() const;
|
||||||
Arm::ExtReg GetExtRegRef() const;
|
A32::ExtReg GetA32ExtRegRef() const;
|
||||||
bool GetU1() const;
|
bool GetU1() const;
|
||||||
u8 GetU8() const;
|
u8 GetU8() const;
|
||||||
u16 GetU16() const;
|
u16 GetU16() const;
|
||||||
|
@ -50,8 +50,8 @@ private:
|
||||||
|
|
||||||
union {
|
union {
|
||||||
Inst* inst; // type == Type::Opaque
|
Inst* inst; // type == Type::Opaque
|
||||||
Arm::Reg imm_regref;
|
A32::Reg imm_a32regref;
|
||||||
Arm::ExtReg imm_extregref;
|
A32::ExtReg imm_a32extregref;
|
||||||
bool imm_u1;
|
bool imm_u1;
|
||||||
u8 imm_u8;
|
u8 imm_u8;
|
||||||
u16 imm_u16;
|
u16 imm_u16;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
/* This file is part of the dynarmic project.
|
|
||||||
* Copyright (c) 2016 MerryMage
|
|
||||||
* This software may be used and distributed according to the terms of the GNU
|
|
||||||
* General Public License version 2 or any later version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "frontend/ir/basic_block.h"
|
|
||||||
#include "frontend/ir/location_descriptor.h"
|
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
|
|
||||||
namespace Dynarmic {
|
|
||||||
namespace Arm {
|
|
||||||
|
|
||||||
IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
|
||||||
IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code);
|
|
||||||
|
|
||||||
IR::Block Translate(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) {
|
|
||||||
return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Arm
|
|
||||||
} // namespace Dynarmic
|
|
|
@ -55,23 +55,23 @@ void GetSetElimination(IR::Block& block) {
|
||||||
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
for (auto inst = block.begin(); inst != block.end(); ++inst) {
|
||||||
switch (inst->GetOpcode()) {
|
switch (inst->GetOpcode()) {
|
||||||
case IR::Opcode::SetRegister: {
|
case IR::Opcode::SetRegister: {
|
||||||
Arm::Reg reg = inst->GetArg(0).GetRegRef();
|
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
|
||||||
if (reg == Arm::Reg::PC)
|
if (reg == A32::Reg::PC)
|
||||||
break;
|
break;
|
||||||
size_t reg_index = static_cast<size_t>(reg);
|
size_t reg_index = static_cast<size_t>(reg);
|
||||||
do_set(reg_info[reg_index], inst->GetArg(1), inst);
|
do_set(reg_info[reg_index], inst->GetArg(1), inst);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::GetRegister: {
|
case IR::Opcode::GetRegister: {
|
||||||
Arm::Reg reg = inst->GetArg(0).GetRegRef();
|
A32::Reg reg = inst->GetArg(0).GetA32RegRef();
|
||||||
ASSERT(reg != Arm::Reg::PC);
|
ASSERT(reg != A32::Reg::PC);
|
||||||
size_t reg_index = static_cast<size_t>(reg);
|
size_t reg_index = static_cast<size_t>(reg);
|
||||||
do_get(reg_info[reg_index], inst);
|
do_get(reg_info[reg_index], inst);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::SetExtendedRegister32: {
|
case IR::Opcode::SetExtendedRegister32: {
|
||||||
Arm::ExtReg reg = inst->GetArg(0).GetExtRegRef();
|
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
|
||||||
size_t reg_index = Arm::RegNumber(reg);
|
size_t reg_index = A32::RegNumber(reg);
|
||||||
do_set(ext_reg_singles_info[reg_index], inst->GetArg(1), inst);
|
do_set(ext_reg_singles_info[reg_index], inst->GetArg(1), inst);
|
||||||
|
|
||||||
size_t doubles_reg_index = reg_index / 2;
|
size_t doubles_reg_index = reg_index / 2;
|
||||||
|
@ -81,8 +81,8 @@ void GetSetElimination(IR::Block& block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::GetExtendedRegister32: {
|
case IR::Opcode::GetExtendedRegister32: {
|
||||||
Arm::ExtReg reg = inst->GetArg(0).GetExtRegRef();
|
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
|
||||||
size_t reg_index = Arm::RegNumber(reg);
|
size_t reg_index = A32::RegNumber(reg);
|
||||||
do_get(ext_reg_singles_info[reg_index], inst);
|
do_get(ext_reg_singles_info[reg_index], inst);
|
||||||
|
|
||||||
size_t doubles_reg_index = reg_index / 2;
|
size_t doubles_reg_index = reg_index / 2;
|
||||||
|
@ -92,8 +92,8 @@ void GetSetElimination(IR::Block& block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::SetExtendedRegister64: {
|
case IR::Opcode::SetExtendedRegister64: {
|
||||||
Arm::ExtReg reg = inst->GetArg(0).GetExtRegRef();
|
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
|
||||||
size_t reg_index = Arm::RegNumber(reg);
|
size_t reg_index = A32::RegNumber(reg);
|
||||||
do_set(ext_reg_doubles_info[reg_index], inst->GetArg(1), inst);
|
do_set(ext_reg_doubles_info[reg_index], inst->GetArg(1), inst);
|
||||||
|
|
||||||
size_t singles_reg_index = reg_index * 2;
|
size_t singles_reg_index = reg_index * 2;
|
||||||
|
@ -104,8 +104,8 @@ void GetSetElimination(IR::Block& block) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case IR::Opcode::GetExtendedRegister64: {
|
case IR::Opcode::GetExtendedRegister64: {
|
||||||
Arm::ExtReg reg = inst->GetArg(0).GetExtRegRef();
|
A32::ExtReg reg = inst->GetArg(0).GetA32ExtRegRef();
|
||||||
size_t reg_index = Arm::RegNumber(reg);
|
size_t reg_index = A32::RegNumber(reg);
|
||||||
do_get(ext_reg_doubles_info[reg_index], inst);
|
do_get(ext_reg_doubles_info[reg_index], inst);
|
||||||
|
|
||||||
size_t singles_reg_index = reg_index * 2;
|
size_t singles_reg_index = reg_index * 2;
|
||||||
|
|
|
@ -1,34 +1,31 @@
|
||||||
add_executable(dynarmic_tests
|
add_executable(dynarmic_tests
|
||||||
# Source files
|
|
||||||
arm/fuzz_arm.cpp
|
arm/fuzz_arm.cpp
|
||||||
arm/fuzz_thumb.cpp
|
arm/fuzz_thumb.cpp
|
||||||
arm/test_arm_disassembler.cpp
|
arm/test_arm_disassembler.cpp
|
||||||
arm/test_thumb_instructions.cpp
|
arm/test_thumb_instructions.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
|
rand_int.h
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_dec.cpp
|
skyeye_interpreter/dyncom/arm_dyncom_dec.cpp
|
||||||
|
skyeye_interpreter/dyncom/arm_dyncom_dec.h
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp
|
skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp
|
||||||
|
skyeye_interpreter/dyncom/arm_dyncom_interpreter.h
|
||||||
|
skyeye_interpreter/dyncom/arm_dyncom_run.h
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_thumb.cpp
|
skyeye_interpreter/dyncom/arm_dyncom_thumb.cpp
|
||||||
|
skyeye_interpreter/dyncom/arm_dyncom_thumb.h
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_trans.cpp
|
skyeye_interpreter/dyncom/arm_dyncom_trans.cpp
|
||||||
|
skyeye_interpreter/dyncom/arm_dyncom_trans.h
|
||||||
|
skyeye_interpreter/skyeye_common/arm_regformat.h
|
||||||
skyeye_interpreter/skyeye_common/armstate.cpp
|
skyeye_interpreter/skyeye_common/armstate.cpp
|
||||||
|
skyeye_interpreter/skyeye_common/armstate.h
|
||||||
skyeye_interpreter/skyeye_common/armsupp.cpp
|
skyeye_interpreter/skyeye_common/armsupp.cpp
|
||||||
|
skyeye_interpreter/skyeye_common/armsupp.h
|
||||||
|
skyeye_interpreter/skyeye_common/vfp/asm_vfp.h
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfp.cpp
|
skyeye_interpreter/skyeye_common/vfp/vfp.cpp
|
||||||
|
skyeye_interpreter/skyeye_common/vfp/vfp.h
|
||||||
|
skyeye_interpreter/skyeye_common/vfp/vfp_helper.h
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfpdouble.cpp
|
skyeye_interpreter/skyeye_common/vfp/vfpdouble.cpp
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp
|
skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfpsingle.cpp
|
skyeye_interpreter/skyeye_common/vfp/vfpsingle.cpp
|
||||||
|
|
||||||
# Header files
|
|
||||||
rand_int.h
|
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_dec.h
|
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_interpreter.h
|
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_run.h
|
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_thumb.h
|
|
||||||
skyeye_interpreter/dyncom/arm_dyncom_trans.h
|
|
||||||
skyeye_interpreter/skyeye_common/arm_regformat.h
|
|
||||||
skyeye_interpreter/skyeye_common/armstate.h
|
|
||||||
skyeye_interpreter/skyeye_common/armsupp.h
|
|
||||||
skyeye_interpreter/skyeye_common/vfp/asm_vfp.h
|
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfp.h
|
|
||||||
skyeye_interpreter/skyeye_common/vfp/vfp_helper.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
include(CreateDirectoryGroups)
|
include(CreateDirectoryGroups)
|
||||||
|
|
|
@ -19,10 +19,13 @@
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/disassembler/disassembler.h"
|
#include "frontend/A32/disassembler/disassembler.h"
|
||||||
|
#include "frontend/A32/FPSCR.h"
|
||||||
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
#include "frontend/A32/PSR.h"
|
||||||
|
#include "frontend/A32/translate/translate.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/ir/location_descriptor.h"
|
#include "frontend/ir/location_descriptor.h"
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
#include "ir_opt/passes.h"
|
#include "ir_opt/passes.h"
|
||||||
#include "rand_int.h"
|
#include "rand_int.h"
|
||||||
#include "skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
|
#include "skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
|
||||||
|
@ -270,12 +273,12 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe
|
||||||
|
|
||||||
printf("\nInstruction Listing: \n");
|
printf("\nInstruction Listing: \n");
|
||||||
for (size_t i = 0; i < instruction_count; i++) {
|
for (size_t i = 0; i < instruction_count; i++) {
|
||||||
printf("%x: %s\n", code_mem[i], Dynarmic::Arm::DisassembleArm(code_mem[i]).c_str());
|
printf("%x: %s\n", code_mem[i], Dynarmic::A32::DisassembleArm(code_mem[i]).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nInitial Register Listing: \n");
|
printf("\nInitial Register Listing: \n");
|
||||||
for (int i = 0; i <= 15; i++) {
|
for (int i = 0; i <= 15; i++) {
|
||||||
auto reg = Dynarmic::Arm::RegToString(static_cast<Dynarmic::Arm::Reg>(i));
|
auto reg = Dynarmic::A32::RegToString(static_cast<Dynarmic::A32::Reg>(i));
|
||||||
printf("%4s: %08x\n", reg, initial_regs[i]);
|
printf("%4s: %08x\n", reg, initial_regs[i]);
|
||||||
}
|
}
|
||||||
printf("CPSR: %08x\n", initial_cpsr);
|
printf("CPSR: %08x\n", initial_cpsr);
|
||||||
|
@ -287,7 +290,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe
|
||||||
printf("\nFinal Register Listing: \n");
|
printf("\nFinal Register Listing: \n");
|
||||||
printf(" interp jit\n");
|
printf(" interp jit\n");
|
||||||
for (int i = 0; i <= 15; i++) {
|
for (int i = 0; i <= 15; i++) {
|
||||||
auto reg = Dynarmic::Arm::RegToString(static_cast<Dynarmic::Arm::Reg>(i));
|
auto reg = Dynarmic::A32::RegToString(static_cast<Dynarmic::A32::Reg>(i));
|
||||||
printf("%4s: %08x %08x %s\n", reg, interp.Reg[i], jit.Regs()[i], interp.Reg[i] != jit.Regs()[i] ? "*" : "");
|
printf("%4s: %08x %08x %s\n", reg, interp.Reg[i], jit.Regs()[i], interp.Reg[i] != jit.Regs()[i] ? "*" : "");
|
||||||
}
|
}
|
||||||
printf("CPSR: %08x %08x %s\n", interp.Cpsr, jit.Cpsr(), interp.Cpsr != jit.Cpsr() ? "*" : "");
|
printf("CPSR: %08x %08x %s\n", interp.Cpsr, jit.Cpsr(), interp.Cpsr != jit.Cpsr() ? "*" : "");
|
||||||
|
@ -308,8 +311,8 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe
|
||||||
|
|
||||||
size_t num_insts = 0;
|
size_t num_insts = 0;
|
||||||
while (num_insts < instructions_to_execute_count) {
|
while (num_insts < instructions_to_execute_count) {
|
||||||
Dynarmic::IR::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::Arm::PSR{}, Dynarmic::Arm::FPSCR{}};
|
Dynarmic::A32::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::A32::PSR{}, Dynarmic::A32::FPSCR{}};
|
||||||
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryReadCode);
|
Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, &MemoryReadCode);
|
||||||
Dynarmic::Optimization::GetSetElimination(ir_block);
|
Dynarmic::Optimization::GetSetElimination(ir_block);
|
||||||
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
||||||
Dynarmic::Optimization::VerificationPass(ir_block);
|
Dynarmic::Optimization::VerificationPass(ir_block);
|
||||||
|
|
|
@ -18,9 +18,12 @@
|
||||||
|
|
||||||
#include "common/bit_util.h"
|
#include "common/bit_util.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "frontend/disassembler/disassembler.h"
|
#include "frontend/A32/disassembler/disassembler.h"
|
||||||
|
#include "frontend/A32/FPSCR.h"
|
||||||
|
#include "frontend/A32/location_descriptor.h"
|
||||||
|
#include "frontend/A32/PSR.h"
|
||||||
|
#include "frontend/A32/translate/translate.h"
|
||||||
#include "frontend/ir/basic_block.h"
|
#include "frontend/ir/basic_block.h"
|
||||||
#include "frontend/translate/translate.h"
|
|
||||||
#include "ir_opt/passes.h"
|
#include "ir_opt/passes.h"
|
||||||
#include "rand_int.h"
|
#include "rand_int.h"
|
||||||
#include "skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
|
#include "skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
|
||||||
|
@ -230,7 +233,7 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e
|
||||||
|
|
||||||
printf("\nInstruction Listing: \n");
|
printf("\nInstruction Listing: \n");
|
||||||
for (size_t i = 0; i < instruction_count; i++) {
|
for (size_t i = 0; i < instruction_count; i++) {
|
||||||
printf("%s\n", Dynarmic::Arm::DisassembleThumb16(code_mem[i]).c_str());
|
printf("%s\n", Dynarmic::A32::DisassembleThumb16(code_mem[i]).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\nInitial Register Listing: \n");
|
printf("\nInitial Register Listing: \n");
|
||||||
|
@ -255,13 +258,13 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e
|
||||||
printf("%zu [%x] = %" PRIu64 "\n", record.size, record.address, record.data);
|
printf("%zu [%x] = %" PRIu64 "\n", record.size, record.address, record.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dynarmic::Arm::PSR cpsr;
|
Dynarmic::A32::PSR cpsr;
|
||||||
cpsr.T(true);
|
cpsr.T(true);
|
||||||
|
|
||||||
size_t num_insts = 0;
|
size_t num_insts = 0;
|
||||||
while (num_insts < instructions_to_execute_count) {
|
while (num_insts < instructions_to_execute_count) {
|
||||||
Dynarmic::IR::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, Dynarmic::Arm::FPSCR{}};
|
Dynarmic::A32::LocationDescriptor descriptor = {u32(num_insts * 4), cpsr, Dynarmic::A32::FPSCR{}};
|
||||||
Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryReadCode);
|
Dynarmic::IR::Block ir_block = Dynarmic::A32::Translate(descriptor, &MemoryReadCode);
|
||||||
Dynarmic::Optimization::GetSetElimination(ir_block);
|
Dynarmic::Optimization::GetSetElimination(ir_block);
|
||||||
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
Dynarmic::Optimization::DeadCodeElimination(ir_block);
|
||||||
Dynarmic::Optimization::VerificationPass(ir_block);
|
Dynarmic::Optimization::VerificationPass(ir_block);
|
||||||
|
|
|
@ -6,9 +6,9 @@
|
||||||
|
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include "frontend/disassembler/disassembler.h"
|
#include "frontend/A32/disassembler/disassembler.h"
|
||||||
|
|
||||||
using Dynarmic::Arm::DisassembleArm;
|
using Dynarmic::A32::DisassembleArm;
|
||||||
|
|
||||||
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
TEST_CASE("Disassemble branch instructions", "[arm][disassembler]") {
|
||||||
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
REQUIRE(DisassembleArm(0xEAFFFFFE) == "b +#0");
|
||||||
|
|
Loading…
Reference in a new issue