Label A32 specific code appropriately

This commit is contained in:
MerryMage 2018-01-01 15:23:56 +00:00
parent 89e9ce8aff
commit b3c73e2622
58 changed files with 938 additions and 831 deletions

View file

@ -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 {
/** /**

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View 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

View 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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>";
} }

View file

@ -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
View 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

View file

@ -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());
} }

View file

@ -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();

View file

@ -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;
} }

View file

@ -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

View file

@ -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_;
}; };

View file

@ -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 {

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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");