diff options
Diffstat (limited to 'src/core')
33 files changed, 22 insertions, 14549 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d93eb39a4..7da6ed318 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -1,19 +1,7 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | arm/dynarmic/arm_dynarmic.cpp | 2 | arm/dynarmic/arm_dynarmic.cpp |
| 3 | arm/dynarmic/arm_dynarmic_cp15.cpp | ||
| 4 | arm/dyncom/arm_dyncom.cpp | ||
| 5 | arm/dyncom/arm_dyncom_dec.cpp | ||
| 6 | arm/dyncom/arm_dyncom_interpreter.cpp | ||
| 7 | arm/dyncom/arm_dyncom_thumb.cpp | ||
| 8 | arm/dyncom/arm_dyncom_trans.cpp | ||
| 9 | arm/unicorn/arm_unicorn.cpp | 3 | arm/unicorn/arm_unicorn.cpp |
| 10 | arm/unicorn/unicorn_dynload.c | 4 | arm/unicorn/unicorn_dynload.c |
| 11 | arm/skyeye_common/armstate.cpp | ||
| 12 | arm/skyeye_common/armsupp.cpp | ||
| 13 | arm/skyeye_common/vfp/vfp.cpp | ||
| 14 | arm/skyeye_common/vfp/vfpdouble.cpp | ||
| 15 | arm/skyeye_common/vfp/vfpinstr.cpp | ||
| 16 | arm/skyeye_common/vfp/vfpsingle.cpp | ||
| 17 | core.cpp | 5 | core.cpp |
| 18 | core_timing.cpp | 6 | core_timing.cpp |
| 19 | file_sys/archive_backend.cpp | 7 | file_sys/archive_backend.cpp |
| @@ -86,21 +74,8 @@ set(HEADERS | |||
| 86 | 3ds.h | 74 | 3ds.h |
| 87 | arm/arm_interface.h | 75 | arm/arm_interface.h |
| 88 | arm/dynarmic/arm_dynarmic.h | 76 | arm/dynarmic/arm_dynarmic.h |
| 89 | arm/dynarmic/arm_dynarmic_cp15.h | ||
| 90 | arm/dyncom/arm_dyncom.h | ||
| 91 | arm/dyncom/arm_dyncom_dec.h | ||
| 92 | arm/dyncom/arm_dyncom_interpreter.h | ||
| 93 | arm/dyncom/arm_dyncom_run.h | ||
| 94 | arm/dyncom/arm_dyncom_thumb.h | ||
| 95 | arm/dyncom/arm_dyncom_trans.h | ||
| 96 | arm/unicorn/arm_unicorn.h | 77 | arm/unicorn/arm_unicorn.h |
| 97 | arm/unicorn/unicorn_dynload.h | 78 | arm/unicorn/unicorn_dynload.h |
| 98 | arm/skyeye_common/arm_regformat.h | ||
| 99 | arm/skyeye_common/armstate.h | ||
| 100 | arm/skyeye_common/armsupp.h | ||
| 101 | arm/skyeye_common/vfp/asm_vfp.h | ||
| 102 | arm/skyeye_common/vfp/vfp.h | ||
| 103 | arm/skyeye_common/vfp/vfp_helper.h | ||
| 104 | core.h | 79 | core.h |
| 105 | core_timing.h | 80 | core_timing.h |
| 106 | file_sys/archive_backend.h | 81 | file_sys/archive_backend.h |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 0b3096347..c0d6e2604 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "core/hle/kernel/vm_manager.h" | 8 | #include "core/hle/kernel/vm_manager.h" |
| 9 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 10 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 11 | 9 | ||
| 12 | /// Generic ARM11 CPU interface | 10 | /// Generic ARM11 CPU interface |
| 13 | class ARM_Interface : NonCopyable { | 11 | class ARM_Interface : NonCopyable { |
| @@ -96,20 +94,6 @@ public: | |||
| 96 | virtual void SetVFPReg(int index, u32 value) = 0; | 94 | virtual void SetVFPReg(int index, u32 value) = 0; |
| 97 | 95 | ||
| 98 | /** | 96 | /** |
| 99 | * Gets the current value within a given VFP system register | ||
| 100 | * @param reg The VFP system register | ||
| 101 | * @return The value within the VFP system register | ||
| 102 | */ | ||
| 103 | virtual u32 GetVFPSystemReg(VFPSystemRegister reg) const = 0; | ||
| 104 | |||
| 105 | /** | ||
| 106 | * Sets the VFP system register to the given value | ||
| 107 | * @param reg The VFP system register | ||
| 108 | * @param value Value to set the VFP system register to | ||
| 109 | */ | ||
| 110 | virtual void SetVFPSystemReg(VFPSystemRegister reg, u32 value) = 0; | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Get the current CPSR register | 97 | * Get the current CPSR register |
| 114 | * @return Returns the value of the CPSR register | 98 | * @return Returns the value of the CPSR register |
| 115 | */ | 99 | */ |
| @@ -121,20 +105,6 @@ public: | |||
| 121 | */ | 105 | */ |
| 122 | virtual void SetCPSR(u32 cpsr) = 0; | 106 | virtual void SetCPSR(u32 cpsr) = 0; |
| 123 | 107 | ||
| 124 | /** | ||
| 125 | * Gets the value stored in a CP15 register. | ||
| 126 | * @param reg The CP15 register to retrieve the value from. | ||
| 127 | * @return the value stored in the given CP15 register. | ||
| 128 | */ | ||
| 129 | virtual u32 GetCP15Register(CP15Register reg) = 0; | ||
| 130 | |||
| 131 | /** | ||
| 132 | * Stores the given value into the indicated CP15 register. | ||
| 133 | * @param reg The CP15 register to store the value into. | ||
| 134 | * @param value The value to store into the CP15 register. | ||
| 135 | */ | ||
| 136 | virtual void SetCP15Register(CP15Register reg, u32 value) = 0; | ||
| 137 | |||
| 138 | virtual VAddr GetTlsAddress() const = 0; | 108 | virtual VAddr GetTlsAddress() const = 0; |
| 139 | 109 | ||
| 140 | virtual void SetTlsAddress(VAddr address) = 0; | 110 | virtual void SetTlsAddress(VAddr address) = 0; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 6dcab5bab..89754da17 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -7,11 +7,9 @@ | |||
| 7 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 8 | #include "common/microprofile.h" | 8 | #include "common/microprofile.h" |
| 9 | #include "core/arm/dynarmic/arm_dynarmic.h" | 9 | #include "core/arm/dynarmic/arm_dynarmic.h" |
| 10 | #include "core/arm/dynarmic/arm_dynarmic_cp15.h" | ||
| 11 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 12 | #include "core/core.h" | 10 | #include "core/core.h" |
| 13 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 14 | #include "core/hle/svc.h" | 12 | #include "core/hle/kernel/svc.h" |
| 15 | #include "core/memory.h" | 13 | #include "core/memory.h" |
| 16 | 14 | ||
| 17 | static void InterpreterFallback(u64 pc, Dynarmic::Jit* jit, void* user_arg) { | 15 | static void InterpreterFallback(u64 pc, Dynarmic::Jit* jit, void* user_arg) { |
| @@ -55,11 +53,11 @@ void MemoryWrite64(const u64 addr, const u64 data) { | |||
| 55 | Memory::Write64(static_cast<VAddr>(addr), data); | 53 | Memory::Write64(static_cast<VAddr>(addr), data); |
| 56 | } | 54 | } |
| 57 | 55 | ||
| 58 | static Dynarmic::UserCallbacks GetUserCallbacks(ARM_Dynarmic* this_) { | 56 | static Dynarmic::UserCallbacks GetUserCallbacks(ARM_Interface* interpreter_fallback) { |
| 59 | Dynarmic::UserCallbacks user_callbacks{}; | 57 | Dynarmic::UserCallbacks user_callbacks{}; |
| 60 | user_callbacks.InterpreterFallback = &InterpreterFallback; | 58 | user_callbacks.InterpreterFallback = &InterpreterFallback; |
| 61 | user_callbacks.user_arg = static_cast<void*>(this_); | 59 | user_callbacks.user_arg = static_cast<void*>(interpreter_fallback); |
| 62 | user_callbacks.CallSVC = &SVC::CallSVC; | 60 | user_callbacks.CallSVC = &Kernel::CallSVC; |
| 63 | user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory; | 61 | user_callbacks.memory.IsReadOnlyMemory = &IsReadOnlyMemory; |
| 64 | user_callbacks.memory.ReadCode = &MemoryRead32; | 62 | user_callbacks.memory.ReadCode = &MemoryRead32; |
| 65 | user_callbacks.memory.Read8 = &MemoryRead8; | 63 | user_callbacks.memory.Read8 = &MemoryRead8; |
| @@ -74,7 +72,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks(ARM_Dynarmic* this_) { | |||
| 74 | return user_callbacks; | 72 | return user_callbacks; |
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | ARM_Dynarmic::ARM_Dynarmic(PrivilegeMode initial_mode) { | 75 | ARM_Dynarmic::ARM_Dynarmic() { |
| 78 | } | 76 | } |
| 79 | 77 | ||
| 80 | void ARM_Dynarmic::MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) { | 78 | void ARM_Dynarmic::MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) { |
| @@ -111,13 +109,6 @@ u32 ARM_Dynarmic::GetVFPReg(int index) const { | |||
| 111 | void ARM_Dynarmic::SetVFPReg(int index, u32 value) { | 109 | void ARM_Dynarmic::SetVFPReg(int index, u32 value) { |
| 112 | } | 110 | } |
| 113 | 111 | ||
| 114 | u32 ARM_Dynarmic::GetVFPSystemReg(VFPSystemRegister reg) const { | ||
| 115 | return {}; | ||
| 116 | } | ||
| 117 | |||
| 118 | void ARM_Dynarmic::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { | ||
| 119 | } | ||
| 120 | |||
| 121 | u32 ARM_Dynarmic::GetCPSR() const { | 112 | u32 ARM_Dynarmic::GetCPSR() const { |
| 122 | return jit->Cpsr(); | 113 | return jit->Cpsr(); |
| 123 | } | 114 | } |
| @@ -126,13 +117,6 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) { | |||
| 126 | jit->Cpsr() = cpsr; | 117 | jit->Cpsr() = cpsr; |
| 127 | } | 118 | } |
| 128 | 119 | ||
| 129 | u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) { | ||
| 130 | return {}; | ||
| 131 | } | ||
| 132 | |||
| 133 | void ARM_Dynarmic::SetCP15Register(CP15Register reg, u32 value) { | ||
| 134 | } | ||
| 135 | |||
| 136 | VAddr ARM_Dynarmic::GetTlsAddress() const { | 120 | VAddr ARM_Dynarmic::GetTlsAddress() const { |
| 137 | return jit->TlsAddr(); | 121 | return jit->TlsAddr(); |
| 138 | } | 122 | } |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h index 6567359b0..5c7f516d8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.h +++ b/src/core/arm/dynarmic/arm_dynarmic.h | |||
| @@ -9,7 +9,6 @@ | |||
| 9 | #include <dynarmic/dynarmic.h> | 9 | #include <dynarmic/dynarmic.h> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/arm/arm_interface.h" | 11 | #include "core/arm/arm_interface.h" |
| 12 | #include "core/arm/skyeye_common/armstate.h" | ||
| 13 | 12 | ||
| 14 | namespace Memory { | 13 | namespace Memory { |
| 15 | struct PageTable; | 14 | struct PageTable; |
| @@ -17,7 +16,7 @@ struct PageTable; | |||
| 17 | 16 | ||
| 18 | class ARM_Dynarmic final : public ARM_Interface { | 17 | class ARM_Dynarmic final : public ARM_Interface { |
| 19 | public: | 18 | public: |
| 20 | ARM_Dynarmic(PrivilegeMode initial_mode); | 19 | ARM_Dynarmic(); |
| 21 | 20 | ||
| 22 | void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) override; | 21 | void MapBackingMemory(VAddr address, size_t size, u8* memory, Kernel::VMAPermission perms) override; |
| 23 | 22 | ||
| @@ -29,12 +28,8 @@ public: | |||
| 29 | void SetExtReg(int index, u128& value) override; | 28 | void SetExtReg(int index, u128& value) override; |
| 30 | u32 GetVFPReg(int index) const override; | 29 | u32 GetVFPReg(int index) const override; |
| 31 | void SetVFPReg(int index, u32 value) override; | 30 | void SetVFPReg(int index, u32 value) override; |
| 32 | u32 GetVFPSystemReg(VFPSystemRegister reg) const override; | ||
| 33 | void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override; | ||
| 34 | u32 GetCPSR() const override; | 31 | u32 GetCPSR() const override; |
| 35 | void SetCPSR(u32 cpsr) override; | 32 | void SetCPSR(u32 cpsr) override; |
| 36 | u32 GetCP15Register(CP15Register reg) override; | ||
| 37 | void SetCP15Register(CP15Register reg, u32 value) override; | ||
| 38 | VAddr GetTlsAddress() const override; | 33 | VAddr GetTlsAddress() const override; |
| 39 | void SetTlsAddress(VAddr address) override; | 34 | void SetTlsAddress(VAddr address) override; |
| 40 | 35 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp deleted file mode 100644 index b1fdce096..000000000 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp +++ /dev/null | |||
| @@ -1,88 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/arm/dynarmic/arm_dynarmic_cp15.h" | ||
| 6 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 7 | #include "core/arm/skyeye_common/armstate.h" | ||
| 8 | |||
| 9 | using Callback = Dynarmic::Coprocessor::Callback; | ||
| 10 | using CallbackOrAccessOneWord = Dynarmic::Coprocessor::CallbackOrAccessOneWord; | ||
| 11 | using CallbackOrAccessTwoWords = Dynarmic::Coprocessor::CallbackOrAccessTwoWords; | ||
| 12 | |||
| 13 | DynarmicCP15::DynarmicCP15(const std::shared_ptr<ARMul_State>& state) : interpreter_state(state) {} | ||
| 14 | |||
| 15 | DynarmicCP15::~DynarmicCP15() = default; | ||
| 16 | |||
| 17 | boost::optional<Callback> DynarmicCP15::CompileInternalOperation(bool two, unsigned opc1, | ||
| 18 | CoprocReg CRd, CoprocReg CRn, | ||
| 19 | CoprocReg CRm, unsigned opc2) { | ||
| 20 | return boost::none; | ||
| 21 | } | ||
| 22 | |||
| 23 | CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, | ||
| 24 | CoprocReg CRm, unsigned opc2) { | ||
| 25 | // TODO(merry): Privileged CP15 registers | ||
| 26 | |||
| 27 | if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C5 && opc2 == 4) { | ||
| 28 | // This is a dummy write, we ignore the value written here. | ||
| 29 | return &interpreter_state->CP15[CP15_FLUSH_PREFETCH_BUFFER]; | ||
| 30 | } | ||
| 31 | |||
| 32 | if (!two && CRn == CoprocReg::C7 && opc1 == 0 && CRm == CoprocReg::C10) { | ||
| 33 | switch (opc2) { | ||
| 34 | case 4: | ||
| 35 | // This is a dummy write, we ignore the value written here. | ||
| 36 | return &interpreter_state->CP15[CP15_DATA_SYNC_BARRIER]; | ||
| 37 | case 5: | ||
| 38 | // This is a dummy write, we ignore the value written here. | ||
| 39 | return &interpreter_state->CP15[CP15_DATA_MEMORY_BARRIER]; | ||
| 40 | default: | ||
| 41 | return boost::blank{}; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0 && opc2 == 2) { | ||
| 46 | return &interpreter_state->CP15[CP15_THREAD_UPRW]; | ||
| 47 | } | ||
| 48 | |||
| 49 | return boost::blank{}; | ||
| 50 | } | ||
| 51 | |||
| 52 | CallbackOrAccessTwoWords DynarmicCP15::CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) { | ||
| 53 | return boost::blank{}; | ||
| 54 | } | ||
| 55 | |||
| 56 | CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, | ||
| 57 | CoprocReg CRm, unsigned opc2) { | ||
| 58 | // TODO(merry): Privileged CP15 registers | ||
| 59 | |||
| 60 | if (!two && CRn == CoprocReg::C13 && opc1 == 0 && CRm == CoprocReg::C0) { | ||
| 61 | switch (opc2) { | ||
| 62 | case 2: | ||
| 63 | return &interpreter_state->CP15[CP15_THREAD_UPRW]; | ||
| 64 | case 3: | ||
| 65 | return &interpreter_state->CP15[CP15_THREAD_URO]; | ||
| 66 | default: | ||
| 67 | return boost::blank{}; | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | return boost::blank{}; | ||
| 72 | } | ||
| 73 | |||
| 74 | CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) { | ||
| 75 | return boost::blank{}; | ||
| 76 | } | ||
| 77 | |||
| 78 | boost::optional<Callback> DynarmicCP15::CompileLoadWords(bool two, bool long_transfer, | ||
| 79 | CoprocReg CRd, | ||
| 80 | boost::optional<u8> option) { | ||
| 81 | return boost::none; | ||
| 82 | } | ||
| 83 | |||
| 84 | boost::optional<Callback> DynarmicCP15::CompileStoreWords(bool two, bool long_transfer, | ||
| 85 | CoprocReg CRd, | ||
| 86 | boost::optional<u8> option) { | ||
| 87 | return boost::none; | ||
| 88 | } | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h deleted file mode 100644 index 7fa54e14c..000000000 --- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | #include <dynarmic/coprocessor.h> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | struct ARMul_State; | ||
| 10 | |||
| 11 | class DynarmicCP15 final : public Dynarmic::Coprocessor { | ||
| 12 | public: | ||
| 13 | explicit DynarmicCP15(const std::shared_ptr<ARMul_State>&); | ||
| 14 | ~DynarmicCP15() override; | ||
| 15 | |||
| 16 | boost::optional<Callback> CompileInternalOperation(bool two, unsigned opc1, CoprocReg CRd, | ||
| 17 | CoprocReg CRn, CoprocReg CRm, | ||
| 18 | unsigned opc2) override; | ||
| 19 | CallbackOrAccessOneWord CompileSendOneWord(bool two, unsigned opc1, CoprocReg CRn, | ||
| 20 | CoprocReg CRm, unsigned opc2) override; | ||
| 21 | CallbackOrAccessTwoWords CompileSendTwoWords(bool two, unsigned opc, CoprocReg CRm) override; | ||
| 22 | CallbackOrAccessOneWord CompileGetOneWord(bool two, unsigned opc1, CoprocReg CRn, CoprocReg CRm, | ||
| 23 | unsigned opc2) override; | ||
| 24 | CallbackOrAccessTwoWords CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) override; | ||
| 25 | boost::optional<Callback> CompileLoadWords(bool two, bool long_transfer, CoprocReg CRd, | ||
| 26 | boost::optional<u8> option) override; | ||
| 27 | boost::optional<Callback> CompileStoreWords(bool two, bool long_transfer, CoprocReg CRd, | ||
| 28 | boost::optional<u8> option) override; | ||
| 29 | |||
| 30 | private: | ||
| 31 | std::shared_ptr<ARMul_State> interpreter_state; | ||
| 32 | }; | ||
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp deleted file mode 100644 index 5ebf7a2f1..000000000 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ /dev/null | |||
| @@ -1,132 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstring> | ||
| 6 | #include <memory> | ||
| 7 | #include "core/arm/dyncom/arm_dyncom.h" | ||
| 8 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 9 | #include "core/arm/dyncom/arm_dyncom_run.h" | ||
| 10 | #include "core/arm/dyncom/arm_dyncom_trans.h" | ||
| 11 | #include "core/arm/skyeye_common/armstate.h" | ||
| 12 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 13 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 14 | #include "core/core.h" | ||
| 15 | #include "core/core_timing.h" | ||
| 16 | |||
| 17 | ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { | ||
| 18 | state = std::make_unique<ARMul_State>(initial_mode); | ||
| 19 | } | ||
| 20 | |||
| 21 | ARM_DynCom::~ARM_DynCom() {} | ||
| 22 | |||
| 23 | void ARM_DynCom::ClearInstructionCache() { | ||
| 24 | state->instruction_cache.clear(); | ||
| 25 | trans_cache_buf_top = 0; | ||
| 26 | } | ||
| 27 | |||
| 28 | void ARM_DynCom::SetPC(u64 pc) { | ||
| 29 | state->Reg[15] = pc; | ||
| 30 | } | ||
| 31 | |||
| 32 | void ARM_DynCom::PageTableChanged() { | ||
| 33 | ClearInstructionCache(); | ||
| 34 | } | ||
| 35 | |||
| 36 | u64 ARM_DynCom::GetPC() const { | ||
| 37 | return state->Reg[15]; | ||
| 38 | } | ||
| 39 | |||
| 40 | u64 ARM_DynCom::GetReg(int index) const { | ||
| 41 | return state->Reg[index]; | ||
| 42 | } | ||
| 43 | |||
| 44 | void ARM_DynCom::SetReg(int index, u64 value) { | ||
| 45 | state->Reg[index] = value; | ||
| 46 | } | ||
| 47 | |||
| 48 | const u128& ARM_DynCom::GetExtReg(int index) const { | ||
| 49 | return {}; | ||
| 50 | } | ||
| 51 | |||
| 52 | void ARM_DynCom::SetExtReg(int index, u128& value) { | ||
| 53 | } | ||
| 54 | |||
| 55 | u32 ARM_DynCom::GetVFPReg(int index) const { | ||
| 56 | return state->ExtReg[index]; | ||
| 57 | } | ||
| 58 | |||
| 59 | void ARM_DynCom::SetVFPReg(int index, u32 value) { | ||
| 60 | state->ExtReg[index] = value; | ||
| 61 | } | ||
| 62 | |||
| 63 | u32 ARM_DynCom::GetVFPSystemReg(VFPSystemRegister reg) const { | ||
| 64 | return state->VFP[reg]; | ||
| 65 | } | ||
| 66 | |||
| 67 | void ARM_DynCom::SetVFPSystemReg(VFPSystemRegister reg, u32 value) { | ||
| 68 | state->VFP[reg] = value; | ||
| 69 | } | ||
| 70 | |||
| 71 | u32 ARM_DynCom::GetCPSR() const { | ||
| 72 | return state->Cpsr; | ||
| 73 | } | ||
| 74 | |||
| 75 | void ARM_DynCom::SetCPSR(u32 cpsr) { | ||
| 76 | state->Cpsr = cpsr; | ||
| 77 | } | ||
| 78 | |||
| 79 | u32 ARM_DynCom::GetCP15Register(CP15Register reg) { | ||
| 80 | return state->CP15[reg]; | ||
| 81 | } | ||
| 82 | |||
| 83 | void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) { | ||
| 84 | state->CP15[reg] = value; | ||
| 85 | } | ||
| 86 | |||
| 87 | VAddr ARM_DynCom::GetTlsAddress() const { | ||
| 88 | return {}; | ||
| 89 | } | ||
| 90 | |||
| 91 | void ARM_DynCom::SetTlsAddress(VAddr /*address*/) { | ||
| 92 | } | ||
| 93 | |||
| 94 | void ARM_DynCom::ExecuteInstructions(int num_instructions) { | ||
| 95 | state->NumInstrsToExecute = num_instructions; | ||
| 96 | |||
| 97 | // Dyncom only breaks on instruction dispatch. This only happens on every instruction when | ||
| 98 | // executing one instruction at a time. Otherwise, if a block is being executed, more | ||
| 99 | // instructions may actually be executed than specified. | ||
| 100 | unsigned ticks_executed = InterpreterMainLoop(state.get()); | ||
| 101 | CoreTiming::AddTicks(ticks_executed); | ||
| 102 | } | ||
| 103 | |||
| 104 | void ARM_DynCom::SaveContext(ThreadContext& ctx) { | ||
| 105 | memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers)); | ||
| 106 | memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers)); | ||
| 107 | |||
| 108 | ctx.sp = state->Reg[13]; | ||
| 109 | ctx.lr = state->Reg[14]; | ||
| 110 | ctx.pc = state->Reg[15]; | ||
| 111 | ctx.cpsr = state->Cpsr; | ||
| 112 | |||
| 113 | ctx.fpscr = state->VFP[VFP_FPSCR]; | ||
| 114 | ctx.fpexc = state->VFP[VFP_FPEXC]; | ||
| 115 | } | ||
| 116 | |||
| 117 | void ARM_DynCom::LoadContext(const ThreadContext& ctx) { | ||
| 118 | memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers)); | ||
| 119 | memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers)); | ||
| 120 | |||
| 121 | state->Reg[13] = ctx.sp; | ||
| 122 | state->Reg[14] = ctx.lr; | ||
| 123 | state->Reg[15] = ctx.pc; | ||
| 124 | state->Cpsr = ctx.cpsr; | ||
| 125 | |||
| 126 | state->VFP[VFP_FPSCR] = ctx.fpscr; | ||
| 127 | state->VFP[VFP_FPEXC] = ctx.fpexc; | ||
| 128 | } | ||
| 129 | |||
| 130 | void ARM_DynCom::PrepareReschedule() { | ||
| 131 | state->NumInstrsToExecute = 0; | ||
| 132 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h deleted file mode 100644 index cc3c0f3da..000000000 --- a/src/core/arm/dyncom/arm_dyncom.h +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/arm/arm_interface.h" | ||
| 10 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 11 | #include "core/arm/skyeye_common/armstate.h" | ||
| 12 | |||
| 13 | class ARM_DynCom final : public ARM_Interface { | ||
| 14 | public: | ||
| 15 | ARM_DynCom(PrivilegeMode initial_mode); | ||
| 16 | ~ARM_DynCom(); | ||
| 17 | |||
| 18 | void ClearInstructionCache() override; | ||
| 19 | void PageTableChanged() override; | ||
| 20 | |||
| 21 | void SetPC(u64 pc) override; | ||
| 22 | u64 GetPC() const override; | ||
| 23 | u64 GetReg(int index) const override; | ||
| 24 | void SetReg(int index, u64 value) override; | ||
| 25 | const u128& GetExtReg(int index) const override; | ||
| 26 | void SetExtReg(int index, u128& value) override; | ||
| 27 | u32 GetVFPReg(int index) const override; | ||
| 28 | void SetVFPReg(int index, u32 value) override; | ||
| 29 | u32 GetVFPSystemReg(VFPSystemRegister reg) const override; | ||
| 30 | void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override; | ||
| 31 | u32 GetCPSR() const override; | ||
| 32 | void SetCPSR(u32 cpsr) override; | ||
| 33 | u32 GetCP15Register(CP15Register reg) override; | ||
| 34 | void SetCP15Register(CP15Register reg, u32 value) override; | ||
| 35 | VAddr GetTlsAddress() const override; | ||
| 36 | void SetTlsAddress(VAddr address) override; | ||
| 37 | |||
| 38 | void SaveContext(ThreadContext& ctx) override; | ||
| 39 | void LoadContext(const ThreadContext& ctx) override; | ||
| 40 | |||
| 41 | void PrepareReschedule() override; | ||
| 42 | void ExecuteInstructions(int num_instructions) override; | ||
| 43 | |||
| 44 | private: | ||
| 45 | std::unique_ptr<ARMul_State> state; | ||
| 46 | }; | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp deleted file mode 100644 index dcfcd6561..000000000 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ /dev/null | |||
| @@ -1,478 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/arm/dyncom/arm_dyncom_dec.h" | ||
| 6 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 7 | |||
| 8 | // clang-format off | ||
| 9 | const InstructionSetEncodingItem arm_instruction[] = { | ||
| 10 | { "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | ||
| 11 | { "vmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 12 | { "vnmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 13 | { "vnmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | ||
| 14 | { "vnmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 15 | { "vmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | ||
| 16 | { "vadd", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | ||
| 17 | { "vsub", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 18 | { "vdiv", 5, ARMVFP2, { 23, 27, 0x1D, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | ||
| 19 | { "vmov(i)", 4, ARMVFP3, { 23, 27, 0x1D, 20, 21, 0x3, 9, 11, 0x5, 4, 7, 0 }}, | ||
| 20 | { "vmov(r)", 5, ARMVFP3, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }}, | ||
| 21 | { "vabs", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, | ||
| 22 | { "vneg", 5, ARMVFP2, { 23, 27, 0x1D, 17, 21, 0x18, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }}, | ||
| 23 | { "vsqrt", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x31, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, | ||
| 24 | { "vcmp", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x34, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 25 | { "vcmp2", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x35, 9, 11, 0x5, 0, 6, 0x40 }}, | ||
| 26 | { "vcvt(bds)", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x37, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }}, | ||
| 27 | { "vcvt(bff)", 6, ARMVFP3, { 23, 27, 0x1D, 19, 21, 0x7, 17, 17, 0x1, 9, 11, 5, 6, 6, 1 }}, | ||
| 28 | { "vcvt(bfi)", 5, ARMVFP2, { 23, 27, 0x1D, 19, 21, 0x7, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 29 | { "vmovbrs", 3, ARMVFP2, { 21, 27, 0x70, 8, 11, 0xA, 0, 6, 0x10 }}, | ||
| 30 | { "vmsr", 2, ARMVFP2, { 20, 27, 0xEE, 0, 11, 0xA10 }}, | ||
| 31 | { "vmovbrc", 4, ARMVFP2, { 23, 27, 0x1C, 20, 20, 0x0, 8, 11, 0xB, 0, 4, 0x10 }}, | ||
| 32 | { "vmrs", 2, ARMVFP2, { 20, 27, 0xEF, 0, 11, 0xA10 }}, | ||
| 33 | { "vmovbcr", 4, ARMVFP2, { 24, 27, 0xE, 20, 20, 1, 8, 11, 0xB, 0, 4, 0x10 }}, | ||
| 34 | { "vmovbrrss", 3, ARMVFP2, { 21, 27, 0x62, 8, 11, 0xA, 4, 4, 1 }}, | ||
| 35 | { "vmovbrrd", 3, ARMVFP2, { 21, 27, 0x62, 6, 11, 0x2C, 4, 4, 1 }}, | ||
| 36 | { "vstr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 0, 9, 11, 5 }}, | ||
| 37 | { "vpush", 3, ARMVFP2, { 23, 27, 0x1A, 16, 21, 0x2D, 9, 11, 5 }}, | ||
| 38 | { "vstm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 0, 9, 11, 5 }}, | ||
| 39 | { "vpop", 3, ARMVFP2, { 23, 27, 0x19, 16, 21, 0x3D, 9, 11, 5 }}, | ||
| 40 | { "vldr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 1, 9, 11, 5 }}, | ||
| 41 | { "vldm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 1, 9, 11, 5 }}, | ||
| 42 | |||
| 43 | { "srs", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005 }}, | ||
| 44 | { "rfe", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a }}, | ||
| 45 | { "bkpt", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000007 }}, | ||
| 46 | { "blx", 1, 3, { 25, 31, 0x0000007d }}, | ||
| 47 | { "cps", 3, 6, { 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000 }}, | ||
| 48 | { "pld", 4, 4, { 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f }}, | ||
| 49 | { "setend", 2, 6, { 16, 31, 0x0000f101, 4, 7, 0x00000000 }}, | ||
| 50 | { "clrex", 1, 6, { 0, 31, 0xf57ff01f }}, | ||
| 51 | { "rev16", 2, 6, { 16, 27, 0x000006bf, 4, 11, 0x000000fb }}, | ||
| 52 | { "usad8", 3, 6, { 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001 }}, | ||
| 53 | { "sxtb", 2, 6, { 16, 27, 0x000006af, 4, 7, 0x00000007 }}, | ||
| 54 | { "uxtb", 2, 6, { 16, 27, 0x000006ef, 4, 7, 0x00000007 }}, | ||
| 55 | { "sxth", 2, 6, { 16, 27, 0x000006bf, 4, 7, 0x00000007 }}, | ||
| 56 | { "sxtb16", 2, 6, { 16, 27, 0x0000068f, 4, 7, 0x00000007 }}, | ||
| 57 | { "uxth", 2, 6, { 16, 27, 0x000006ff, 4, 7, 0x00000007 }}, | ||
| 58 | { "uxtb16", 2, 6, { 16, 27, 0x000006cf, 4, 7, 0x00000007 }}, | ||
| 59 | { "cpy", 2, 6, { 20, 27, 0x0000001a, 4, 11, 0x00000000 }}, | ||
| 60 | { "uxtab", 2, 6, { 20, 27, 0x0000006e, 4, 9, 0x00000007 }}, | ||
| 61 | { "ssub8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x0000000f }}, | ||
| 62 | { "shsub8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x0000000f }}, | ||
| 63 | { "ssubaddx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000005 }}, | ||
| 64 | { "strex", 2, 6, { 20, 27, 0x00000018, 4, 7, 0x00000009 }}, | ||
| 65 | { "strexb", 2, 7, { 20, 27, 0x0000001c, 4, 7, 0x00000009 }}, | ||
| 66 | { "swp", 2, 0, { 20, 27, 0x00000010, 4, 7, 0x00000009 }}, | ||
| 67 | { "swpb", 2, 0, { 20, 27, 0x00000014, 4, 7, 0x00000009 }}, | ||
| 68 | { "ssub16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000007 }}, | ||
| 69 | { "ssat16", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000003 }}, | ||
| 70 | { "shsubaddx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000005 }}, | ||
| 71 | { "qsubaddx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000005 }}, | ||
| 72 | { "shaddsubx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000003 }}, | ||
| 73 | { "shadd8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000009 }}, | ||
| 74 | { "shadd16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000001 }}, | ||
| 75 | { "sel", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x0000000b }}, | ||
| 76 | { "saddsubx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000003 }}, | ||
| 77 | { "sadd8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000009 }}, | ||
| 78 | { "sadd16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000001 }}, | ||
| 79 | { "shsub16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000007 }}, | ||
| 80 | { "umaal", 2, 6, { 20, 27, 0x00000004, 4, 7, 0x00000009 }}, | ||
| 81 | { "uxtab16", 2, 6, { 20, 27, 0x0000006c, 4, 7, 0x00000007 }}, | ||
| 82 | { "usubaddx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000005 }}, | ||
| 83 | { "usub8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x0000000f }}, | ||
| 84 | { "usub16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000007 }}, | ||
| 85 | { "usat16", 2, 6, { 20, 27, 0x0000006e, 4, 7, 0x00000003 }}, | ||
| 86 | { "usada8", 2, 6, { 20, 27, 0x00000078, 4, 7, 0x00000001 }}, | ||
| 87 | { "uqsubaddx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000005 }}, | ||
| 88 | { "uqsub8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x0000000f }}, | ||
| 89 | { "uqsub16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000007 }}, | ||
| 90 | { "uqaddsubx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000003 }}, | ||
| 91 | { "uqadd8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000009 }}, | ||
| 92 | { "uqadd16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000001 }}, | ||
| 93 | { "sxtab", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000007 }}, | ||
| 94 | { "uhsubaddx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000005 }}, | ||
| 95 | { "uhsub8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x0000000f }}, | ||
| 96 | { "uhsub16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000007 }}, | ||
| 97 | { "uhaddsubx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000003 }}, | ||
| 98 | { "uhadd8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000009 }}, | ||
| 99 | { "uhadd16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000001 }}, | ||
| 100 | { "uaddsubx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000003 }}, | ||
| 101 | { "uadd8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000009 }}, | ||
| 102 | { "uadd16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000001 }}, | ||
| 103 | { "sxtah", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000007 }}, | ||
| 104 | { "sxtab16", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x00000007 }}, | ||
| 105 | { "qadd8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000009 }}, | ||
| 106 | { "bxj", 2, 5, { 20, 27, 0x00000012, 4, 7, 0x00000002 }}, | ||
| 107 | { "clz", 2, 3, { 20, 27, 0x00000016, 4, 7, 0x00000001 }}, | ||
| 108 | { "uxtah", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x00000007 }}, | ||
| 109 | { "bx", 2, 2, { 20, 27, 0x00000012, 4, 7, 0x00000001 }}, | ||
| 110 | { "rev", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000003 }}, | ||
| 111 | { "blx", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000003 }}, | ||
| 112 | { "revsh", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x0000000b }}, | ||
| 113 | { "qadd", 2, 4, { 20, 27, 0x00000010, 4, 7, 0x00000005 }}, | ||
| 114 | { "qadd16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000001 }}, | ||
| 115 | { "qaddsubx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000003 }}, | ||
| 116 | { "ldrex", 2, 0, { 20, 27, 0x00000019, 4, 7, 0x00000009 }}, | ||
| 117 | { "qdadd", 2, 4, { 20, 27, 0x00000014, 4, 7, 0x00000005 }}, | ||
| 118 | { "qdsub", 2, 4, { 20, 27, 0x00000016, 4, 7, 0x00000005 }}, | ||
| 119 | { "qsub", 2, 4, { 20, 27, 0x00000012, 4, 7, 0x00000005 }}, | ||
| 120 | { "ldrexb", 2, 7, { 20, 27, 0x0000001d, 4, 7, 0x00000009 }}, | ||
| 121 | { "qsub8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x0000000f }}, | ||
| 122 | { "qsub16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000007 }}, | ||
| 123 | { "smuad", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 124 | { "smmul", 4, 6, { 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 125 | { "smusd", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, | ||
| 126 | { "smlsd", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, | ||
| 127 | { "smlsld", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001 }}, | ||
| 128 | { "smmla", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 129 | { "smmls", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001 }}, | ||
| 130 | { "smlald", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 131 | { "smlad", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 132 | { "smlaw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000 }}, | ||
| 133 | { "smulw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002 }}, | ||
| 134 | { "pkhtb", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000005 }}, | ||
| 135 | { "pkhbt", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000001 }}, | ||
| 136 | { "smul", 3, 4, { 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, | ||
| 137 | { "smlalxy", 3, 4, { 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, | ||
| 138 | { "smla", 3, 4, { 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000 }}, | ||
| 139 | { "mcrr", 1, 6, { 20, 27, 0x000000c4 }}, | ||
| 140 | { "mrrc", 1, 6, { 20, 27, 0x000000c5 }}, | ||
| 141 | { "cmp", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000015 }}, | ||
| 142 | { "tst", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000011 }}, | ||
| 143 | { "teq", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000013 }}, | ||
| 144 | { "cmn", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000017 }}, | ||
| 145 | { "smull", 2, 0, { 21, 27, 0x00000006, 4, 7, 0x00000009 }}, | ||
| 146 | { "umull", 2, 0, { 21, 27, 0x00000004, 4, 7, 0x00000009 }}, | ||
| 147 | { "umlal", 2, 0, { 21, 27, 0x00000005, 4, 7, 0x00000009 }}, | ||
| 148 | { "smlal", 2, 0, { 21, 27, 0x00000007, 4, 7, 0x00000009 }}, | ||
| 149 | { "mul", 2, 0, { 21, 27, 0x00000000, 4, 7, 0x00000009 }}, | ||
| 150 | { "mla", 2, 0, { 21, 27, 0x00000001, 4, 7, 0x00000009 }}, | ||
| 151 | { "ssat", 2, 6, { 21, 27, 0x00000035, 4, 5, 0x00000001 }}, | ||
| 152 | { "usat", 2, 6, { 21, 27, 0x00000037, 4, 5, 0x00000001 }}, | ||
| 153 | { "mrs", 4, 0, { 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000 }}, | ||
| 154 | { "msr", 3, 0, { 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000 }}, | ||
| 155 | { "and", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000000 }}, | ||
| 156 | { "bic", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000e }}, | ||
| 157 | { "ldm", 3, 0, { 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000 }}, | ||
| 158 | { "eor", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000001 }}, | ||
| 159 | { "add", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000004 }}, | ||
| 160 | { "rsb", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000003 }}, | ||
| 161 | { "rsc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000007 }}, | ||
| 162 | { "sbc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000006 }}, | ||
| 163 | { "adc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000005 }}, | ||
| 164 | { "sub", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000002 }}, | ||
| 165 | { "orr", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000c }}, | ||
| 166 | { "mvn", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000f }}, | ||
| 167 | { "mov", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000d }}, | ||
| 168 | { "stm", 2, 0, { 25, 27, 0x00000004, 20, 22, 0x00000004 }}, | ||
| 169 | { "ldm", 4, 0, { 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001 }}, | ||
| 170 | { "ldrsh", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f }}, | ||
| 171 | { "stm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000 }}, | ||
| 172 | { "ldm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, | ||
| 173 | { "ldrsb", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d }}, | ||
| 174 | { "strd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f }}, | ||
| 175 | { "ldrh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b }}, | ||
| 176 | { "strh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b }}, | ||
| 177 | { "ldrd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d }}, | ||
| 178 | { "strt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002 }}, | ||
| 179 | { "strbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006 }}, | ||
| 180 | { "ldrbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007 }}, | ||
| 181 | { "ldrt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003 }}, | ||
| 182 | { "mrc", 3, 6, { 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001 }}, | ||
| 183 | { "mcr", 3, 0, { 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001 }}, | ||
| 184 | { "msr", 3, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000001 }}, | ||
| 185 | { "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 19, 0x00000004 }}, | ||
| 186 | { "msr", 5, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 19, 19, 0x00000001, 16, 17, 0x00000000 }}, | ||
| 187 | { "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 17, 0x00000001 }}, | ||
| 188 | { "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 17, 17, 0x00000001 }}, | ||
| 189 | { "ldrb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001 }}, | ||
| 190 | { "strb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000 }}, | ||
| 191 | { "ldr", 4, 0, { 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, | ||
| 192 | { "ldrcond", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }}, | ||
| 193 | { "str", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000 }}, | ||
| 194 | { "cdp", 2, 0, { 24, 27, 0x0000000e, 4, 4, 0x00000000 }}, | ||
| 195 | { "stc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000000 }}, | ||
| 196 | { "ldc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000001 }}, | ||
| 197 | { "ldrexd", 2, ARMV6K, { 20, 27, 0x0000001B, 4, 7, 0x00000009 }}, | ||
| 198 | { "strexd", 2, ARMV6K, { 20, 27, 0x0000001A, 4, 7, 0x00000009 }}, | ||
| 199 | { "ldrexh", 2, ARMV6K, { 20, 27, 0x0000001F, 4, 7, 0x00000009 }}, | ||
| 200 | { "strexh", 2, ARMV6K, { 20, 27, 0x0000001E, 4, 7, 0x00000009 }}, | ||
| 201 | { "nop", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000000 }}, | ||
| 202 | { "yield", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000001 }}, | ||
| 203 | { "wfe", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000002 }}, | ||
| 204 | { "wfi", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000003 }}, | ||
| 205 | { "sev", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000004 }}, | ||
| 206 | { "swi", 1, 0, { 24, 27, 0x0000000f }}, | ||
| 207 | { "bbl", 1, 0, { 25, 27, 0x00000005 }}, | ||
| 208 | }; | ||
| 209 | |||
| 210 | |||
| 211 | const InstructionSetEncodingItem arm_exclusion_code[] = { | ||
| 212 | { "vmla", 0, ARMVFP2, { 0 }}, | ||
| 213 | { "vmls", 0, ARMVFP2, { 0 }}, | ||
| 214 | { "vnmla", 0, ARMVFP2, { 0 }}, | ||
| 215 | { "vnmls", 0, ARMVFP2, { 0 }}, | ||
| 216 | { "vnmul", 0, ARMVFP2, { 0 }}, | ||
| 217 | { "vmul", 0, ARMVFP2, { 0 }}, | ||
| 218 | { "vadd", 0, ARMVFP2, { 0 }}, | ||
| 219 | { "vsub", 0, ARMVFP2, { 0 }}, | ||
| 220 | { "vdiv", 0, ARMVFP2, { 0 }}, | ||
| 221 | { "vmov(i)", 0, ARMVFP3, { 0 }}, | ||
| 222 | { "vmov(r)", 0, ARMVFP3, { 0 }}, | ||
| 223 | { "vabs", 0, ARMVFP2, { 0 }}, | ||
| 224 | { "vneg", 0, ARMVFP2, { 0 }}, | ||
| 225 | { "vsqrt", 0, ARMVFP2, { 0 }}, | ||
| 226 | { "vcmp", 0, ARMVFP2, { 0 }}, | ||
| 227 | { "vcmp2", 0, ARMVFP2, { 0 }}, | ||
| 228 | { "vcvt(bff)", 0, ARMVFP3, { 4, 4, 1 }}, | ||
| 229 | { "vcvt(bds)", 0, ARMVFP2, { 0 }}, | ||
| 230 | { "vcvt(bfi)", 0, ARMVFP2, { 0 }}, | ||
| 231 | { "vmovbrs", 0, ARMVFP2, { 0 }}, | ||
| 232 | { "vmsr", 0, ARMVFP2, { 0 }}, | ||
| 233 | { "vmovbrc", 0, ARMVFP2, { 0 }}, | ||
| 234 | { "vmrs", 0, ARMVFP2, { 0 }}, | ||
| 235 | { "vmovbcr", 0, ARMVFP2, { 0 }}, | ||
| 236 | { "vmovbrrss", 0, ARMVFP2, { 0 }}, | ||
| 237 | { "vmovbrrd", 0, ARMVFP2, { 0 }}, | ||
| 238 | { "vstr", 0, ARMVFP2, { 0 }}, | ||
| 239 | { "vpush", 0, ARMVFP2, { 0 }}, | ||
| 240 | { "vstm", 0, ARMVFP2, { 0 }}, | ||
| 241 | { "vpop", 0, ARMVFP2, { 0 }}, | ||
| 242 | { "vldr", 0, ARMVFP2, { 0 }}, | ||
| 243 | { "vldm", 0, ARMVFP2, { 0 }}, | ||
| 244 | |||
| 245 | { "srs", 0, 6, { 0 }}, | ||
| 246 | { "rfe", 0, 6, { 0 }}, | ||
| 247 | { "bkpt", 0, 3, { 0 }}, | ||
| 248 | { "blx", 0, 3, { 0 }}, | ||
| 249 | { "cps", 0, 6, { 0 }}, | ||
| 250 | { "pld", 0, 4, { 0 }}, | ||
| 251 | { "setend", 0, 6, { 0 }}, | ||
| 252 | { "clrex", 0, 6, { 0 }}, | ||
| 253 | { "rev16", 0, 6, { 0 }}, | ||
| 254 | { "usad8", 0, 6, { 0 }}, | ||
| 255 | { "sxtb", 0, 6, { 0 }}, | ||
| 256 | { "uxtb", 0, 6, { 0 }}, | ||
| 257 | { "sxth", 0, 6, { 0 }}, | ||
| 258 | { "sxtb16", 0, 6, { 0 }}, | ||
| 259 | { "uxth", 0, 6, { 0 }}, | ||
| 260 | { "uxtb16", 0, 6, { 0 }}, | ||
| 261 | { "cpy", 0, 6, { 0 }}, | ||
| 262 | { "uxtab", 0, 6, { 0 }}, | ||
| 263 | { "ssub8", 0, 6, { 0 }}, | ||
| 264 | { "shsub8", 0, 6, { 0 }}, | ||
| 265 | { "ssubaddx", 0, 6, { 0 }}, | ||
| 266 | { "strex", 0, 6, { 0 }}, | ||
| 267 | { "strexb", 0, 7, { 0 }}, | ||
| 268 | { "swp", 0, 0, { 0 }}, | ||
| 269 | { "swpb", 0, 0, { 0 }}, | ||
| 270 | { "ssub16", 0, 6, { 0 }}, | ||
| 271 | { "ssat16", 0, 6, { 0 }}, | ||
| 272 | { "shsubaddx", 0, 6, { 0 }}, | ||
| 273 | { "qsubaddx", 0, 6, { 0 }}, | ||
| 274 | { "shaddsubx", 0, 6, { 0 }}, | ||
| 275 | { "shadd8", 0, 6, { 0 }}, | ||
| 276 | { "shadd16", 0, 6, { 0 }}, | ||
| 277 | { "sel", 0, 6, { 0 }}, | ||
| 278 | { "saddsubx", 0, 6, { 0 }}, | ||
| 279 | { "sadd8", 0, 6, { 0 }}, | ||
| 280 | { "sadd16", 0, 6, { 0 }}, | ||
| 281 | { "shsub16", 0, 6, { 0 }}, | ||
| 282 | { "umaal", 0, 6, { 0 }}, | ||
| 283 | { "uxtab16", 0, 6, { 0 }}, | ||
| 284 | { "usubaddx", 0, 6, { 0 }}, | ||
| 285 | { "usub8", 0, 6, { 0 }}, | ||
| 286 | { "usub16", 0, 6, { 0 }}, | ||
| 287 | { "usat16", 0, 6, { 0 }}, | ||
| 288 | { "usada8", 0, 6, { 0 }}, | ||
| 289 | { "uqsubaddx", 0, 6, { 0 }}, | ||
| 290 | { "uqsub8", 0, 6, { 0 }}, | ||
| 291 | { "uqsub16", 0, 6, { 0 }}, | ||
| 292 | { "uqaddsubx", 0, 6, { 0 }}, | ||
| 293 | { "uqadd8", 0, 6, { 0 }}, | ||
| 294 | { "uqadd16", 0, 6, { 0 }}, | ||
| 295 | { "sxtab", 0, 6, { 0 }}, | ||
| 296 | { "uhsubaddx", 0, 6, { 0 }}, | ||
| 297 | { "uhsub8", 0, 6, { 0 }}, | ||
| 298 | { "uhsub16", 0, 6, { 0 }}, | ||
| 299 | { "uhaddsubx", 0, 6, { 0 }}, | ||
| 300 | { "uhadd8", 0, 6, { 0 }}, | ||
| 301 | { "uhadd16", 0, 6, { 0 }}, | ||
| 302 | { "uaddsubx", 0, 6, { 0 }}, | ||
| 303 | { "uadd8", 0, 6, { 0 }}, | ||
| 304 | { "uadd16", 0, 6, { 0 }}, | ||
| 305 | { "sxtah", 0, 6, { 0 }}, | ||
| 306 | { "sxtab16", 0, 6, { 0 }}, | ||
| 307 | { "qadd8", 0, 6, { 0 }}, | ||
| 308 | { "bxj", 0, 5, { 0 }}, | ||
| 309 | { "clz", 0, 3, { 0 }}, | ||
| 310 | { "uxtah", 0, 6, { 0 }}, | ||
| 311 | { "bx", 0, 2, { 0 }}, | ||
| 312 | { "rev", 0, 6, { 0 }}, | ||
| 313 | { "blx", 0, 3, { 0 }}, | ||
| 314 | { "revsh", 0, 6, { 0 }}, | ||
| 315 | { "qadd", 0, 4, { 0 }}, | ||
| 316 | { "qadd16", 0, 6, { 0 }}, | ||
| 317 | { "qaddsubx", 0, 6, { 0 }}, | ||
| 318 | { "ldrex", 0, 0, { 0 }}, | ||
| 319 | { "qdadd", 0, 4, { 0 }}, | ||
| 320 | { "qdsub", 0, 4, { 0 }}, | ||
| 321 | { "qsub", 0, 4, { 0 }}, | ||
| 322 | { "ldrexb", 0, 7, { 0 }}, | ||
| 323 | { "qsub8", 0, 6, { 0 }}, | ||
| 324 | { "qsub16", 0, 6, { 0 }}, | ||
| 325 | { "smuad", 0, 6, { 0 }}, | ||
| 326 | { "smmul", 0, 6, { 0 }}, | ||
| 327 | { "smusd", 0, 6, { 0 }}, | ||
| 328 | { "smlsd", 0, 6, { 0 }}, | ||
| 329 | { "smlsld", 0, 6, { 0 }}, | ||
| 330 | { "smmla", 0, 6, { 0 }}, | ||
| 331 | { "smmls", 0, 6, { 0 }}, | ||
| 332 | { "smlald", 0, 6, { 0 }}, | ||
| 333 | { "smlad", 0, 6, { 0 }}, | ||
| 334 | { "smlaw", 0, 4, { 0 }}, | ||
| 335 | { "smulw", 0, 4, { 0 }}, | ||
| 336 | { "pkhtb", 0, 6, { 0 }}, | ||
| 337 | { "pkhbt", 0, 6, { 0 }}, | ||
| 338 | { "smul", 0, 4, { 0 }}, | ||
| 339 | { "smlal", 0, 4, { 0 }}, | ||
| 340 | { "smla", 0, 4, { 0 }}, | ||
| 341 | { "mcrr", 0, 6, { 0 }}, | ||
| 342 | { "mrrc", 0, 6, { 0 }}, | ||
| 343 | { "cmp", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 344 | { "tst", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 345 | { "teq", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 346 | { "cmn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 347 | { "smull", 0, 0, { 0 }}, | ||
| 348 | { "umull", 0, 0, { 0 }}, | ||
| 349 | { "umlal", 0, 0, { 0 }}, | ||
| 350 | { "smlal", 0, 0, { 0 }}, | ||
| 351 | { "mul", 0, 0, { 0 }}, | ||
| 352 | { "mla", 0, 0, { 0 }}, | ||
| 353 | { "ssat", 0, 6, { 0 }}, | ||
| 354 | { "usat", 0, 6, { 0 }}, | ||
| 355 | { "mrs", 0, 0, { 0 }}, | ||
| 356 | { "msr", 0, 0, { 0 }}, | ||
| 357 | { "and", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 358 | { "bic", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 359 | { "ldm", 0, 0, { 0 }}, | ||
| 360 | { "eor", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 361 | { "add", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 362 | { "rsb", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 363 | { "rsc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 364 | { "sbc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 365 | { "adc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 366 | { "sub", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 367 | { "orr", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 368 | { "mvn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 369 | { "mov", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }}, | ||
| 370 | { "stm", 0, 0, { 0 }}, | ||
| 371 | { "ldm", 0, 0, { 0 }}, | ||
| 372 | { "ldrsh", 0, 2, { 0 }}, | ||
| 373 | { "stm", 0, 0, { 0 }}, | ||
| 374 | { "ldm", 0, 0, { 0 }}, | ||
| 375 | { "ldrsb", 0, 2, { 0 }}, | ||
| 376 | { "strd", 0, 4, { 0 }}, | ||
| 377 | { "ldrh", 0, 0, { 0 }}, | ||
| 378 | { "strh", 0, 0, { 0 }}, | ||
| 379 | { "ldrd", 0, 4, { 0 }}, | ||
| 380 | { "strt", 0, 0, { 0 }}, | ||
| 381 | { "strbt", 0, 0, { 0 }}, | ||
| 382 | { "ldrbt", 0, 0, { 0 }}, | ||
| 383 | { "ldrt", 0, 0, { 0 }}, | ||
| 384 | { "mrc", 0, 6, { 0 }}, | ||
| 385 | { "mcr", 0, 0, { 0 }}, | ||
| 386 | { "msr", 0, 0, { 0 }}, | ||
| 387 | { "msr", 0, 0, { 0 }}, | ||
| 388 | { "msr", 0, 0, { 0 }}, | ||
| 389 | { "msr", 0, 0, { 0 }}, | ||
| 390 | { "msr", 0, 0, { 0 }}, | ||
| 391 | { "ldrb", 0, 0, { 0 }}, | ||
| 392 | { "strb", 0, 0, { 0 }}, | ||
| 393 | { "ldr", 0, 0, { 0 }}, | ||
| 394 | { "ldrcond", 1, 0, { 28, 31, 0x0000000e }}, | ||
| 395 | { "str", 0, 0, { 0 }}, | ||
| 396 | { "cdp", 0, 0, { 0 }}, | ||
| 397 | { "stc", 0, 0, { 0 }}, | ||
| 398 | { "ldc", 0, 0, { 0 }}, | ||
| 399 | { "ldrexd", 0, ARMV6K, { 0 }}, | ||
| 400 | { "strexd", 0, ARMV6K, { 0 }}, | ||
| 401 | { "ldrexh", 0, ARMV6K, { 0 }}, | ||
| 402 | { "strexh", 0, ARMV6K, { 0 }}, | ||
| 403 | { "nop", 0, ARMV6K, { 0 }}, | ||
| 404 | { "yield", 0, ARMV6K, { 0 }}, | ||
| 405 | { "wfe", 0, ARMV6K, { 0 }}, | ||
| 406 | { "wfi", 0, ARMV6K, { 0 }}, | ||
| 407 | { "sev", 0, ARMV6K, { 0 }}, | ||
| 408 | { "swi", 0, 0, { 0 }}, | ||
| 409 | { "bbl", 0, 0, { 0 }}, | ||
| 410 | |||
| 411 | { "bl_1_thumb", 0, INVALID, { 0 }}, // Should be table[-4] | ||
| 412 | { "bl_2_thumb", 0, INVALID, { 0 }}, // Should be located at the end of the table[-3] | ||
| 413 | { "blx_1_thumb", 0, INVALID, { 0 }}, // Should be located at table[-2] | ||
| 414 | { "invalid", 0, INVALID, { 0 }} | ||
| 415 | }; | ||
| 416 | // clang-format on | ||
| 417 | |||
| 418 | ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx) { | ||
| 419 | int n = 0; | ||
| 420 | int base = 0; | ||
| 421 | int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); | ||
| 422 | ARMDecodeStatus ret = ARMDecodeStatus::FAILURE; | ||
| 423 | |||
| 424 | for (int i = 0; i < instr_slots; i++) { | ||
| 425 | n = arm_instruction[i].attribute_value; | ||
| 426 | base = 0; | ||
| 427 | |||
| 428 | // 3DS has no VFP3 support | ||
| 429 | if (arm_instruction[i].version == ARMVFP3) | ||
| 430 | continue; | ||
| 431 | |||
| 432 | while (n) { | ||
| 433 | if (arm_instruction[i].content[base + 1] == 31 && | ||
| 434 | arm_instruction[i].content[base] == 0) { | ||
| 435 | // clrex | ||
| 436 | if (instr != arm_instruction[i].content[base + 2]) { | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | } else if (BITS(instr, arm_instruction[i].content[base], | ||
| 440 | arm_instruction[i].content[base + 1]) != | ||
| 441 | arm_instruction[i].content[base + 2]) { | ||
| 442 | break; | ||
| 443 | } | ||
| 444 | base += 3; | ||
| 445 | n--; | ||
| 446 | } | ||
| 447 | |||
| 448 | // All conditions are satisfied. | ||
| 449 | if (n == 0) | ||
| 450 | ret = ARMDecodeStatus::SUCCESS; | ||
| 451 | |||
| 452 | if (ret == ARMDecodeStatus::SUCCESS) { | ||
| 453 | n = arm_exclusion_code[i].attribute_value; | ||
| 454 | if (n != 0) { | ||
| 455 | base = 0; | ||
| 456 | while (n) { | ||
| 457 | if (BITS(instr, arm_exclusion_code[i].content[base], | ||
| 458 | arm_exclusion_code[i].content[base + 1]) != | ||
| 459 | arm_exclusion_code[i].content[base + 2]) { | ||
| 460 | break; | ||
| 461 | } | ||
| 462 | base += 3; | ||
| 463 | n--; | ||
| 464 | } | ||
| 465 | |||
| 466 | // All conditions are satisfied. | ||
| 467 | if (n == 0) | ||
| 468 | ret = ARMDecodeStatus::FAILURE; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | if (ret == ARMDecodeStatus::SUCCESS) { | ||
| 473 | *idx = i; | ||
| 474 | return ret; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | return ret; | ||
| 478 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h deleted file mode 100644 index 1dcf7ecd1..000000000 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ /dev/null | |||
| @@ -1,36 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | enum class ARMDecodeStatus { SUCCESS, FAILURE }; | ||
| 10 | |||
| 11 | ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx); | ||
| 12 | |||
| 13 | struct InstructionSetEncodingItem { | ||
| 14 | const char* name; | ||
| 15 | int attribute_value; | ||
| 16 | int version; | ||
| 17 | u32 content[21]; | ||
| 18 | }; | ||
| 19 | |||
| 20 | // ARM versions | ||
| 21 | enum { | ||
| 22 | INVALID = 0, | ||
| 23 | ARMALL, | ||
| 24 | ARMV4, | ||
| 25 | ARMV4T, | ||
| 26 | ARMV5T, | ||
| 27 | ARMV5TE, | ||
| 28 | ARMV5TEJ, | ||
| 29 | ARMV6, | ||
| 30 | ARM1176JZF_S, | ||
| 31 | ARMVFP2, | ||
| 32 | ARMVFP3, | ||
| 33 | ARMV6K, | ||
| 34 | }; | ||
| 35 | |||
| 36 | extern const InstructionSetEncodingItem arm_instruction[]; | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp deleted file mode 100644 index fc2d6aabc..000000000 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ /dev/null | |||
| @@ -1,4578 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #define CITRA_IGNORE_EXIT(x) | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <cinttypes> | ||
| 9 | #include <cstdio> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/logging/log.h" | ||
| 12 | #include "common/microprofile.h" | ||
| 13 | #include "core/arm/dyncom/arm_dyncom_dec.h" | ||
| 14 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 15 | #include "core/arm/dyncom/arm_dyncom_run.h" | ||
| 16 | #include "core/arm/dyncom/arm_dyncom_thumb.h" | ||
| 17 | #include "core/arm/dyncom/arm_dyncom_trans.h" | ||
| 18 | #include "core/arm/skyeye_common/armstate.h" | ||
| 19 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 20 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 21 | #include "core/gdbstub/gdbstub.h" | ||
| 22 | #include "core/hle/svc.h" | ||
| 23 | #include "core/memory.h" | ||
| 24 | |||
| 25 | #define RM BITS(sht_oper, 0, 3) | ||
| 26 | #define RS BITS(sht_oper, 8, 11) | ||
| 27 | |||
| 28 | #define glue(x, y) x##y | ||
| 29 | #define DPO(s) glue(DataProcessingOperands, s) | ||
| 30 | #define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i)) | ||
| 31 | #define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i)) | ||
| 32 | #define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) | ||
| 33 | #define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) | ||
| 34 | |||
| 35 | static bool CondPassed(const ARMul_State* cpu, unsigned int cond) { | ||
| 36 | const bool n_flag = cpu->NFlag != 0; | ||
| 37 | const bool z_flag = cpu->ZFlag != 0; | ||
| 38 | const bool c_flag = cpu->CFlag != 0; | ||
| 39 | const bool v_flag = cpu->VFlag != 0; | ||
| 40 | |||
| 41 | switch (cond) { | ||
| 42 | case ConditionCode::EQ: | ||
| 43 | return z_flag; | ||
| 44 | case ConditionCode::NE: | ||
| 45 | return !z_flag; | ||
| 46 | case ConditionCode::CS: | ||
| 47 | return c_flag; | ||
| 48 | case ConditionCode::CC: | ||
| 49 | return !c_flag; | ||
| 50 | case ConditionCode::MI: | ||
| 51 | return n_flag; | ||
| 52 | case ConditionCode::PL: | ||
| 53 | return !n_flag; | ||
| 54 | case ConditionCode::VS: | ||
| 55 | return v_flag; | ||
| 56 | case ConditionCode::VC: | ||
| 57 | return !v_flag; | ||
| 58 | case ConditionCode::HI: | ||
| 59 | return (c_flag && !z_flag); | ||
| 60 | case ConditionCode::LS: | ||
| 61 | return (!c_flag || z_flag); | ||
| 62 | case ConditionCode::GE: | ||
| 63 | return (n_flag == v_flag); | ||
| 64 | case ConditionCode::LT: | ||
| 65 | return (n_flag != v_flag); | ||
| 66 | case ConditionCode::GT: | ||
| 67 | return (!z_flag && (n_flag == v_flag)); | ||
| 68 | case ConditionCode::LE: | ||
| 69 | return (z_flag || (n_flag != v_flag)); | ||
| 70 | case ConditionCode::AL: | ||
| 71 | case ConditionCode::NV: // Unconditional | ||
| 72 | return true; | ||
| 73 | } | ||
| 74 | |||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 78 | static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 79 | unsigned int immed_8 = BITS(sht_oper, 0, 7); | ||
| 80 | unsigned int rotate_imm = BITS(sht_oper, 8, 11); | ||
| 81 | unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); | ||
| 82 | if (rotate_imm == 0) | ||
| 83 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 84 | else | ||
| 85 | cpu->shifter_carry_out = BIT(shifter_operand, 31); | ||
| 86 | return shifter_operand; | ||
| 87 | } | ||
| 88 | |||
| 89 | static unsigned int DPO(Register)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 90 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 91 | unsigned int shifter_operand = rm; | ||
| 92 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 93 | return shifter_operand; | ||
| 94 | } | ||
| 95 | |||
| 96 | static unsigned int DPO(LogicalShiftLeftByImmediate)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 97 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 98 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 99 | unsigned int shifter_operand; | ||
| 100 | if (shift_imm == 0) { | ||
| 101 | shifter_operand = rm; | ||
| 102 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 103 | } else { | ||
| 104 | shifter_operand = rm << shift_imm; | ||
| 105 | cpu->shifter_carry_out = BIT(rm, 32 - shift_imm); | ||
| 106 | } | ||
| 107 | return shifter_operand; | ||
| 108 | } | ||
| 109 | |||
| 110 | static unsigned int DPO(LogicalShiftLeftByRegister)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 111 | int shifter_operand; | ||
| 112 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 113 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 114 | if (BITS(rs, 0, 7) == 0) { | ||
| 115 | shifter_operand = rm; | ||
| 116 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 117 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 118 | shifter_operand = rm << BITS(rs, 0, 7); | ||
| 119 | cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7)); | ||
| 120 | } else if (BITS(rs, 0, 7) == 32) { | ||
| 121 | shifter_operand = 0; | ||
| 122 | cpu->shifter_carry_out = BIT(rm, 0); | ||
| 123 | } else { | ||
| 124 | shifter_operand = 0; | ||
| 125 | cpu->shifter_carry_out = 0; | ||
| 126 | } | ||
| 127 | return shifter_operand; | ||
| 128 | } | ||
| 129 | |||
| 130 | static unsigned int DPO(LogicalShiftRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 131 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 132 | unsigned int shifter_operand; | ||
| 133 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 134 | if (shift_imm == 0) { | ||
| 135 | shifter_operand = 0; | ||
| 136 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 137 | } else { | ||
| 138 | shifter_operand = rm >> shift_imm; | ||
| 139 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 140 | } | ||
| 141 | return shifter_operand; | ||
| 142 | } | ||
| 143 | |||
| 144 | static unsigned int DPO(LogicalShiftRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 145 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 146 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 147 | unsigned int shifter_operand; | ||
| 148 | if (BITS(rs, 0, 7) == 0) { | ||
| 149 | shifter_operand = rm; | ||
| 150 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 151 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 152 | shifter_operand = rm >> BITS(rs, 0, 7); | ||
| 153 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); | ||
| 154 | } else if (BITS(rs, 0, 7) == 32) { | ||
| 155 | shifter_operand = 0; | ||
| 156 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 157 | } else { | ||
| 158 | shifter_operand = 0; | ||
| 159 | cpu->shifter_carry_out = 0; | ||
| 160 | } | ||
| 161 | return shifter_operand; | ||
| 162 | } | ||
| 163 | |||
| 164 | static unsigned int DPO(ArithmeticShiftRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 165 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 166 | unsigned int shifter_operand; | ||
| 167 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 168 | if (shift_imm == 0) { | ||
| 169 | if (BIT(rm, 31) == 0) | ||
| 170 | shifter_operand = 0; | ||
| 171 | else | ||
| 172 | shifter_operand = 0xFFFFFFFF; | ||
| 173 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 174 | } else { | ||
| 175 | shifter_operand = static_cast<int>(rm) >> shift_imm; | ||
| 176 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 177 | } | ||
| 178 | return shifter_operand; | ||
| 179 | } | ||
| 180 | |||
| 181 | static unsigned int DPO(ArithmeticShiftRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 182 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 183 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 184 | unsigned int shifter_operand; | ||
| 185 | if (BITS(rs, 0, 7) == 0) { | ||
| 186 | shifter_operand = rm; | ||
| 187 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 188 | } else if (BITS(rs, 0, 7) < 32) { | ||
| 189 | shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7); | ||
| 190 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); | ||
| 191 | } else { | ||
| 192 | if (BIT(rm, 31) == 0) | ||
| 193 | shifter_operand = 0; | ||
| 194 | else | ||
| 195 | shifter_operand = 0xffffffff; | ||
| 196 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 197 | } | ||
| 198 | return shifter_operand; | ||
| 199 | } | ||
| 200 | |||
| 201 | static unsigned int DPO(RotateRightByImmediate)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 202 | unsigned int shifter_operand; | ||
| 203 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 204 | int shift_imm = BITS(sht_oper, 7, 11); | ||
| 205 | if (shift_imm == 0) { | ||
| 206 | shifter_operand = (cpu->CFlag << 31) | (rm >> 1); | ||
| 207 | cpu->shifter_carry_out = BIT(rm, 0); | ||
| 208 | } else { | ||
| 209 | shifter_operand = ROTATE_RIGHT_32(rm, shift_imm); | ||
| 210 | cpu->shifter_carry_out = BIT(rm, shift_imm - 1); | ||
| 211 | } | ||
| 212 | return shifter_operand; | ||
| 213 | } | ||
| 214 | |||
| 215 | static unsigned int DPO(RotateRightByRegister)(ARMul_State* cpu, unsigned int sht_oper) { | ||
| 216 | unsigned int rm = CHECK_READ_REG15(cpu, RM); | ||
| 217 | unsigned int rs = CHECK_READ_REG15(cpu, RS); | ||
| 218 | unsigned int shifter_operand; | ||
| 219 | if (BITS(rs, 0, 7) == 0) { | ||
| 220 | shifter_operand = rm; | ||
| 221 | cpu->shifter_carry_out = cpu->CFlag; | ||
| 222 | } else if (BITS(rs, 0, 4) == 0) { | ||
| 223 | shifter_operand = rm; | ||
| 224 | cpu->shifter_carry_out = BIT(rm, 31); | ||
| 225 | } else { | ||
| 226 | shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4)); | ||
| 227 | cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1); | ||
| 228 | } | ||
| 229 | return shifter_operand; | ||
| 230 | } | ||
| 231 | |||
| 232 | #define DEBUG_MSG \ | ||
| 233 | LOG_DEBUG(Core_ARM, "inst is %x", inst); \ | ||
| 234 | CITRA_IGNORE_EXIT(0) | ||
| 235 | |||
| 236 | #define LnSWoUB(s) glue(LnSWoUB, s) | ||
| 237 | #define MLnS(s) glue(MLnS, s) | ||
| 238 | #define LdnStM(s) glue(LdnStM, s) | ||
| 239 | |||
| 240 | #define W_BIT BIT(inst, 21) | ||
| 241 | #define U_BIT BIT(inst, 23) | ||
| 242 | #define I_BIT BIT(inst, 25) | ||
| 243 | #define P_BIT BIT(inst, 24) | ||
| 244 | #define OFFSET_12 BITS(inst, 0, 11) | ||
| 245 | |||
| 246 | static void LnSWoUB(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 247 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 248 | unsigned int addr; | ||
| 249 | |||
| 250 | if (U_BIT) | ||
| 251 | addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; | ||
| 252 | else | ||
| 253 | addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; | ||
| 254 | |||
| 255 | virt_addr = addr; | ||
| 256 | } | ||
| 257 | |||
| 258 | static void LnSWoUB(RegisterOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 259 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 260 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 261 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 262 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 263 | unsigned int addr; | ||
| 264 | |||
| 265 | if (U_BIT) | ||
| 266 | addr = rn + rm; | ||
| 267 | else | ||
| 268 | addr = rn - rm; | ||
| 269 | |||
| 270 | virt_addr = addr; | ||
| 271 | } | ||
| 272 | |||
| 273 | static void LnSWoUB(ImmediatePostIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 274 | unsigned int& virt_addr) { | ||
| 275 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 276 | unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 277 | |||
| 278 | if (U_BIT) | ||
| 279 | cpu->Reg[Rn] += OFFSET_12; | ||
| 280 | else | ||
| 281 | cpu->Reg[Rn] -= OFFSET_12; | ||
| 282 | |||
| 283 | virt_addr = addr; | ||
| 284 | } | ||
| 285 | |||
| 286 | static void LnSWoUB(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 287 | unsigned int& virt_addr) { | ||
| 288 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 289 | unsigned int addr; | ||
| 290 | |||
| 291 | if (U_BIT) | ||
| 292 | addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; | ||
| 293 | else | ||
| 294 | addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; | ||
| 295 | |||
| 296 | virt_addr = addr; | ||
| 297 | |||
| 298 | if (CondPassed(cpu, BITS(inst, 28, 31))) | ||
| 299 | cpu->Reg[Rn] = addr; | ||
| 300 | } | ||
| 301 | |||
| 302 | static void MLnS(RegisterPreIndexed)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 303 | unsigned int addr; | ||
| 304 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 305 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 306 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 307 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 308 | |||
| 309 | if (U_BIT) | ||
| 310 | addr = rn + rm; | ||
| 311 | else | ||
| 312 | addr = rn - rm; | ||
| 313 | |||
| 314 | virt_addr = addr; | ||
| 315 | |||
| 316 | if (CondPassed(cpu, BITS(inst, 28, 31))) | ||
| 317 | cpu->Reg[Rn] = addr; | ||
| 318 | } | ||
| 319 | |||
| 320 | static void LnSWoUB(RegisterPreIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 321 | unsigned int& virt_addr) { | ||
| 322 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 323 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 324 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 325 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 326 | unsigned int addr; | ||
| 327 | |||
| 328 | if (U_BIT) | ||
| 329 | addr = rn + rm; | ||
| 330 | else | ||
| 331 | addr = rn - rm; | ||
| 332 | |||
| 333 | virt_addr = addr; | ||
| 334 | |||
| 335 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 336 | cpu->Reg[Rn] = addr; | ||
| 337 | } | ||
| 338 | } | ||
| 339 | |||
| 340 | static void LnSWoUB(ScaledRegisterPreIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 341 | unsigned int& virt_addr) { | ||
| 342 | unsigned int shift = BITS(inst, 5, 6); | ||
| 343 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 344 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 345 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 346 | unsigned int index = 0; | ||
| 347 | unsigned int addr; | ||
| 348 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 349 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 350 | |||
| 351 | switch (shift) { | ||
| 352 | case 0: | ||
| 353 | index = rm << shift_imm; | ||
| 354 | break; | ||
| 355 | case 1: | ||
| 356 | if (shift_imm == 0) { | ||
| 357 | index = 0; | ||
| 358 | } else { | ||
| 359 | index = rm >> shift_imm; | ||
| 360 | } | ||
| 361 | break; | ||
| 362 | case 2: | ||
| 363 | if (shift_imm == 0) { // ASR #32 | ||
| 364 | if (BIT(rm, 31) == 1) | ||
| 365 | index = 0xFFFFFFFF; | ||
| 366 | else | ||
| 367 | index = 0; | ||
| 368 | } else { | ||
| 369 | index = static_cast<int>(rm) >> shift_imm; | ||
| 370 | } | ||
| 371 | break; | ||
| 372 | case 3: | ||
| 373 | if (shift_imm == 0) { | ||
| 374 | index = (cpu->CFlag << 31) | (rm >> 1); | ||
| 375 | } else { | ||
| 376 | index = ROTATE_RIGHT_32(rm, shift_imm); | ||
| 377 | } | ||
| 378 | break; | ||
| 379 | } | ||
| 380 | |||
| 381 | if (U_BIT) | ||
| 382 | addr = rn + index; | ||
| 383 | else | ||
| 384 | addr = rn - index; | ||
| 385 | |||
| 386 | virt_addr = addr; | ||
| 387 | |||
| 388 | if (CondPassed(cpu, BITS(inst, 28, 31))) | ||
| 389 | cpu->Reg[Rn] = addr; | ||
| 390 | } | ||
| 391 | |||
| 392 | static void LnSWoUB(ScaledRegisterPostIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 393 | unsigned int& virt_addr) { | ||
| 394 | unsigned int shift = BITS(inst, 5, 6); | ||
| 395 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 396 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 397 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 398 | unsigned int index = 0; | ||
| 399 | unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 400 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 401 | |||
| 402 | switch (shift) { | ||
| 403 | case 0: | ||
| 404 | index = rm << shift_imm; | ||
| 405 | break; | ||
| 406 | case 1: | ||
| 407 | if (shift_imm == 0) { | ||
| 408 | index = 0; | ||
| 409 | } else { | ||
| 410 | index = rm >> shift_imm; | ||
| 411 | } | ||
| 412 | break; | ||
| 413 | case 2: | ||
| 414 | if (shift_imm == 0) { // ASR #32 | ||
| 415 | if (BIT(rm, 31) == 1) | ||
| 416 | index = 0xFFFFFFFF; | ||
| 417 | else | ||
| 418 | index = 0; | ||
| 419 | } else { | ||
| 420 | index = static_cast<int>(rm) >> shift_imm; | ||
| 421 | } | ||
| 422 | break; | ||
| 423 | case 3: | ||
| 424 | if (shift_imm == 0) { | ||
| 425 | index = (cpu->CFlag << 31) | (rm >> 1); | ||
| 426 | } else { | ||
| 427 | index = ROTATE_RIGHT_32(rm, shift_imm); | ||
| 428 | } | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | |||
| 432 | virt_addr = addr; | ||
| 433 | |||
| 434 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 435 | if (U_BIT) | ||
| 436 | cpu->Reg[Rn] += index; | ||
| 437 | else | ||
| 438 | cpu->Reg[Rn] -= index; | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | static void LnSWoUB(RegisterPostIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 443 | unsigned int& virt_addr) { | ||
| 444 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 445 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 446 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 447 | |||
| 448 | virt_addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 449 | |||
| 450 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 451 | if (U_BIT) { | ||
| 452 | cpu->Reg[Rn] += rm; | ||
| 453 | } else { | ||
| 454 | cpu->Reg[Rn] -= rm; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | } | ||
| 458 | |||
| 459 | static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 460 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 461 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 462 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 463 | unsigned int addr; | ||
| 464 | |||
| 465 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 466 | |||
| 467 | if (U_BIT) | ||
| 468 | addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; | ||
| 469 | else | ||
| 470 | addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; | ||
| 471 | |||
| 472 | virt_addr = addr; | ||
| 473 | } | ||
| 474 | |||
| 475 | static void MLnS(RegisterOffset)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 476 | unsigned int addr; | ||
| 477 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 478 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 479 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 480 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 481 | |||
| 482 | if (U_BIT) | ||
| 483 | addr = rn + rm; | ||
| 484 | else | ||
| 485 | addr = rn - rm; | ||
| 486 | |||
| 487 | virt_addr = addr; | ||
| 488 | } | ||
| 489 | |||
| 490 | static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 491 | unsigned int& virt_addr) { | ||
| 492 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 493 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 494 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 495 | unsigned int addr; | ||
| 496 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 497 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 498 | |||
| 499 | if (U_BIT) | ||
| 500 | addr = rn + offset_8; | ||
| 501 | else | ||
| 502 | addr = rn - offset_8; | ||
| 503 | |||
| 504 | virt_addr = addr; | ||
| 505 | |||
| 506 | if (CondPassed(cpu, BITS(inst, 28, 31))) | ||
| 507 | cpu->Reg[Rn] = addr; | ||
| 508 | } | ||
| 509 | |||
| 510 | static void MLnS(ImmediatePostIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 511 | unsigned int& virt_addr) { | ||
| 512 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 513 | unsigned int immedH = BITS(inst, 8, 11); | ||
| 514 | unsigned int immedL = BITS(inst, 0, 3); | ||
| 515 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 516 | |||
| 517 | virt_addr = rn; | ||
| 518 | |||
| 519 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 520 | unsigned int offset_8 = (immedH << 4) | immedL; | ||
| 521 | if (U_BIT) | ||
| 522 | rn += offset_8; | ||
| 523 | else | ||
| 524 | rn -= offset_8; | ||
| 525 | |||
| 526 | cpu->Reg[Rn] = rn; | ||
| 527 | } | ||
| 528 | } | ||
| 529 | |||
| 530 | static void MLnS(RegisterPostIndexed)(ARMul_State* cpu, unsigned int inst, | ||
| 531 | unsigned int& virt_addr) { | ||
| 532 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 533 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 534 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 535 | |||
| 536 | virt_addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 537 | |||
| 538 | if (CondPassed(cpu, BITS(inst, 28, 31))) { | ||
| 539 | if (U_BIT) | ||
| 540 | cpu->Reg[Rn] += rm; | ||
| 541 | else | ||
| 542 | cpu->Reg[Rn] -= rm; | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | static void LdnStM(DecrementBefore)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 547 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 548 | unsigned int i = BITS(inst, 0, 15); | ||
| 549 | int count = 0; | ||
| 550 | |||
| 551 | while (i) { | ||
| 552 | if (i & 1) | ||
| 553 | count++; | ||
| 554 | i = i >> 1; | ||
| 555 | } | ||
| 556 | |||
| 557 | virt_addr = CHECK_READ_REG15_WA(cpu, Rn) - count * 4; | ||
| 558 | |||
| 559 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) | ||
| 560 | cpu->Reg[Rn] -= count * 4; | ||
| 561 | } | ||
| 562 | |||
| 563 | static void LdnStM(IncrementBefore)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 564 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 565 | unsigned int i = BITS(inst, 0, 15); | ||
| 566 | int count = 0; | ||
| 567 | |||
| 568 | while (i) { | ||
| 569 | if (i & 1) | ||
| 570 | count++; | ||
| 571 | i = i >> 1; | ||
| 572 | } | ||
| 573 | |||
| 574 | virt_addr = CHECK_READ_REG15_WA(cpu, Rn) + 4; | ||
| 575 | |||
| 576 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) | ||
| 577 | cpu->Reg[Rn] += count * 4; | ||
| 578 | } | ||
| 579 | |||
| 580 | static void LdnStM(IncrementAfter)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 581 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 582 | unsigned int i = BITS(inst, 0, 15); | ||
| 583 | int count = 0; | ||
| 584 | |||
| 585 | while (i) { | ||
| 586 | if (i & 1) | ||
| 587 | count++; | ||
| 588 | i = i >> 1; | ||
| 589 | } | ||
| 590 | |||
| 591 | virt_addr = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 592 | |||
| 593 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) | ||
| 594 | cpu->Reg[Rn] += count * 4; | ||
| 595 | } | ||
| 596 | |||
| 597 | static void LdnStM(DecrementAfter)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr) { | ||
| 598 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 599 | unsigned int i = BITS(inst, 0, 15); | ||
| 600 | int count = 0; | ||
| 601 | while (i) { | ||
| 602 | if (i & 1) | ||
| 603 | count++; | ||
| 604 | i = i >> 1; | ||
| 605 | } | ||
| 606 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 607 | unsigned int start_addr = rn - count * 4 + 4; | ||
| 608 | |||
| 609 | virt_addr = start_addr; | ||
| 610 | |||
| 611 | if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { | ||
| 612 | cpu->Reg[Rn] -= count * 4; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | |||
| 616 | static void LnSWoUB(ScaledRegisterOffset)(ARMul_State* cpu, unsigned int inst, | ||
| 617 | unsigned int& virt_addr) { | ||
| 618 | unsigned int shift = BITS(inst, 5, 6); | ||
| 619 | unsigned int shift_imm = BITS(inst, 7, 11); | ||
| 620 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 621 | unsigned int Rm = BITS(inst, 0, 3); | ||
| 622 | unsigned int index = 0; | ||
| 623 | unsigned int addr; | ||
| 624 | unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); | ||
| 625 | unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); | ||
| 626 | |||
| 627 | switch (shift) { | ||
| 628 | case 0: | ||
| 629 | index = rm << shift_imm; | ||
| 630 | break; | ||
| 631 | case 1: | ||
| 632 | if (shift_imm == 0) { | ||
| 633 | index = 0; | ||
| 634 | } else { | ||
| 635 | index = rm >> shift_imm; | ||
| 636 | } | ||
| 637 | break; | ||
| 638 | case 2: | ||
| 639 | if (shift_imm == 0) { // ASR #32 | ||
| 640 | if (BIT(rm, 31) == 1) | ||
| 641 | index = 0xFFFFFFFF; | ||
| 642 | else | ||
| 643 | index = 0; | ||
| 644 | } else { | ||
| 645 | index = static_cast<int>(rm) >> shift_imm; | ||
| 646 | } | ||
| 647 | break; | ||
| 648 | case 3: | ||
| 649 | if (shift_imm == 0) { | ||
| 650 | index = (cpu->CFlag << 31) | (rm >> 1); | ||
| 651 | } else { | ||
| 652 | index = ROTATE_RIGHT_32(rm, shift_imm); | ||
| 653 | } | ||
| 654 | break; | ||
| 655 | } | ||
| 656 | |||
| 657 | if (U_BIT) { | ||
| 658 | addr = rn + index; | ||
| 659 | } else | ||
| 660 | addr = rn - index; | ||
| 661 | |||
| 662 | virt_addr = addr; | ||
| 663 | } | ||
| 664 | |||
| 665 | shtop_fp_t GetShifterOp(unsigned int inst) { | ||
| 666 | if (BIT(inst, 25)) { | ||
| 667 | return DPO(Immediate); | ||
| 668 | } else if (BITS(inst, 4, 11) == 0) { | ||
| 669 | return DPO(Register); | ||
| 670 | } else if (BITS(inst, 4, 6) == 0) { | ||
| 671 | return DPO(LogicalShiftLeftByImmediate); | ||
| 672 | } else if (BITS(inst, 4, 7) == 1) { | ||
| 673 | return DPO(LogicalShiftLeftByRegister); | ||
| 674 | } else if (BITS(inst, 4, 6) == 2) { | ||
| 675 | return DPO(LogicalShiftRightByImmediate); | ||
| 676 | } else if (BITS(inst, 4, 7) == 3) { | ||
| 677 | return DPO(LogicalShiftRightByRegister); | ||
| 678 | } else if (BITS(inst, 4, 6) == 4) { | ||
| 679 | return DPO(ArithmeticShiftRightByImmediate); | ||
| 680 | } else if (BITS(inst, 4, 7) == 5) { | ||
| 681 | return DPO(ArithmeticShiftRightByRegister); | ||
| 682 | } else if (BITS(inst, 4, 6) == 6) { | ||
| 683 | return DPO(RotateRightByImmediate); | ||
| 684 | } else if (BITS(inst, 4, 7) == 7) { | ||
| 685 | return DPO(RotateRightByRegister); | ||
| 686 | } | ||
| 687 | return nullptr; | ||
| 688 | } | ||
| 689 | |||
| 690 | get_addr_fp_t GetAddressingOp(unsigned int inst) { | ||
| 691 | if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { | ||
| 692 | return LnSWoUB(ImmediateOffset); | ||
| 693 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { | ||
| 694 | return LnSWoUB(RegisterOffset); | ||
| 695 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { | ||
| 696 | return LnSWoUB(ScaledRegisterOffset); | ||
| 697 | } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) { | ||
| 698 | return LnSWoUB(ImmediatePreIndexed); | ||
| 699 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) { | ||
| 700 | return LnSWoUB(RegisterPreIndexed); | ||
| 701 | } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) { | ||
| 702 | return LnSWoUB(ScaledRegisterPreIndexed); | ||
| 703 | } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) { | ||
| 704 | return LnSWoUB(ImmediatePostIndexed); | ||
| 705 | } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { | ||
| 706 | return LnSWoUB(RegisterPostIndexed); | ||
| 707 | } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { | ||
| 708 | return LnSWoUB(ScaledRegisterPostIndexed); | ||
| 709 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && | ||
| 710 | BIT(inst, 4) == 1) { | ||
| 711 | return MLnS(ImmediateOffset); | ||
| 712 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && | ||
| 713 | BIT(inst, 4) == 1) { | ||
| 714 | return MLnS(RegisterOffset); | ||
| 715 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && | ||
| 716 | BIT(inst, 4) == 1) { | ||
| 717 | return MLnS(ImmediatePreIndexed); | ||
| 718 | } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && | ||
| 719 | BIT(inst, 4) == 1) { | ||
| 720 | return MLnS(RegisterPreIndexed); | ||
| 721 | } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && | ||
| 722 | BIT(inst, 4) == 1) { | ||
| 723 | return MLnS(ImmediatePostIndexed); | ||
| 724 | } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && | ||
| 725 | BIT(inst, 4) == 1) { | ||
| 726 | return MLnS(RegisterPostIndexed); | ||
| 727 | } else if (BITS(inst, 23, 27) == 0x11) { | ||
| 728 | return LdnStM(IncrementAfter); | ||
| 729 | } else if (BITS(inst, 23, 27) == 0x13) { | ||
| 730 | return LdnStM(IncrementBefore); | ||
| 731 | } else if (BITS(inst, 23, 27) == 0x10) { | ||
| 732 | return LdnStM(DecrementAfter); | ||
| 733 | } else if (BITS(inst, 23, 27) == 0x12) { | ||
| 734 | return LdnStM(DecrementBefore); | ||
| 735 | } | ||
| 736 | return nullptr; | ||
| 737 | } | ||
| 738 | |||
| 739 | // Specialized for LDRT, LDRBT, STRT, and STRBT, which have specific addressing mode requirements | ||
| 740 | get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst) { | ||
| 741 | if (BITS(inst, 25, 27) == 2) { | ||
| 742 | return LnSWoUB(ImmediatePostIndexed); | ||
| 743 | } else if (BITS(inst, 25, 27) == 3) { | ||
| 744 | return LnSWoUB(ScaledRegisterPostIndexed); | ||
| 745 | } | ||
| 746 | // Reaching this would indicate the thumb version | ||
| 747 | // of this instruction, however the 3DS CPU doesn't | ||
| 748 | // support this variant (the 3DS CPU is only ARMv6K, | ||
| 749 | // while this variant is added in ARMv6T2). | ||
| 750 | // So it's sufficient for citra to not implement this. | ||
| 751 | return nullptr; | ||
| 752 | } | ||
| 753 | |||
| 754 | enum { FETCH_SUCCESS, FETCH_FAILURE }; | ||
| 755 | |||
| 756 | static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, | ||
| 757 | ARM_INST_PTR* ptr_inst_base) { | ||
| 758 | // Check if in Thumb mode | ||
| 759 | ThumbDecodeStatus ret = TranslateThumbInstruction(addr, inst, arm_inst, inst_size); | ||
| 760 | if (ret == ThumbDecodeStatus::BRANCH) { | ||
| 761 | int inst_index; | ||
| 762 | int table_length = static_cast<int>(arm_instruction_trans_len); | ||
| 763 | u32 tinstr = GetThumbInstruction(inst, addr); | ||
| 764 | |||
| 765 | switch ((tinstr & 0xF800) >> 11) { | ||
| 766 | case 26: | ||
| 767 | case 27: | ||
| 768 | if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)) { | ||
| 769 | inst_index = table_length - 4; | ||
| 770 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 771 | } else { | ||
| 772 | LOG_ERROR(Core_ARM, "thumb decoder error"); | ||
| 773 | } | ||
| 774 | break; | ||
| 775 | case 28: | ||
| 776 | // Branch 2, unconditional branch | ||
| 777 | inst_index = table_length - 5; | ||
| 778 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 779 | break; | ||
| 780 | |||
| 781 | case 8: | ||
| 782 | case 29: | ||
| 783 | // For BLX 1 thumb instruction | ||
| 784 | inst_index = table_length - 1; | ||
| 785 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 786 | break; | ||
| 787 | case 30: | ||
| 788 | // For BL 1 thumb instruction | ||
| 789 | inst_index = table_length - 3; | ||
| 790 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 791 | break; | ||
| 792 | case 31: | ||
| 793 | // For BL 2 thumb instruction | ||
| 794 | inst_index = table_length - 2; | ||
| 795 | *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); | ||
| 796 | break; | ||
| 797 | default: | ||
| 798 | ret = ThumbDecodeStatus::UNDEFINED; | ||
| 799 | break; | ||
| 800 | } | ||
| 801 | } | ||
| 802 | return ret; | ||
| 803 | } | ||
| 804 | |||
| 805 | enum { KEEP_GOING, FETCH_EXCEPTION }; | ||
| 806 | |||
| 807 | MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64)); | ||
| 808 | |||
| 809 | static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr, | ||
| 810 | ARM_INST_PTR& inst_base) { | ||
| 811 | u32 inst_size = 4; | ||
| 812 | u32 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); | ||
| 813 | |||
| 814 | // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM | ||
| 815 | // instruction | ||
| 816 | if (cpu->TFlag) { | ||
| 817 | u32 arm_inst; | ||
| 818 | ThumbDecodeStatus state = | ||
| 819 | DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base); | ||
| 820 | |||
| 821 | // We have translated the Thumb branch instruction in the Thumb decoder | ||
| 822 | if (state == ThumbDecodeStatus::BRANCH) { | ||
| 823 | return inst_size; | ||
| 824 | } | ||
| 825 | inst = arm_inst; | ||
| 826 | } | ||
| 827 | |||
| 828 | int idx; | ||
| 829 | if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { | ||
| 830 | LOG_ERROR(Core_ARM, "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %08" PRIX32, | ||
| 831 | phys_addr, inst); | ||
| 832 | LOG_ERROR(Core_ARM, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, | ||
| 833 | cpu->TFlag, cpu->Reg[15]); | ||
| 834 | CITRA_IGNORE_EXIT(-1); | ||
| 835 | } | ||
| 836 | inst_base = arm_instruction_trans[idx](inst, idx); | ||
| 837 | |||
| 838 | return inst_size; | ||
| 839 | } | ||
| 840 | |||
| 841 | static int InterpreterTranslateBlock(ARMul_State* cpu, std::size_t& bb_start, u32 addr) { | ||
| 842 | MICROPROFILE_SCOPE(DynCom_Decode); | ||
| 843 | |||
| 844 | // Decode instruction, get index | ||
| 845 | // Allocate memory and init InsCream | ||
| 846 | // Go on next, until terminal instruction | ||
| 847 | // Save start addr of basicblock in CreamCache | ||
| 848 | ARM_INST_PTR inst_base = nullptr; | ||
| 849 | TransExtData ret = TransExtData::NON_BRANCH; | ||
| 850 | int size = 0; // instruction size of basic block | ||
| 851 | bb_start = trans_cache_buf_top; | ||
| 852 | |||
| 853 | u32 phys_addr = addr; | ||
| 854 | u32 pc_start = cpu->Reg[15]; | ||
| 855 | |||
| 856 | while (ret == TransExtData::NON_BRANCH) { | ||
| 857 | unsigned int inst_size = InterpreterTranslateInstruction(cpu, phys_addr, inst_base); | ||
| 858 | |||
| 859 | size++; | ||
| 860 | |||
| 861 | phys_addr += inst_size; | ||
| 862 | |||
| 863 | if ((phys_addr & 0xfff) == 0) { | ||
| 864 | inst_base->br = TransExtData::END_OF_PAGE; | ||
| 865 | } | ||
| 866 | ret = inst_base->br; | ||
| 867 | }; | ||
| 868 | |||
| 869 | cpu->instruction_cache[pc_start] = bb_start; | ||
| 870 | |||
| 871 | return KEEP_GOING; | ||
| 872 | } | ||
| 873 | |||
| 874 | static int InterpreterTranslateSingle(ARMul_State* cpu, std::size_t& bb_start, u32 addr) { | ||
| 875 | MICROPROFILE_SCOPE(DynCom_Decode); | ||
| 876 | |||
| 877 | ARM_INST_PTR inst_base = nullptr; | ||
| 878 | bb_start = trans_cache_buf_top; | ||
| 879 | |||
| 880 | u32 phys_addr = addr; | ||
| 881 | u32 pc_start = cpu->Reg[15]; | ||
| 882 | |||
| 883 | InterpreterTranslateInstruction(cpu, phys_addr, inst_base); | ||
| 884 | |||
| 885 | if (inst_base->br == TransExtData::NON_BRANCH) { | ||
| 886 | inst_base->br = TransExtData::SINGLE_STEP; | ||
| 887 | } | ||
| 888 | |||
| 889 | cpu->instruction_cache[pc_start] = bb_start; | ||
| 890 | |||
| 891 | return KEEP_GOING; | ||
| 892 | } | ||
| 893 | |||
| 894 | static int clz(unsigned int x) { | ||
| 895 | int n; | ||
| 896 | if (x == 0) | ||
| 897 | return (32); | ||
| 898 | n = 1; | ||
| 899 | if ((x >> 16) == 0) { | ||
| 900 | n = n + 16; | ||
| 901 | x = x << 16; | ||
| 902 | } | ||
| 903 | if ((x >> 24) == 0) { | ||
| 904 | n = n + 8; | ||
| 905 | x = x << 8; | ||
| 906 | } | ||
| 907 | if ((x >> 28) == 0) { | ||
| 908 | n = n + 4; | ||
| 909 | x = x << 4; | ||
| 910 | } | ||
| 911 | if ((x >> 30) == 0) { | ||
| 912 | n = n + 2; | ||
| 913 | x = x << 2; | ||
| 914 | } | ||
| 915 | n = n - (x >> 31); | ||
| 916 | return n; | ||
| 917 | } | ||
| 918 | |||
| 919 | MICROPROFILE_DEFINE(DynCom_Execute, "DynCom", "Execute", MP_RGB(255, 0, 0)); | ||
| 920 | |||
| 921 | unsigned InterpreterMainLoop(ARMul_State* cpu) { | ||
| 922 | MICROPROFILE_SCOPE(DynCom_Execute); | ||
| 923 | |||
| 924 | GDBStub::BreakpointAddress breakpoint_data; | ||
| 925 | |||
| 926 | #undef RM | ||
| 927 | #undef RS | ||
| 928 | |||
| 929 | #define CRn inst_cream->crn | ||
| 930 | #define OPCODE_1 inst_cream->opcode_1 | ||
| 931 | #define OPCODE_2 inst_cream->opcode_2 | ||
| 932 | #define CRm inst_cream->crm | ||
| 933 | #define RD cpu->Reg[inst_cream->Rd] | ||
| 934 | #define RD2 cpu->Reg[inst_cream->Rd + 1] | ||
| 935 | #define RN cpu->Reg[inst_cream->Rn] | ||
| 936 | #define RM cpu->Reg[inst_cream->Rm] | ||
| 937 | #define RS cpu->Reg[inst_cream->Rs] | ||
| 938 | #define RDHI cpu->Reg[inst_cream->RdHi] | ||
| 939 | #define RDLO cpu->Reg[inst_cream->RdLo] | ||
| 940 | #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4) | ||
| 941 | #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24) | ||
| 942 | #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) | ||
| 943 | |||
| 944 | #define FETCH_INST \ | ||
| 945 | if (inst_base->br != TransExtData::NON_BRANCH) \ | ||
| 946 | goto DISPATCH; \ | ||
| 947 | inst_base = (arm_inst*)&trans_cache_buf[ptr] | ||
| 948 | |||
| 949 | #define INC_PC(l) ptr += sizeof(arm_inst) + l | ||
| 950 | #define INC_PC_STUB ptr += sizeof(arm_inst) | ||
| 951 | |||
| 952 | #define GDB_BP_CHECK \ | ||
| 953 | cpu->Cpsr &= ~(1 << 5); \ | ||
| 954 | cpu->Cpsr |= cpu->TFlag << 5; \ | ||
| 955 | if (GDBStub::IsServerEnabled()) { \ | ||
| 956 | if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None && \ | ||
| 957 | PC == breakpoint_data.address)) { \ | ||
| 958 | GDBStub::Break(); \ | ||
| 959 | goto END; \ | ||
| 960 | } \ | ||
| 961 | } | ||
| 962 | |||
| 963 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a | ||
| 964 | // clunky switch statement. | ||
| 965 | #if defined __GNUC__ || defined __clang__ | ||
| 966 | #define GOTO_NEXT_INST \ | ||
| 967 | GDB_BP_CHECK; \ | ||
| 968 | if (num_instrs >= cpu->NumInstrsToExecute) \ | ||
| 969 | goto END; \ | ||
| 970 | num_instrs++; \ | ||
| 971 | goto* InstLabel[inst_base->idx] | ||
| 972 | #else | ||
| 973 | #define GOTO_NEXT_INST \ | ||
| 974 | GDB_BP_CHECK; \ | ||
| 975 | if (num_instrs >= cpu->NumInstrsToExecute) \ | ||
| 976 | goto END; \ | ||
| 977 | num_instrs++; \ | ||
| 978 | switch (inst_base->idx) { \ | ||
| 979 | case 0: \ | ||
| 980 | goto VMLA_INST; \ | ||
| 981 | case 1: \ | ||
| 982 | goto VMLS_INST; \ | ||
| 983 | case 2: \ | ||
| 984 | goto VNMLA_INST; \ | ||
| 985 | case 3: \ | ||
| 986 | goto VNMLS_INST; \ | ||
| 987 | case 4: \ | ||
| 988 | goto VNMUL_INST; \ | ||
| 989 | case 5: \ | ||
| 990 | goto VMUL_INST; \ | ||
| 991 | case 6: \ | ||
| 992 | goto VADD_INST; \ | ||
| 993 | case 7: \ | ||
| 994 | goto VSUB_INST; \ | ||
| 995 | case 8: \ | ||
| 996 | goto VDIV_INST; \ | ||
| 997 | case 9: \ | ||
| 998 | goto VMOVI_INST; \ | ||
| 999 | case 10: \ | ||
| 1000 | goto VMOVR_INST; \ | ||
| 1001 | case 11: \ | ||
| 1002 | goto VABS_INST; \ | ||
| 1003 | case 12: \ | ||
| 1004 | goto VNEG_INST; \ | ||
| 1005 | case 13: \ | ||
| 1006 | goto VSQRT_INST; \ | ||
| 1007 | case 14: \ | ||
| 1008 | goto VCMP_INST; \ | ||
| 1009 | case 15: \ | ||
| 1010 | goto VCMP2_INST; \ | ||
| 1011 | case 16: \ | ||
| 1012 | goto VCVTBDS_INST; \ | ||
| 1013 | case 17: \ | ||
| 1014 | goto VCVTBFF_INST; \ | ||
| 1015 | case 18: \ | ||
| 1016 | goto VCVTBFI_INST; \ | ||
| 1017 | case 19: \ | ||
| 1018 | goto VMOVBRS_INST; \ | ||
| 1019 | case 20: \ | ||
| 1020 | goto VMSR_INST; \ | ||
| 1021 | case 21: \ | ||
| 1022 | goto VMOVBRC_INST; \ | ||
| 1023 | case 22: \ | ||
| 1024 | goto VMRS_INST; \ | ||
| 1025 | case 23: \ | ||
| 1026 | goto VMOVBCR_INST; \ | ||
| 1027 | case 24: \ | ||
| 1028 | goto VMOVBRRSS_INST; \ | ||
| 1029 | case 25: \ | ||
| 1030 | goto VMOVBRRD_INST; \ | ||
| 1031 | case 26: \ | ||
| 1032 | goto VSTR_INST; \ | ||
| 1033 | case 27: \ | ||
| 1034 | goto VPUSH_INST; \ | ||
| 1035 | case 28: \ | ||
| 1036 | goto VSTM_INST; \ | ||
| 1037 | case 29: \ | ||
| 1038 | goto VPOP_INST; \ | ||
| 1039 | case 30: \ | ||
| 1040 | goto VLDR_INST; \ | ||
| 1041 | case 31: \ | ||
| 1042 | goto VLDM_INST; \ | ||
| 1043 | case 32: \ | ||
| 1044 | goto SRS_INST; \ | ||
| 1045 | case 33: \ | ||
| 1046 | goto RFE_INST; \ | ||
| 1047 | case 34: \ | ||
| 1048 | goto BKPT_INST; \ | ||
| 1049 | case 35: \ | ||
| 1050 | goto BLX_INST; \ | ||
| 1051 | case 36: \ | ||
| 1052 | goto CPS_INST; \ | ||
| 1053 | case 37: \ | ||
| 1054 | goto PLD_INST; \ | ||
| 1055 | case 38: \ | ||
| 1056 | goto SETEND_INST; \ | ||
| 1057 | case 39: \ | ||
| 1058 | goto CLREX_INST; \ | ||
| 1059 | case 40: \ | ||
| 1060 | goto REV16_INST; \ | ||
| 1061 | case 41: \ | ||
| 1062 | goto USAD8_INST; \ | ||
| 1063 | case 42: \ | ||
| 1064 | goto SXTB_INST; \ | ||
| 1065 | case 43: \ | ||
| 1066 | goto UXTB_INST; \ | ||
| 1067 | case 44: \ | ||
| 1068 | goto SXTH_INST; \ | ||
| 1069 | case 45: \ | ||
| 1070 | goto SXTB16_INST; \ | ||
| 1071 | case 46: \ | ||
| 1072 | goto UXTH_INST; \ | ||
| 1073 | case 47: \ | ||
| 1074 | goto UXTB16_INST; \ | ||
| 1075 | case 48: \ | ||
| 1076 | goto CPY_INST; \ | ||
| 1077 | case 49: \ | ||
| 1078 | goto UXTAB_INST; \ | ||
| 1079 | case 50: \ | ||
| 1080 | goto SSUB8_INST; \ | ||
| 1081 | case 51: \ | ||
| 1082 | goto SHSUB8_INST; \ | ||
| 1083 | case 52: \ | ||
| 1084 | goto SSUBADDX_INST; \ | ||
| 1085 | case 53: \ | ||
| 1086 | goto STREX_INST; \ | ||
| 1087 | case 54: \ | ||
| 1088 | goto STREXB_INST; \ | ||
| 1089 | case 55: \ | ||
| 1090 | goto SWP_INST; \ | ||
| 1091 | case 56: \ | ||
| 1092 | goto SWPB_INST; \ | ||
| 1093 | case 57: \ | ||
| 1094 | goto SSUB16_INST; \ | ||
| 1095 | case 58: \ | ||
| 1096 | goto SSAT16_INST; \ | ||
| 1097 | case 59: \ | ||
| 1098 | goto SHSUBADDX_INST; \ | ||
| 1099 | case 60: \ | ||
| 1100 | goto QSUBADDX_INST; \ | ||
| 1101 | case 61: \ | ||
| 1102 | goto SHADDSUBX_INST; \ | ||
| 1103 | case 62: \ | ||
| 1104 | goto SHADD8_INST; \ | ||
| 1105 | case 63: \ | ||
| 1106 | goto SHADD16_INST; \ | ||
| 1107 | case 64: \ | ||
| 1108 | goto SEL_INST; \ | ||
| 1109 | case 65: \ | ||
| 1110 | goto SADDSUBX_INST; \ | ||
| 1111 | case 66: \ | ||
| 1112 | goto SADD8_INST; \ | ||
| 1113 | case 67: \ | ||
| 1114 | goto SADD16_INST; \ | ||
| 1115 | case 68: \ | ||
| 1116 | goto SHSUB16_INST; \ | ||
| 1117 | case 69: \ | ||
| 1118 | goto UMAAL_INST; \ | ||
| 1119 | case 70: \ | ||
| 1120 | goto UXTAB16_INST; \ | ||
| 1121 | case 71: \ | ||
| 1122 | goto USUBADDX_INST; \ | ||
| 1123 | case 72: \ | ||
| 1124 | goto USUB8_INST; \ | ||
| 1125 | case 73: \ | ||
| 1126 | goto USUB16_INST; \ | ||
| 1127 | case 74: \ | ||
| 1128 | goto USAT16_INST; \ | ||
| 1129 | case 75: \ | ||
| 1130 | goto USADA8_INST; \ | ||
| 1131 | case 76: \ | ||
| 1132 | goto UQSUBADDX_INST; \ | ||
| 1133 | case 77: \ | ||
| 1134 | goto UQSUB8_INST; \ | ||
| 1135 | case 78: \ | ||
| 1136 | goto UQSUB16_INST; \ | ||
| 1137 | case 79: \ | ||
| 1138 | goto UQADDSUBX_INST; \ | ||
| 1139 | case 80: \ | ||
| 1140 | goto UQADD8_INST; \ | ||
| 1141 | case 81: \ | ||
| 1142 | goto UQADD16_INST; \ | ||
| 1143 | case 82: \ | ||
| 1144 | goto SXTAB_INST; \ | ||
| 1145 | case 83: \ | ||
| 1146 | goto UHSUBADDX_INST; \ | ||
| 1147 | case 84: \ | ||
| 1148 | goto UHSUB8_INST; \ | ||
| 1149 | case 85: \ | ||
| 1150 | goto UHSUB16_INST; \ | ||
| 1151 | case 86: \ | ||
| 1152 | goto UHADDSUBX_INST; \ | ||
| 1153 | case 87: \ | ||
| 1154 | goto UHADD8_INST; \ | ||
| 1155 | case 88: \ | ||
| 1156 | goto UHADD16_INST; \ | ||
| 1157 | case 89: \ | ||
| 1158 | goto UADDSUBX_INST; \ | ||
| 1159 | case 90: \ | ||
| 1160 | goto UADD8_INST; \ | ||
| 1161 | case 91: \ | ||
| 1162 | goto UADD16_INST; \ | ||
| 1163 | case 92: \ | ||
| 1164 | goto SXTAH_INST; \ | ||
| 1165 | case 93: \ | ||
| 1166 | goto SXTAB16_INST; \ | ||
| 1167 | case 94: \ | ||
| 1168 | goto QADD8_INST; \ | ||
| 1169 | case 95: \ | ||
| 1170 | goto BXJ_INST; \ | ||
| 1171 | case 96: \ | ||
| 1172 | goto CLZ_INST; \ | ||
| 1173 | case 97: \ | ||
| 1174 | goto UXTAH_INST; \ | ||
| 1175 | case 98: \ | ||
| 1176 | goto BX_INST; \ | ||
| 1177 | case 99: \ | ||
| 1178 | goto REV_INST; \ | ||
| 1179 | case 100: \ | ||
| 1180 | goto BLX_INST; \ | ||
| 1181 | case 101: \ | ||
| 1182 | goto REVSH_INST; \ | ||
| 1183 | case 102: \ | ||
| 1184 | goto QADD_INST; \ | ||
| 1185 | case 103: \ | ||
| 1186 | goto QADD16_INST; \ | ||
| 1187 | case 104: \ | ||
| 1188 | goto QADDSUBX_INST; \ | ||
| 1189 | case 105: \ | ||
| 1190 | goto LDREX_INST; \ | ||
| 1191 | case 106: \ | ||
| 1192 | goto QDADD_INST; \ | ||
| 1193 | case 107: \ | ||
| 1194 | goto QDSUB_INST; \ | ||
| 1195 | case 108: \ | ||
| 1196 | goto QSUB_INST; \ | ||
| 1197 | case 109: \ | ||
| 1198 | goto LDREXB_INST; \ | ||
| 1199 | case 110: \ | ||
| 1200 | goto QSUB8_INST; \ | ||
| 1201 | case 111: \ | ||
| 1202 | goto QSUB16_INST; \ | ||
| 1203 | case 112: \ | ||
| 1204 | goto SMUAD_INST; \ | ||
| 1205 | case 113: \ | ||
| 1206 | goto SMMUL_INST; \ | ||
| 1207 | case 114: \ | ||
| 1208 | goto SMUSD_INST; \ | ||
| 1209 | case 115: \ | ||
| 1210 | goto SMLSD_INST; \ | ||
| 1211 | case 116: \ | ||
| 1212 | goto SMLSLD_INST; \ | ||
| 1213 | case 117: \ | ||
| 1214 | goto SMMLA_INST; \ | ||
| 1215 | case 118: \ | ||
| 1216 | goto SMMLS_INST; \ | ||
| 1217 | case 119: \ | ||
| 1218 | goto SMLALD_INST; \ | ||
| 1219 | case 120: \ | ||
| 1220 | goto SMLAD_INST; \ | ||
| 1221 | case 121: \ | ||
| 1222 | goto SMLAW_INST; \ | ||
| 1223 | case 122: \ | ||
| 1224 | goto SMULW_INST; \ | ||
| 1225 | case 123: \ | ||
| 1226 | goto PKHTB_INST; \ | ||
| 1227 | case 124: \ | ||
| 1228 | goto PKHBT_INST; \ | ||
| 1229 | case 125: \ | ||
| 1230 | goto SMUL_INST; \ | ||
| 1231 | case 126: \ | ||
| 1232 | goto SMLALXY_INST; \ | ||
| 1233 | case 127: \ | ||
| 1234 | goto SMLA_INST; \ | ||
| 1235 | case 128: \ | ||
| 1236 | goto MCRR_INST; \ | ||
| 1237 | case 129: \ | ||
| 1238 | goto MRRC_INST; \ | ||
| 1239 | case 130: \ | ||
| 1240 | goto CMP_INST; \ | ||
| 1241 | case 131: \ | ||
| 1242 | goto TST_INST; \ | ||
| 1243 | case 132: \ | ||
| 1244 | goto TEQ_INST; \ | ||
| 1245 | case 133: \ | ||
| 1246 | goto CMN_INST; \ | ||
| 1247 | case 134: \ | ||
| 1248 | goto SMULL_INST; \ | ||
| 1249 | case 135: \ | ||
| 1250 | goto UMULL_INST; \ | ||
| 1251 | case 136: \ | ||
| 1252 | goto UMLAL_INST; \ | ||
| 1253 | case 137: \ | ||
| 1254 | goto SMLAL_INST; \ | ||
| 1255 | case 138: \ | ||
| 1256 | goto MUL_INST; \ | ||
| 1257 | case 139: \ | ||
| 1258 | goto MLA_INST; \ | ||
| 1259 | case 140: \ | ||
| 1260 | goto SSAT_INST; \ | ||
| 1261 | case 141: \ | ||
| 1262 | goto USAT_INST; \ | ||
| 1263 | case 142: \ | ||
| 1264 | goto MRS_INST; \ | ||
| 1265 | case 143: \ | ||
| 1266 | goto MSR_INST; \ | ||
| 1267 | case 144: \ | ||
| 1268 | goto AND_INST; \ | ||
| 1269 | case 145: \ | ||
| 1270 | goto BIC_INST; \ | ||
| 1271 | case 146: \ | ||
| 1272 | goto LDM_INST; \ | ||
| 1273 | case 147: \ | ||
| 1274 | goto EOR_INST; \ | ||
| 1275 | case 148: \ | ||
| 1276 | goto ADD_INST; \ | ||
| 1277 | case 149: \ | ||
| 1278 | goto RSB_INST; \ | ||
| 1279 | case 150: \ | ||
| 1280 | goto RSC_INST; \ | ||
| 1281 | case 151: \ | ||
| 1282 | goto SBC_INST; \ | ||
| 1283 | case 152: \ | ||
| 1284 | goto ADC_INST; \ | ||
| 1285 | case 153: \ | ||
| 1286 | goto SUB_INST; \ | ||
| 1287 | case 154: \ | ||
| 1288 | goto ORR_INST; \ | ||
| 1289 | case 155: \ | ||
| 1290 | goto MVN_INST; \ | ||
| 1291 | case 156: \ | ||
| 1292 | goto MOV_INST; \ | ||
| 1293 | case 157: \ | ||
| 1294 | goto STM_INST; \ | ||
| 1295 | case 158: \ | ||
| 1296 | goto LDM_INST; \ | ||
| 1297 | case 159: \ | ||
| 1298 | goto LDRSH_INST; \ | ||
| 1299 | case 160: \ | ||
| 1300 | goto STM_INST; \ | ||
| 1301 | case 161: \ | ||
| 1302 | goto LDM_INST; \ | ||
| 1303 | case 162: \ | ||
| 1304 | goto LDRSB_INST; \ | ||
| 1305 | case 163: \ | ||
| 1306 | goto STRD_INST; \ | ||
| 1307 | case 164: \ | ||
| 1308 | goto LDRH_INST; \ | ||
| 1309 | case 165: \ | ||
| 1310 | goto STRH_INST; \ | ||
| 1311 | case 166: \ | ||
| 1312 | goto LDRD_INST; \ | ||
| 1313 | case 167: \ | ||
| 1314 | goto STRT_INST; \ | ||
| 1315 | case 168: \ | ||
| 1316 | goto STRBT_INST; \ | ||
| 1317 | case 169: \ | ||
| 1318 | goto LDRBT_INST; \ | ||
| 1319 | case 170: \ | ||
| 1320 | goto LDRT_INST; \ | ||
| 1321 | case 171: \ | ||
| 1322 | goto MRC_INST; \ | ||
| 1323 | case 172: \ | ||
| 1324 | goto MCR_INST; \ | ||
| 1325 | case 173: \ | ||
| 1326 | goto MSR_INST; \ | ||
| 1327 | case 174: \ | ||
| 1328 | goto MSR_INST; \ | ||
| 1329 | case 175: \ | ||
| 1330 | goto MSR_INST; \ | ||
| 1331 | case 176: \ | ||
| 1332 | goto MSR_INST; \ | ||
| 1333 | case 177: \ | ||
| 1334 | goto MSR_INST; \ | ||
| 1335 | case 178: \ | ||
| 1336 | goto LDRB_INST; \ | ||
| 1337 | case 179: \ | ||
| 1338 | goto STRB_INST; \ | ||
| 1339 | case 180: \ | ||
| 1340 | goto LDR_INST; \ | ||
| 1341 | case 181: \ | ||
| 1342 | goto LDRCOND_INST; \ | ||
| 1343 | case 182: \ | ||
| 1344 | goto STR_INST; \ | ||
| 1345 | case 183: \ | ||
| 1346 | goto CDP_INST; \ | ||
| 1347 | case 184: \ | ||
| 1348 | goto STC_INST; \ | ||
| 1349 | case 185: \ | ||
| 1350 | goto LDC_INST; \ | ||
| 1351 | case 186: \ | ||
| 1352 | goto LDREXD_INST; \ | ||
| 1353 | case 187: \ | ||
| 1354 | goto STREXD_INST; \ | ||
| 1355 | case 188: \ | ||
| 1356 | goto LDREXH_INST; \ | ||
| 1357 | case 189: \ | ||
| 1358 | goto STREXH_INST; \ | ||
| 1359 | case 190: \ | ||
| 1360 | goto NOP_INST; \ | ||
| 1361 | case 191: \ | ||
| 1362 | goto YIELD_INST; \ | ||
| 1363 | case 192: \ | ||
| 1364 | goto WFE_INST; \ | ||
| 1365 | case 193: \ | ||
| 1366 | goto WFI_INST; \ | ||
| 1367 | case 194: \ | ||
| 1368 | goto SEV_INST; \ | ||
| 1369 | case 195: \ | ||
| 1370 | goto SWI_INST; \ | ||
| 1371 | case 196: \ | ||
| 1372 | goto BBL_INST; \ | ||
| 1373 | case 197: \ | ||
| 1374 | goto B_2_THUMB; \ | ||
| 1375 | case 198: \ | ||
| 1376 | goto B_COND_THUMB; \ | ||
| 1377 | case 199: \ | ||
| 1378 | goto BL_1_THUMB; \ | ||
| 1379 | case 200: \ | ||
| 1380 | goto BL_2_THUMB; \ | ||
| 1381 | case 201: \ | ||
| 1382 | goto BLX_1_THUMB; \ | ||
| 1383 | case 202: \ | ||
| 1384 | goto DISPATCH; \ | ||
| 1385 | case 203: \ | ||
| 1386 | goto INIT_INST_LENGTH; \ | ||
| 1387 | case 204: \ | ||
| 1388 | goto END; \ | ||
| 1389 | } | ||
| 1390 | #endif | ||
| 1391 | |||
| 1392 | #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0) | ||
| 1393 | #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1) | ||
| 1394 | #define UPDATE_CFLAG_WITH_SC (cpu->CFlag = cpu->shifter_carry_out) | ||
| 1395 | |||
| 1396 | #define SAVE_NZCVT \ | ||
| 1397 | cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | (cpu->NFlag << 31) | (cpu->ZFlag << 30) | \ | ||
| 1398 | (cpu->CFlag << 29) | (cpu->VFlag << 28) | (cpu->TFlag << 5) | ||
| 1399 | #define LOAD_NZCVT \ | ||
| 1400 | cpu->NFlag = (cpu->Cpsr >> 31); \ | ||
| 1401 | cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \ | ||
| 1402 | cpu->CFlag = (cpu->Cpsr >> 29) & 1; \ | ||
| 1403 | cpu->VFlag = (cpu->Cpsr >> 28) & 1; \ | ||
| 1404 | cpu->TFlag = (cpu->Cpsr >> 5) & 1; | ||
| 1405 | |||
| 1406 | #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) | ||
| 1407 | #define PC (cpu->Reg[15]) | ||
| 1408 | |||
| 1409 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback | ||
| 1410 | // to a clunky switch statement. | ||
| 1411 | #if defined __GNUC__ || defined __clang__ | ||
| 1412 | void* InstLabel[] = {&&VMLA_INST, | ||
| 1413 | &&VMLS_INST, | ||
| 1414 | &&VNMLA_INST, | ||
| 1415 | &&VNMLS_INST, | ||
| 1416 | &&VNMUL_INST, | ||
| 1417 | &&VMUL_INST, | ||
| 1418 | &&VADD_INST, | ||
| 1419 | &&VSUB_INST, | ||
| 1420 | &&VDIV_INST, | ||
| 1421 | &&VMOVI_INST, | ||
| 1422 | &&VMOVR_INST, | ||
| 1423 | &&VABS_INST, | ||
| 1424 | &&VNEG_INST, | ||
| 1425 | &&VSQRT_INST, | ||
| 1426 | &&VCMP_INST, | ||
| 1427 | &&VCMP2_INST, | ||
| 1428 | &&VCVTBDS_INST, | ||
| 1429 | &&VCVTBFF_INST, | ||
| 1430 | &&VCVTBFI_INST, | ||
| 1431 | &&VMOVBRS_INST, | ||
| 1432 | &&VMSR_INST, | ||
| 1433 | &&VMOVBRC_INST, | ||
| 1434 | &&VMRS_INST, | ||
| 1435 | &&VMOVBCR_INST, | ||
| 1436 | &&VMOVBRRSS_INST, | ||
| 1437 | &&VMOVBRRD_INST, | ||
| 1438 | &&VSTR_INST, | ||
| 1439 | &&VPUSH_INST, | ||
| 1440 | &&VSTM_INST, | ||
| 1441 | &&VPOP_INST, | ||
| 1442 | &&VLDR_INST, | ||
| 1443 | &&VLDM_INST, | ||
| 1444 | |||
| 1445 | &&SRS_INST, | ||
| 1446 | &&RFE_INST, | ||
| 1447 | &&BKPT_INST, | ||
| 1448 | &&BLX_INST, | ||
| 1449 | &&CPS_INST, | ||
| 1450 | &&PLD_INST, | ||
| 1451 | &&SETEND_INST, | ||
| 1452 | &&CLREX_INST, | ||
| 1453 | &&REV16_INST, | ||
| 1454 | &&USAD8_INST, | ||
| 1455 | &&SXTB_INST, | ||
| 1456 | &&UXTB_INST, | ||
| 1457 | &&SXTH_INST, | ||
| 1458 | &&SXTB16_INST, | ||
| 1459 | &&UXTH_INST, | ||
| 1460 | &&UXTB16_INST, | ||
| 1461 | &&CPY_INST, | ||
| 1462 | &&UXTAB_INST, | ||
| 1463 | &&SSUB8_INST, | ||
| 1464 | &&SHSUB8_INST, | ||
| 1465 | &&SSUBADDX_INST, | ||
| 1466 | &&STREX_INST, | ||
| 1467 | &&STREXB_INST, | ||
| 1468 | &&SWP_INST, | ||
| 1469 | &&SWPB_INST, | ||
| 1470 | &&SSUB16_INST, | ||
| 1471 | &&SSAT16_INST, | ||
| 1472 | &&SHSUBADDX_INST, | ||
| 1473 | &&QSUBADDX_INST, | ||
| 1474 | &&SHADDSUBX_INST, | ||
| 1475 | &&SHADD8_INST, | ||
| 1476 | &&SHADD16_INST, | ||
| 1477 | &&SEL_INST, | ||
| 1478 | &&SADDSUBX_INST, | ||
| 1479 | &&SADD8_INST, | ||
| 1480 | &&SADD16_INST, | ||
| 1481 | &&SHSUB16_INST, | ||
| 1482 | &&UMAAL_INST, | ||
| 1483 | &&UXTAB16_INST, | ||
| 1484 | &&USUBADDX_INST, | ||
| 1485 | &&USUB8_INST, | ||
| 1486 | &&USUB16_INST, | ||
| 1487 | &&USAT16_INST, | ||
| 1488 | &&USADA8_INST, | ||
| 1489 | &&UQSUBADDX_INST, | ||
| 1490 | &&UQSUB8_INST, | ||
| 1491 | &&UQSUB16_INST, | ||
| 1492 | &&UQADDSUBX_INST, | ||
| 1493 | &&UQADD8_INST, | ||
| 1494 | &&UQADD16_INST, | ||
| 1495 | &&SXTAB_INST, | ||
| 1496 | &&UHSUBADDX_INST, | ||
| 1497 | &&UHSUB8_INST, | ||
| 1498 | &&UHSUB16_INST, | ||
| 1499 | &&UHADDSUBX_INST, | ||
| 1500 | &&UHADD8_INST, | ||
| 1501 | &&UHADD16_INST, | ||
| 1502 | &&UADDSUBX_INST, | ||
| 1503 | &&UADD8_INST, | ||
| 1504 | &&UADD16_INST, | ||
| 1505 | &&SXTAH_INST, | ||
| 1506 | &&SXTAB16_INST, | ||
| 1507 | &&QADD8_INST, | ||
| 1508 | &&BXJ_INST, | ||
| 1509 | &&CLZ_INST, | ||
| 1510 | &&UXTAH_INST, | ||
| 1511 | &&BX_INST, | ||
| 1512 | &&REV_INST, | ||
| 1513 | &&BLX_INST, | ||
| 1514 | &&REVSH_INST, | ||
| 1515 | &&QADD_INST, | ||
| 1516 | &&QADD16_INST, | ||
| 1517 | &&QADDSUBX_INST, | ||
| 1518 | &&LDREX_INST, | ||
| 1519 | &&QDADD_INST, | ||
| 1520 | &&QDSUB_INST, | ||
| 1521 | &&QSUB_INST, | ||
| 1522 | &&LDREXB_INST, | ||
| 1523 | &&QSUB8_INST, | ||
| 1524 | &&QSUB16_INST, | ||
| 1525 | &&SMUAD_INST, | ||
| 1526 | &&SMMUL_INST, | ||
| 1527 | &&SMUSD_INST, | ||
| 1528 | &&SMLSD_INST, | ||
| 1529 | &&SMLSLD_INST, | ||
| 1530 | &&SMMLA_INST, | ||
| 1531 | &&SMMLS_INST, | ||
| 1532 | &&SMLALD_INST, | ||
| 1533 | &&SMLAD_INST, | ||
| 1534 | &&SMLAW_INST, | ||
| 1535 | &&SMULW_INST, | ||
| 1536 | &&PKHTB_INST, | ||
| 1537 | &&PKHBT_INST, | ||
| 1538 | &&SMUL_INST, | ||
| 1539 | &&SMLALXY_INST, | ||
| 1540 | &&SMLA_INST, | ||
| 1541 | &&MCRR_INST, | ||
| 1542 | &&MRRC_INST, | ||
| 1543 | &&CMP_INST, | ||
| 1544 | &&TST_INST, | ||
| 1545 | &&TEQ_INST, | ||
| 1546 | &&CMN_INST, | ||
| 1547 | &&SMULL_INST, | ||
| 1548 | &&UMULL_INST, | ||
| 1549 | &&UMLAL_INST, | ||
| 1550 | &&SMLAL_INST, | ||
| 1551 | &&MUL_INST, | ||
| 1552 | &&MLA_INST, | ||
| 1553 | &&SSAT_INST, | ||
| 1554 | &&USAT_INST, | ||
| 1555 | &&MRS_INST, | ||
| 1556 | &&MSR_INST, | ||
| 1557 | &&AND_INST, | ||
| 1558 | &&BIC_INST, | ||
| 1559 | &&LDM_INST, | ||
| 1560 | &&EOR_INST, | ||
| 1561 | &&ADD_INST, | ||
| 1562 | &&RSB_INST, | ||
| 1563 | &&RSC_INST, | ||
| 1564 | &&SBC_INST, | ||
| 1565 | &&ADC_INST, | ||
| 1566 | &&SUB_INST, | ||
| 1567 | &&ORR_INST, | ||
| 1568 | &&MVN_INST, | ||
| 1569 | &&MOV_INST, | ||
| 1570 | &&STM_INST, | ||
| 1571 | &&LDM_INST, | ||
| 1572 | &&LDRSH_INST, | ||
| 1573 | &&STM_INST, | ||
| 1574 | &&LDM_INST, | ||
| 1575 | &&LDRSB_INST, | ||
| 1576 | &&STRD_INST, | ||
| 1577 | &&LDRH_INST, | ||
| 1578 | &&STRH_INST, | ||
| 1579 | &&LDRD_INST, | ||
| 1580 | &&STRT_INST, | ||
| 1581 | &&STRBT_INST, | ||
| 1582 | &&LDRBT_INST, | ||
| 1583 | &&LDRT_INST, | ||
| 1584 | &&MRC_INST, | ||
| 1585 | &&MCR_INST, | ||
| 1586 | &&MSR_INST, | ||
| 1587 | &&MSR_INST, | ||
| 1588 | &&MSR_INST, | ||
| 1589 | &&MSR_INST, | ||
| 1590 | &&MSR_INST, | ||
| 1591 | &&LDRB_INST, | ||
| 1592 | &&STRB_INST, | ||
| 1593 | &&LDR_INST, | ||
| 1594 | &&LDRCOND_INST, | ||
| 1595 | &&STR_INST, | ||
| 1596 | &&CDP_INST, | ||
| 1597 | &&STC_INST, | ||
| 1598 | &&LDC_INST, | ||
| 1599 | &&LDREXD_INST, | ||
| 1600 | &&STREXD_INST, | ||
| 1601 | &&LDREXH_INST, | ||
| 1602 | &&STREXH_INST, | ||
| 1603 | &&NOP_INST, | ||
| 1604 | &&YIELD_INST, | ||
| 1605 | &&WFE_INST, | ||
| 1606 | &&WFI_INST, | ||
| 1607 | &&SEV_INST, | ||
| 1608 | &&SWI_INST, | ||
| 1609 | &&BBL_INST, | ||
| 1610 | &&B_2_THUMB, | ||
| 1611 | &&B_COND_THUMB, | ||
| 1612 | &&BL_1_THUMB, | ||
| 1613 | &&BL_2_THUMB, | ||
| 1614 | &&BLX_1_THUMB, | ||
| 1615 | &&DISPATCH, | ||
| 1616 | &&INIT_INST_LENGTH, | ||
| 1617 | &&END}; | ||
| 1618 | #endif | ||
| 1619 | arm_inst* inst_base; | ||
| 1620 | unsigned int addr; | ||
| 1621 | unsigned int num_instrs = 0; | ||
| 1622 | |||
| 1623 | std::size_t ptr; | ||
| 1624 | |||
| 1625 | LOAD_NZCVT; | ||
| 1626 | DISPATCH : { | ||
| 1627 | if (!cpu->NirqSig) { | ||
| 1628 | if (!(cpu->Cpsr & 0x80)) { | ||
| 1629 | goto END; | ||
| 1630 | } | ||
| 1631 | } | ||
| 1632 | |||
| 1633 | if (cpu->TFlag) | ||
| 1634 | cpu->Reg[15] &= 0xfffffffe; | ||
| 1635 | else | ||
| 1636 | cpu->Reg[15] &= 0xfffffffc; | ||
| 1637 | |||
| 1638 | // Find the cached instruction cream, otherwise translate it... | ||
| 1639 | auto itr = cpu->instruction_cache.find(cpu->Reg[15]); | ||
| 1640 | if (itr != cpu->instruction_cache.end()) { | ||
| 1641 | ptr = itr->second; | ||
| 1642 | } else if (cpu->NumInstrsToExecute != 1) { | ||
| 1643 | if (InterpreterTranslateBlock(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) | ||
| 1644 | goto END; | ||
| 1645 | } else { | ||
| 1646 | if (InterpreterTranslateSingle(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) | ||
| 1647 | goto END; | ||
| 1648 | } | ||
| 1649 | |||
| 1650 | // Find breakpoint if one exists within the block | ||
| 1651 | if (GDBStub::IsConnected()) { | ||
| 1652 | breakpoint_data = | ||
| 1653 | GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | inst_base = (arm_inst*)&trans_cache_buf[ptr]; | ||
| 1657 | GOTO_NEXT_INST; | ||
| 1658 | } | ||
| 1659 | ADC_INST : { | ||
| 1660 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1661 | adc_inst* const inst_cream = (adc_inst*)inst_base->component; | ||
| 1662 | |||
| 1663 | u32 rn_val = RN; | ||
| 1664 | if (inst_cream->Rn == 15) | ||
| 1665 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 1666 | |||
| 1667 | bool carry; | ||
| 1668 | bool overflow; | ||
| 1669 | RD = AddWithCarry(rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); | ||
| 1670 | |||
| 1671 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 1672 | if (CurrentModeHasSPSR) { | ||
| 1673 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 1674 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 1675 | LOAD_NZCVT; | ||
| 1676 | } | ||
| 1677 | } else if (inst_cream->S) { | ||
| 1678 | UPDATE_NFLAG(RD); | ||
| 1679 | UPDATE_ZFLAG(RD); | ||
| 1680 | cpu->CFlag = carry; | ||
| 1681 | cpu->VFlag = overflow; | ||
| 1682 | } | ||
| 1683 | if (inst_cream->Rd == 15) { | ||
| 1684 | INC_PC(sizeof(adc_inst)); | ||
| 1685 | goto DISPATCH; | ||
| 1686 | } | ||
| 1687 | } | ||
| 1688 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1689 | INC_PC(sizeof(adc_inst)); | ||
| 1690 | FETCH_INST; | ||
| 1691 | GOTO_NEXT_INST; | ||
| 1692 | } | ||
| 1693 | ADD_INST : { | ||
| 1694 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1695 | add_inst* const inst_cream = (add_inst*)inst_base->component; | ||
| 1696 | |||
| 1697 | u32 rn_val = CHECK_READ_REG15_WA(cpu, inst_cream->Rn); | ||
| 1698 | |||
| 1699 | bool carry; | ||
| 1700 | bool overflow; | ||
| 1701 | RD = AddWithCarry(rn_val, SHIFTER_OPERAND, 0, &carry, &overflow); | ||
| 1702 | |||
| 1703 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 1704 | if (CurrentModeHasSPSR) { | ||
| 1705 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 1706 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); | ||
| 1707 | LOAD_NZCVT; | ||
| 1708 | } | ||
| 1709 | } else if (inst_cream->S) { | ||
| 1710 | UPDATE_NFLAG(RD); | ||
| 1711 | UPDATE_ZFLAG(RD); | ||
| 1712 | cpu->CFlag = carry; | ||
| 1713 | cpu->VFlag = overflow; | ||
| 1714 | } | ||
| 1715 | if (inst_cream->Rd == 15) { | ||
| 1716 | INC_PC(sizeof(add_inst)); | ||
| 1717 | goto DISPATCH; | ||
| 1718 | } | ||
| 1719 | } | ||
| 1720 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1721 | INC_PC(sizeof(add_inst)); | ||
| 1722 | FETCH_INST; | ||
| 1723 | GOTO_NEXT_INST; | ||
| 1724 | } | ||
| 1725 | AND_INST : { | ||
| 1726 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1727 | and_inst* const inst_cream = (and_inst*)inst_base->component; | ||
| 1728 | |||
| 1729 | u32 lop = RN; | ||
| 1730 | u32 rop = SHIFTER_OPERAND; | ||
| 1731 | |||
| 1732 | if (inst_cream->Rn == 15) | ||
| 1733 | lop += 2 * cpu->GetInstructionSize(); | ||
| 1734 | |||
| 1735 | RD = lop & rop; | ||
| 1736 | |||
| 1737 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 1738 | if (CurrentModeHasSPSR) { | ||
| 1739 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 1740 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); | ||
| 1741 | LOAD_NZCVT; | ||
| 1742 | } | ||
| 1743 | } else if (inst_cream->S) { | ||
| 1744 | UPDATE_NFLAG(RD); | ||
| 1745 | UPDATE_ZFLAG(RD); | ||
| 1746 | UPDATE_CFLAG_WITH_SC; | ||
| 1747 | } | ||
| 1748 | if (inst_cream->Rd == 15) { | ||
| 1749 | INC_PC(sizeof(and_inst)); | ||
| 1750 | goto DISPATCH; | ||
| 1751 | } | ||
| 1752 | } | ||
| 1753 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1754 | INC_PC(sizeof(and_inst)); | ||
| 1755 | FETCH_INST; | ||
| 1756 | GOTO_NEXT_INST; | ||
| 1757 | } | ||
| 1758 | BBL_INST : { | ||
| 1759 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1760 | bbl_inst* inst_cream = (bbl_inst*)inst_base->component; | ||
| 1761 | if (inst_cream->L) { | ||
| 1762 | LINK_RTN_ADDR; | ||
| 1763 | } | ||
| 1764 | SET_PC; | ||
| 1765 | INC_PC(sizeof(bbl_inst)); | ||
| 1766 | goto DISPATCH; | ||
| 1767 | } | ||
| 1768 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1769 | INC_PC(sizeof(bbl_inst)); | ||
| 1770 | goto DISPATCH; | ||
| 1771 | } | ||
| 1772 | BIC_INST : { | ||
| 1773 | bic_inst* inst_cream = (bic_inst*)inst_base->component; | ||
| 1774 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1775 | u32 lop = RN; | ||
| 1776 | if (inst_cream->Rn == 15) { | ||
| 1777 | lop += 2 * cpu->GetInstructionSize(); | ||
| 1778 | } | ||
| 1779 | u32 rop = SHIFTER_OPERAND; | ||
| 1780 | RD = lop & (~rop); | ||
| 1781 | if ((inst_cream->S) && (inst_cream->Rd == 15)) { | ||
| 1782 | if (CurrentModeHasSPSR) { | ||
| 1783 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 1784 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 1785 | LOAD_NZCVT; | ||
| 1786 | } | ||
| 1787 | } else if (inst_cream->S) { | ||
| 1788 | UPDATE_NFLAG(RD); | ||
| 1789 | UPDATE_ZFLAG(RD); | ||
| 1790 | UPDATE_CFLAG_WITH_SC; | ||
| 1791 | } | ||
| 1792 | if (inst_cream->Rd == 15) { | ||
| 1793 | INC_PC(sizeof(bic_inst)); | ||
| 1794 | goto DISPATCH; | ||
| 1795 | } | ||
| 1796 | } | ||
| 1797 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1798 | INC_PC(sizeof(bic_inst)); | ||
| 1799 | FETCH_INST; | ||
| 1800 | GOTO_NEXT_INST; | ||
| 1801 | } | ||
| 1802 | BKPT_INST : { | ||
| 1803 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1804 | bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; | ||
| 1805 | LOG_DEBUG(Core_ARM, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm); | ||
| 1806 | } | ||
| 1807 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1808 | INC_PC(sizeof(bkpt_inst)); | ||
| 1809 | FETCH_INST; | ||
| 1810 | GOTO_NEXT_INST; | ||
| 1811 | } | ||
| 1812 | BLX_INST : { | ||
| 1813 | blx_inst* inst_cream = (blx_inst*)inst_base->component; | ||
| 1814 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1815 | unsigned int inst = inst_cream->inst; | ||
| 1816 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { | ||
| 1817 | const u32 jump_address = cpu->Reg[inst_cream->val.Rm]; | ||
| 1818 | cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize()); | ||
| 1819 | if (cpu->TFlag) | ||
| 1820 | cpu->Reg[14] |= 0x1; | ||
| 1821 | cpu->Reg[15] = jump_address & 0xfffffffe; | ||
| 1822 | cpu->TFlag = jump_address & 0x1; | ||
| 1823 | } else { | ||
| 1824 | cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize()); | ||
| 1825 | cpu->TFlag = 0x1; | ||
| 1826 | int signed_int = inst_cream->val.signed_immed_24; | ||
| 1827 | signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int; | ||
| 1828 | signed_int = signed_int << 2; | ||
| 1829 | cpu->Reg[15] = cpu->Reg[15] + 8 + signed_int + (BIT(inst, 24) << 1); | ||
| 1830 | } | ||
| 1831 | INC_PC(sizeof(blx_inst)); | ||
| 1832 | goto DISPATCH; | ||
| 1833 | } | ||
| 1834 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1835 | INC_PC(sizeof(blx_inst)); | ||
| 1836 | goto DISPATCH; | ||
| 1837 | } | ||
| 1838 | |||
| 1839 | BX_INST: | ||
| 1840 | BXJ_INST : { | ||
| 1841 | // Note that only the 'fail' case of BXJ is emulated. This is because | ||
| 1842 | // the facilities for Jazelle emulation are not implemented. | ||
| 1843 | // | ||
| 1844 | // According to the ARM documentation on BXJ, if setting the J bit in the APSR | ||
| 1845 | // fails, then BXJ functions identically like a regular BX instruction. | ||
| 1846 | // | ||
| 1847 | // This is sufficient for citra, as the CPU for the 3DS does not implement Jazelle. | ||
| 1848 | |||
| 1849 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1850 | bx_inst* const inst_cream = (bx_inst*)inst_base->component; | ||
| 1851 | |||
| 1852 | u32 address = RM; | ||
| 1853 | |||
| 1854 | if (inst_cream->Rm == 15) | ||
| 1855 | address += 2 * cpu->GetInstructionSize(); | ||
| 1856 | |||
| 1857 | cpu->TFlag = address & 1; | ||
| 1858 | cpu->Reg[15] = address & 0xfffffffe; | ||
| 1859 | INC_PC(sizeof(bx_inst)); | ||
| 1860 | goto DISPATCH; | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1864 | INC_PC(sizeof(bx_inst)); | ||
| 1865 | goto DISPATCH; | ||
| 1866 | } | ||
| 1867 | |||
| 1868 | CDP_INST : { | ||
| 1869 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1870 | // Undefined instruction here | ||
| 1871 | cpu->NumInstrsToExecute = 0; | ||
| 1872 | return num_instrs; | ||
| 1873 | } | ||
| 1874 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1875 | INC_PC(sizeof(cdp_inst)); | ||
| 1876 | FETCH_INST; | ||
| 1877 | GOTO_NEXT_INST; | ||
| 1878 | } | ||
| 1879 | |||
| 1880 | CLREX_INST : { | ||
| 1881 | cpu->UnsetExclusiveMemoryAddress(); | ||
| 1882 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1883 | INC_PC(sizeof(clrex_inst)); | ||
| 1884 | FETCH_INST; | ||
| 1885 | GOTO_NEXT_INST; | ||
| 1886 | } | ||
| 1887 | CLZ_INST : { | ||
| 1888 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1889 | clz_inst* inst_cream = (clz_inst*)inst_base->component; | ||
| 1890 | RD = clz(RM); | ||
| 1891 | } | ||
| 1892 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1893 | INC_PC(sizeof(clz_inst)); | ||
| 1894 | FETCH_INST; | ||
| 1895 | GOTO_NEXT_INST; | ||
| 1896 | } | ||
| 1897 | CMN_INST : { | ||
| 1898 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1899 | cmn_inst* const inst_cream = (cmn_inst*)inst_base->component; | ||
| 1900 | |||
| 1901 | u32 rn_val = RN; | ||
| 1902 | if (inst_cream->Rn == 15) | ||
| 1903 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 1904 | |||
| 1905 | bool carry; | ||
| 1906 | bool overflow; | ||
| 1907 | u32 result = AddWithCarry(rn_val, SHIFTER_OPERAND, 0, &carry, &overflow); | ||
| 1908 | |||
| 1909 | UPDATE_NFLAG(result); | ||
| 1910 | UPDATE_ZFLAG(result); | ||
| 1911 | cpu->CFlag = carry; | ||
| 1912 | cpu->VFlag = overflow; | ||
| 1913 | } | ||
| 1914 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1915 | INC_PC(sizeof(cmn_inst)); | ||
| 1916 | FETCH_INST; | ||
| 1917 | GOTO_NEXT_INST; | ||
| 1918 | } | ||
| 1919 | CMP_INST : { | ||
| 1920 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1921 | cmp_inst* const inst_cream = (cmp_inst*)inst_base->component; | ||
| 1922 | |||
| 1923 | u32 rn_val = RN; | ||
| 1924 | if (inst_cream->Rn == 15) | ||
| 1925 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 1926 | |||
| 1927 | bool carry; | ||
| 1928 | bool overflow; | ||
| 1929 | u32 result = AddWithCarry(rn_val, ~SHIFTER_OPERAND, 1, &carry, &overflow); | ||
| 1930 | |||
| 1931 | UPDATE_NFLAG(result); | ||
| 1932 | UPDATE_ZFLAG(result); | ||
| 1933 | cpu->CFlag = carry; | ||
| 1934 | cpu->VFlag = overflow; | ||
| 1935 | } | ||
| 1936 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1937 | INC_PC(sizeof(cmp_inst)); | ||
| 1938 | FETCH_INST; | ||
| 1939 | GOTO_NEXT_INST; | ||
| 1940 | } | ||
| 1941 | CPS_INST : { | ||
| 1942 | cps_inst* inst_cream = (cps_inst*)inst_base->component; | ||
| 1943 | u32 aif_val = 0; | ||
| 1944 | u32 aif_mask = 0; | ||
| 1945 | if (cpu->InAPrivilegedMode()) { | ||
| 1946 | if (inst_cream->imod1) { | ||
| 1947 | if (inst_cream->A) { | ||
| 1948 | aif_val |= (inst_cream->imod0 << 8); | ||
| 1949 | aif_mask |= 1 << 8; | ||
| 1950 | } | ||
| 1951 | if (inst_cream->I) { | ||
| 1952 | aif_val |= (inst_cream->imod0 << 7); | ||
| 1953 | aif_mask |= 1 << 7; | ||
| 1954 | } | ||
| 1955 | if (inst_cream->F) { | ||
| 1956 | aif_val |= (inst_cream->imod0 << 6); | ||
| 1957 | aif_mask |= 1 << 6; | ||
| 1958 | } | ||
| 1959 | aif_mask = ~aif_mask; | ||
| 1960 | cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val; | ||
| 1961 | } | ||
| 1962 | if (inst_cream->mmod) { | ||
| 1963 | cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; | ||
| 1964 | cpu->ChangePrivilegeMode(inst_cream->mode); | ||
| 1965 | } | ||
| 1966 | } | ||
| 1967 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1968 | INC_PC(sizeof(cps_inst)); | ||
| 1969 | FETCH_INST; | ||
| 1970 | GOTO_NEXT_INST; | ||
| 1971 | } | ||
| 1972 | CPY_INST : { | ||
| 1973 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1974 | mov_inst* inst_cream = (mov_inst*)inst_base->component; | ||
| 1975 | |||
| 1976 | RD = SHIFTER_OPERAND; | ||
| 1977 | if (inst_cream->Rd == 15) { | ||
| 1978 | INC_PC(sizeof(mov_inst)); | ||
| 1979 | goto DISPATCH; | ||
| 1980 | } | ||
| 1981 | } | ||
| 1982 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1983 | INC_PC(sizeof(mov_inst)); | ||
| 1984 | FETCH_INST; | ||
| 1985 | GOTO_NEXT_INST; | ||
| 1986 | } | ||
| 1987 | EOR_INST : { | ||
| 1988 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1989 | eor_inst* inst_cream = (eor_inst*)inst_base->component; | ||
| 1990 | |||
| 1991 | u32 lop = RN; | ||
| 1992 | if (inst_cream->Rn == 15) { | ||
| 1993 | lop += 2 * cpu->GetInstructionSize(); | ||
| 1994 | } | ||
| 1995 | u32 rop = SHIFTER_OPERAND; | ||
| 1996 | RD = lop ^ rop; | ||
| 1997 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 1998 | if (CurrentModeHasSPSR) { | ||
| 1999 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2000 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2001 | LOAD_NZCVT; | ||
| 2002 | } | ||
| 2003 | } else if (inst_cream->S) { | ||
| 2004 | UPDATE_NFLAG(RD); | ||
| 2005 | UPDATE_ZFLAG(RD); | ||
| 2006 | UPDATE_CFLAG_WITH_SC; | ||
| 2007 | } | ||
| 2008 | if (inst_cream->Rd == 15) { | ||
| 2009 | INC_PC(sizeof(eor_inst)); | ||
| 2010 | goto DISPATCH; | ||
| 2011 | } | ||
| 2012 | } | ||
| 2013 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2014 | INC_PC(sizeof(eor_inst)); | ||
| 2015 | FETCH_INST; | ||
| 2016 | GOTO_NEXT_INST; | ||
| 2017 | } | ||
| 2018 | LDC_INST : { | ||
| 2019 | // Instruction not implemented | ||
| 2020 | // LOG_CRITICAL(Core_ARM, "unimplemented instruction"); | ||
| 2021 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2022 | INC_PC(sizeof(ldc_inst)); | ||
| 2023 | FETCH_INST; | ||
| 2024 | GOTO_NEXT_INST; | ||
| 2025 | } | ||
| 2026 | LDM_INST : { | ||
| 2027 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2028 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2029 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2030 | |||
| 2031 | unsigned int inst = inst_cream->inst; | ||
| 2032 | if (BIT(inst, 22) && !BIT(inst, 15)) { | ||
| 2033 | for (int i = 0; i < 13; i++) { | ||
| 2034 | if (BIT(inst, i)) { | ||
| 2035 | cpu->Reg[i] = cpu->ReadMemory32(addr); | ||
| 2036 | addr += 4; | ||
| 2037 | } | ||
| 2038 | } | ||
| 2039 | if (BIT(inst, 13)) { | ||
| 2040 | if (cpu->Mode == USER32MODE) | ||
| 2041 | cpu->Reg[13] = cpu->ReadMemory32(addr); | ||
| 2042 | else | ||
| 2043 | cpu->Reg_usr[0] = cpu->ReadMemory32(addr); | ||
| 2044 | |||
| 2045 | addr += 4; | ||
| 2046 | } | ||
| 2047 | if (BIT(inst, 14)) { | ||
| 2048 | if (cpu->Mode == USER32MODE) | ||
| 2049 | cpu->Reg[14] = cpu->ReadMemory32(addr); | ||
| 2050 | else | ||
| 2051 | cpu->Reg_usr[1] = cpu->ReadMemory32(addr); | ||
| 2052 | |||
| 2053 | addr += 4; | ||
| 2054 | } | ||
| 2055 | } else if (!BIT(inst, 22)) { | ||
| 2056 | for (int i = 0; i < 16; i++) { | ||
| 2057 | if (BIT(inst, i)) { | ||
| 2058 | unsigned int ret = cpu->ReadMemory32(addr); | ||
| 2059 | |||
| 2060 | // For armv5t, should enter thumb when bits[0] is non-zero. | ||
| 2061 | if (i == 15) { | ||
| 2062 | cpu->TFlag = ret & 0x1; | ||
| 2063 | ret &= 0xFFFFFFFE; | ||
| 2064 | } | ||
| 2065 | |||
| 2066 | cpu->Reg[i] = ret; | ||
| 2067 | addr += 4; | ||
| 2068 | } | ||
| 2069 | } | ||
| 2070 | } else if (BIT(inst, 22) && BIT(inst, 15)) { | ||
| 2071 | for (int i = 0; i < 15; i++) { | ||
| 2072 | if (BIT(inst, i)) { | ||
| 2073 | cpu->Reg[i] = cpu->ReadMemory32(addr); | ||
| 2074 | addr += 4; | ||
| 2075 | } | ||
| 2076 | } | ||
| 2077 | |||
| 2078 | if (CurrentModeHasSPSR) { | ||
| 2079 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2080 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); | ||
| 2081 | LOAD_NZCVT; | ||
| 2082 | } | ||
| 2083 | |||
| 2084 | cpu->Reg[15] = cpu->ReadMemory32(addr); | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | if (BIT(inst, 15)) { | ||
| 2088 | INC_PC(sizeof(ldst_inst)); | ||
| 2089 | goto DISPATCH; | ||
| 2090 | } | ||
| 2091 | } | ||
| 2092 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2093 | INC_PC(sizeof(ldst_inst)); | ||
| 2094 | FETCH_INST; | ||
| 2095 | GOTO_NEXT_INST; | ||
| 2096 | } | ||
| 2097 | SXTH_INST : { | ||
| 2098 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2099 | sxth_inst* inst_cream = (sxth_inst*)inst_base->component; | ||
| 2100 | |||
| 2101 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); | ||
| 2102 | if (BIT(operand2, 15)) { | ||
| 2103 | operand2 |= 0xffff0000; | ||
| 2104 | } else { | ||
| 2105 | operand2 &= 0xffff; | ||
| 2106 | } | ||
| 2107 | RD = operand2; | ||
| 2108 | } | ||
| 2109 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2110 | INC_PC(sizeof(sxth_inst)); | ||
| 2111 | FETCH_INST; | ||
| 2112 | GOTO_NEXT_INST; | ||
| 2113 | } | ||
| 2114 | LDR_INST : { | ||
| 2115 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2116 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2117 | |||
| 2118 | unsigned int value = cpu->ReadMemory32(addr); | ||
| 2119 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 2120 | |||
| 2121 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 2122 | // For armv5t, should enter thumb when bits[0] is non-zero. | ||
| 2123 | cpu->TFlag = value & 0x1; | ||
| 2124 | cpu->Reg[15] &= 0xFFFFFFFE; | ||
| 2125 | INC_PC(sizeof(ldst_inst)); | ||
| 2126 | goto DISPATCH; | ||
| 2127 | } | ||
| 2128 | |||
| 2129 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2130 | INC_PC(sizeof(ldst_inst)); | ||
| 2131 | FETCH_INST; | ||
| 2132 | GOTO_NEXT_INST; | ||
| 2133 | } | ||
| 2134 | LDRCOND_INST : { | ||
| 2135 | if (CondPassed(cpu, inst_base->cond)) { | ||
| 2136 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2137 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2138 | |||
| 2139 | unsigned int value = cpu->ReadMemory32(addr); | ||
| 2140 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 2141 | |||
| 2142 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 2143 | // For armv5t, should enter thumb when bits[0] is non-zero. | ||
| 2144 | cpu->TFlag = value & 0x1; | ||
| 2145 | cpu->Reg[15] &= 0xFFFFFFFE; | ||
| 2146 | INC_PC(sizeof(ldst_inst)); | ||
| 2147 | goto DISPATCH; | ||
| 2148 | } | ||
| 2149 | } | ||
| 2150 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2151 | INC_PC(sizeof(ldst_inst)); | ||
| 2152 | FETCH_INST; | ||
| 2153 | GOTO_NEXT_INST; | ||
| 2154 | } | ||
| 2155 | UXTH_INST : { | ||
| 2156 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2157 | uxth_inst* inst_cream = (uxth_inst*)inst_base->component; | ||
| 2158 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; | ||
| 2159 | } | ||
| 2160 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2161 | INC_PC(sizeof(uxth_inst)); | ||
| 2162 | FETCH_INST; | ||
| 2163 | GOTO_NEXT_INST; | ||
| 2164 | } | ||
| 2165 | UXTAH_INST : { | ||
| 2166 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2167 | uxtah_inst* inst_cream = (uxtah_inst*)inst_base->component; | ||
| 2168 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; | ||
| 2169 | |||
| 2170 | RD = RN + operand2; | ||
| 2171 | } | ||
| 2172 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2173 | INC_PC(sizeof(uxtah_inst)); | ||
| 2174 | FETCH_INST; | ||
| 2175 | GOTO_NEXT_INST; | ||
| 2176 | } | ||
| 2177 | LDRB_INST : { | ||
| 2178 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2179 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2180 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2181 | |||
| 2182 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory8(addr); | ||
| 2183 | } | ||
| 2184 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2185 | INC_PC(sizeof(ldst_inst)); | ||
| 2186 | FETCH_INST; | ||
| 2187 | GOTO_NEXT_INST; | ||
| 2188 | } | ||
| 2189 | LDRBT_INST : { | ||
| 2190 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2191 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2192 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2193 | |||
| 2194 | const u32 dest_index = BITS(inst_cream->inst, 12, 15); | ||
| 2195 | const u32 previous_mode = cpu->Mode; | ||
| 2196 | |||
| 2197 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 2198 | const u8 value = cpu->ReadMemory8(addr); | ||
| 2199 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 2200 | |||
| 2201 | cpu->Reg[dest_index] = value; | ||
| 2202 | } | ||
| 2203 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2204 | INC_PC(sizeof(ldst_inst)); | ||
| 2205 | FETCH_INST; | ||
| 2206 | GOTO_NEXT_INST; | ||
| 2207 | } | ||
| 2208 | LDRD_INST : { | ||
| 2209 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2210 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2211 | // Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || | ||
| 2212 | // addr[2] == 0) | ||
| 2213 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2214 | |||
| 2215 | // The 3DS doesn't have LPAE (Large Physical Access Extension), so it | ||
| 2216 | // wouldn't do this as a single read. | ||
| 2217 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = cpu->ReadMemory32(addr); | ||
| 2218 | cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = cpu->ReadMemory32(addr + 4); | ||
| 2219 | |||
| 2220 | // No dispatch since this operation should not modify R15 | ||
| 2221 | } | ||
| 2222 | cpu->Reg[15] += 4; | ||
| 2223 | INC_PC(sizeof(ldst_inst)); | ||
| 2224 | FETCH_INST; | ||
| 2225 | GOTO_NEXT_INST; | ||
| 2226 | } | ||
| 2227 | |||
| 2228 | LDREX_INST : { | ||
| 2229 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2230 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2231 | unsigned int read_addr = RN; | ||
| 2232 | |||
| 2233 | cpu->SetExclusiveMemoryAddress(read_addr); | ||
| 2234 | |||
| 2235 | RD = cpu->ReadMemory32(read_addr); | ||
| 2236 | } | ||
| 2237 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2238 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2239 | FETCH_INST; | ||
| 2240 | GOTO_NEXT_INST; | ||
| 2241 | } | ||
| 2242 | LDREXB_INST : { | ||
| 2243 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2244 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2245 | unsigned int read_addr = RN; | ||
| 2246 | |||
| 2247 | cpu->SetExclusiveMemoryAddress(read_addr); | ||
| 2248 | |||
| 2249 | RD = cpu->ReadMemory8(read_addr); | ||
| 2250 | } | ||
| 2251 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2252 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2253 | FETCH_INST; | ||
| 2254 | GOTO_NEXT_INST; | ||
| 2255 | } | ||
| 2256 | LDREXH_INST : { | ||
| 2257 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2258 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2259 | unsigned int read_addr = RN; | ||
| 2260 | |||
| 2261 | cpu->SetExclusiveMemoryAddress(read_addr); | ||
| 2262 | |||
| 2263 | RD = cpu->ReadMemory16(read_addr); | ||
| 2264 | } | ||
| 2265 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2266 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2267 | FETCH_INST; | ||
| 2268 | GOTO_NEXT_INST; | ||
| 2269 | } | ||
| 2270 | LDREXD_INST : { | ||
| 2271 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2272 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2273 | unsigned int read_addr = RN; | ||
| 2274 | |||
| 2275 | cpu->SetExclusiveMemoryAddress(read_addr); | ||
| 2276 | |||
| 2277 | RD = cpu->ReadMemory32(read_addr); | ||
| 2278 | RD2 = cpu->ReadMemory32(read_addr + 4); | ||
| 2279 | } | ||
| 2280 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2281 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2282 | FETCH_INST; | ||
| 2283 | GOTO_NEXT_INST; | ||
| 2284 | } | ||
| 2285 | LDRH_INST : { | ||
| 2286 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2287 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2288 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2289 | |||
| 2290 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr); | ||
| 2291 | } | ||
| 2292 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2293 | INC_PC(sizeof(ldst_inst)); | ||
| 2294 | FETCH_INST; | ||
| 2295 | GOTO_NEXT_INST; | ||
| 2296 | } | ||
| 2297 | LDRSB_INST : { | ||
| 2298 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2299 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2300 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2301 | unsigned int value = cpu->ReadMemory8(addr); | ||
| 2302 | if (BIT(value, 7)) { | ||
| 2303 | value |= 0xffffff00; | ||
| 2304 | } | ||
| 2305 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 2306 | } | ||
| 2307 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2308 | INC_PC(sizeof(ldst_inst)); | ||
| 2309 | FETCH_INST; | ||
| 2310 | GOTO_NEXT_INST; | ||
| 2311 | } | ||
| 2312 | LDRSH_INST : { | ||
| 2313 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2314 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2315 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2316 | |||
| 2317 | unsigned int value = cpu->ReadMemory16(addr); | ||
| 2318 | if (BIT(value, 15)) { | ||
| 2319 | value |= 0xffff0000; | ||
| 2320 | } | ||
| 2321 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | ||
| 2322 | } | ||
| 2323 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2324 | INC_PC(sizeof(ldst_inst)); | ||
| 2325 | FETCH_INST; | ||
| 2326 | GOTO_NEXT_INST; | ||
| 2327 | } | ||
| 2328 | LDRT_INST : { | ||
| 2329 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2330 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 2331 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 2332 | |||
| 2333 | const u32 dest_index = BITS(inst_cream->inst, 12, 15); | ||
| 2334 | const u32 previous_mode = cpu->Mode; | ||
| 2335 | |||
| 2336 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 2337 | const u32 value = cpu->ReadMemory32(addr); | ||
| 2338 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 2339 | |||
| 2340 | cpu->Reg[dest_index] = value; | ||
| 2341 | } | ||
| 2342 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2343 | INC_PC(sizeof(ldst_inst)); | ||
| 2344 | FETCH_INST; | ||
| 2345 | GOTO_NEXT_INST; | ||
| 2346 | } | ||
| 2347 | MCR_INST : { | ||
| 2348 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2349 | mcr_inst* inst_cream = (mcr_inst*)inst_base->component; | ||
| 2350 | |||
| 2351 | unsigned int inst = inst_cream->inst; | ||
| 2352 | if (inst_cream->Rd == 15) { | ||
| 2353 | DEBUG_MSG; | ||
| 2354 | } else { | ||
| 2355 | if (inst_cream->cp_num == 15) | ||
| 2356 | cpu->WriteCP15Register(RD, CRn, OPCODE_1, CRm, OPCODE_2); | ||
| 2357 | } | ||
| 2358 | } | ||
| 2359 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2360 | INC_PC(sizeof(mcr_inst)); | ||
| 2361 | FETCH_INST; | ||
| 2362 | GOTO_NEXT_INST; | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | MCRR_INST : { | ||
| 2366 | // Stubbed, as the MPCore doesn't have any registers that are accessible | ||
| 2367 | // through this instruction. | ||
| 2368 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2369 | mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component; | ||
| 2370 | |||
| 2371 | LOG_ERROR(Core_ARM, "MCRR executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u", | ||
| 2372 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, | ||
| 2373 | inst_cream->rt2); | ||
| 2374 | } | ||
| 2375 | |||
| 2376 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2377 | INC_PC(sizeof(mcrr_inst)); | ||
| 2378 | FETCH_INST; | ||
| 2379 | GOTO_NEXT_INST; | ||
| 2380 | } | ||
| 2381 | |||
| 2382 | MLA_INST : { | ||
| 2383 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2384 | mla_inst* inst_cream = (mla_inst*)inst_base->component; | ||
| 2385 | |||
| 2386 | u64 rm = RM; | ||
| 2387 | u64 rs = RS; | ||
| 2388 | u64 rn = RN; | ||
| 2389 | |||
| 2390 | RD = static_cast<u32>((rm * rs + rn) & 0xffffffff); | ||
| 2391 | if (inst_cream->S) { | ||
| 2392 | UPDATE_NFLAG(RD); | ||
| 2393 | UPDATE_ZFLAG(RD); | ||
| 2394 | } | ||
| 2395 | } | ||
| 2396 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2397 | INC_PC(sizeof(mla_inst)); | ||
| 2398 | FETCH_INST; | ||
| 2399 | GOTO_NEXT_INST; | ||
| 2400 | } | ||
| 2401 | MOV_INST : { | ||
| 2402 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2403 | mov_inst* inst_cream = (mov_inst*)inst_base->component; | ||
| 2404 | |||
| 2405 | RD = SHIFTER_OPERAND; | ||
| 2406 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 2407 | if (CurrentModeHasSPSR) { | ||
| 2408 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2409 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2410 | LOAD_NZCVT; | ||
| 2411 | } | ||
| 2412 | } else if (inst_cream->S) { | ||
| 2413 | UPDATE_NFLAG(RD); | ||
| 2414 | UPDATE_ZFLAG(RD); | ||
| 2415 | UPDATE_CFLAG_WITH_SC; | ||
| 2416 | } | ||
| 2417 | if (inst_cream->Rd == 15) { | ||
| 2418 | INC_PC(sizeof(mov_inst)); | ||
| 2419 | goto DISPATCH; | ||
| 2420 | } | ||
| 2421 | } | ||
| 2422 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2423 | INC_PC(sizeof(mov_inst)); | ||
| 2424 | FETCH_INST; | ||
| 2425 | GOTO_NEXT_INST; | ||
| 2426 | } | ||
| 2427 | MRC_INST : { | ||
| 2428 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2429 | mrc_inst* inst_cream = (mrc_inst*)inst_base->component; | ||
| 2430 | |||
| 2431 | if (inst_cream->cp_num == 15) { | ||
| 2432 | const uint32_t value = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2); | ||
| 2433 | |||
| 2434 | if (inst_cream->Rd == 15) { | ||
| 2435 | cpu->Cpsr = (cpu->Cpsr & ~0xF0000000) | (value & 0xF0000000); | ||
| 2436 | LOAD_NZCVT; | ||
| 2437 | } else { | ||
| 2438 | RD = value; | ||
| 2439 | } | ||
| 2440 | } | ||
| 2441 | } | ||
| 2442 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2443 | INC_PC(sizeof(mrc_inst)); | ||
| 2444 | FETCH_INST; | ||
| 2445 | GOTO_NEXT_INST; | ||
| 2446 | } | ||
| 2447 | |||
| 2448 | MRRC_INST : { | ||
| 2449 | // Stubbed, as the MPCore doesn't have any registers that are accessible | ||
| 2450 | // through this instruction. | ||
| 2451 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2452 | mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component; | ||
| 2453 | |||
| 2454 | LOG_ERROR(Core_ARM, "MRRC executed | Coprocessor: %u, CRm %u, opc1: %u, Rt: %u, Rt2: %u", | ||
| 2455 | inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, | ||
| 2456 | inst_cream->rt2); | ||
| 2457 | } | ||
| 2458 | |||
| 2459 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2460 | INC_PC(sizeof(mcrr_inst)); | ||
| 2461 | FETCH_INST; | ||
| 2462 | GOTO_NEXT_INST; | ||
| 2463 | } | ||
| 2464 | |||
| 2465 | MRS_INST : { | ||
| 2466 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2467 | mrs_inst* inst_cream = (mrs_inst*)inst_base->component; | ||
| 2468 | |||
| 2469 | if (inst_cream->R) { | ||
| 2470 | RD = cpu->Spsr_copy; | ||
| 2471 | } else { | ||
| 2472 | SAVE_NZCVT; | ||
| 2473 | RD = cpu->Cpsr; | ||
| 2474 | } | ||
| 2475 | } | ||
| 2476 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2477 | INC_PC(sizeof(mrs_inst)); | ||
| 2478 | FETCH_INST; | ||
| 2479 | GOTO_NEXT_INST; | ||
| 2480 | } | ||
| 2481 | MSR_INST : { | ||
| 2482 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2483 | msr_inst* inst_cream = (msr_inst*)inst_base->component; | ||
| 2484 | const u32 UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020; | ||
| 2485 | unsigned int inst = inst_cream->inst; | ||
| 2486 | unsigned int operand; | ||
| 2487 | |||
| 2488 | if (BIT(inst, 25)) { | ||
| 2489 | int rot_imm = BITS(inst, 8, 11) * 2; | ||
| 2490 | operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm); | ||
| 2491 | } else { | ||
| 2492 | operand = cpu->Reg[BITS(inst, 0, 3)]; | ||
| 2493 | } | ||
| 2494 | u32 byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) | | ||
| 2495 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); | ||
| 2496 | u32 mask = 0; | ||
| 2497 | if (!inst_cream->R) { | ||
| 2498 | if (cpu->InAPrivilegedMode()) { | ||
| 2499 | if ((operand & StateMask) != 0) { | ||
| 2500 | /// UNPREDICTABLE | ||
| 2501 | DEBUG_MSG; | ||
| 2502 | } else | ||
| 2503 | mask = byte_mask & (UserMask | PrivMask); | ||
| 2504 | } else { | ||
| 2505 | mask = byte_mask & UserMask; | ||
| 2506 | } | ||
| 2507 | SAVE_NZCVT; | ||
| 2508 | |||
| 2509 | cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); | ||
| 2510 | cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F); | ||
| 2511 | LOAD_NZCVT; | ||
| 2512 | } else { | ||
| 2513 | if (CurrentModeHasSPSR) { | ||
| 2514 | mask = byte_mask & (UserMask | PrivMask | StateMask); | ||
| 2515 | cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask); | ||
| 2516 | } | ||
| 2517 | } | ||
| 2518 | } | ||
| 2519 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2520 | INC_PC(sizeof(msr_inst)); | ||
| 2521 | FETCH_INST; | ||
| 2522 | GOTO_NEXT_INST; | ||
| 2523 | } | ||
| 2524 | MUL_INST : { | ||
| 2525 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2526 | mul_inst* inst_cream = (mul_inst*)inst_base->component; | ||
| 2527 | |||
| 2528 | u64 rm = RM; | ||
| 2529 | u64 rs = RS; | ||
| 2530 | RD = static_cast<u32>((rm * rs) & 0xffffffff); | ||
| 2531 | if (inst_cream->S) { | ||
| 2532 | UPDATE_NFLAG(RD); | ||
| 2533 | UPDATE_ZFLAG(RD); | ||
| 2534 | } | ||
| 2535 | } | ||
| 2536 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2537 | INC_PC(sizeof(mul_inst)); | ||
| 2538 | FETCH_INST; | ||
| 2539 | GOTO_NEXT_INST; | ||
| 2540 | } | ||
| 2541 | MVN_INST : { | ||
| 2542 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2543 | mvn_inst* const inst_cream = (mvn_inst*)inst_base->component; | ||
| 2544 | |||
| 2545 | RD = ~SHIFTER_OPERAND; | ||
| 2546 | |||
| 2547 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 2548 | if (CurrentModeHasSPSR) { | ||
| 2549 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2550 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2551 | LOAD_NZCVT; | ||
| 2552 | } | ||
| 2553 | } else if (inst_cream->S) { | ||
| 2554 | UPDATE_NFLAG(RD); | ||
| 2555 | UPDATE_ZFLAG(RD); | ||
| 2556 | UPDATE_CFLAG_WITH_SC; | ||
| 2557 | } | ||
| 2558 | if (inst_cream->Rd == 15) { | ||
| 2559 | INC_PC(sizeof(mvn_inst)); | ||
| 2560 | goto DISPATCH; | ||
| 2561 | } | ||
| 2562 | } | ||
| 2563 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2564 | INC_PC(sizeof(mvn_inst)); | ||
| 2565 | FETCH_INST; | ||
| 2566 | GOTO_NEXT_INST; | ||
| 2567 | } | ||
| 2568 | ORR_INST : { | ||
| 2569 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2570 | orr_inst* const inst_cream = (orr_inst*)inst_base->component; | ||
| 2571 | |||
| 2572 | u32 lop = RN; | ||
| 2573 | u32 rop = SHIFTER_OPERAND; | ||
| 2574 | |||
| 2575 | if (inst_cream->Rn == 15) | ||
| 2576 | lop += 2 * cpu->GetInstructionSize(); | ||
| 2577 | |||
| 2578 | RD = lop | rop; | ||
| 2579 | |||
| 2580 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 2581 | if (CurrentModeHasSPSR) { | ||
| 2582 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2583 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2584 | LOAD_NZCVT; | ||
| 2585 | } | ||
| 2586 | } else if (inst_cream->S) { | ||
| 2587 | UPDATE_NFLAG(RD); | ||
| 2588 | UPDATE_ZFLAG(RD); | ||
| 2589 | UPDATE_CFLAG_WITH_SC; | ||
| 2590 | } | ||
| 2591 | if (inst_cream->Rd == 15) { | ||
| 2592 | INC_PC(sizeof(orr_inst)); | ||
| 2593 | goto DISPATCH; | ||
| 2594 | } | ||
| 2595 | } | ||
| 2596 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2597 | INC_PC(sizeof(orr_inst)); | ||
| 2598 | FETCH_INST; | ||
| 2599 | GOTO_NEXT_INST; | ||
| 2600 | } | ||
| 2601 | |||
| 2602 | NOP_INST : { | ||
| 2603 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2604 | INC_PC_STUB; | ||
| 2605 | FETCH_INST; | ||
| 2606 | GOTO_NEXT_INST; | ||
| 2607 | } | ||
| 2608 | |||
| 2609 | PKHBT_INST : { | ||
| 2610 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2611 | pkh_inst* inst_cream = (pkh_inst*)inst_base->component; | ||
| 2612 | RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000); | ||
| 2613 | } | ||
| 2614 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2615 | INC_PC(sizeof(pkh_inst)); | ||
| 2616 | FETCH_INST; | ||
| 2617 | GOTO_NEXT_INST; | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | PKHTB_INST : { | ||
| 2621 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2622 | pkh_inst* inst_cream = (pkh_inst*)inst_base->component; | ||
| 2623 | int shift_imm = inst_cream->imm ? inst_cream->imm : 31; | ||
| 2624 | RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000); | ||
| 2625 | } | ||
| 2626 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2627 | INC_PC(sizeof(pkh_inst)); | ||
| 2628 | FETCH_INST; | ||
| 2629 | GOTO_NEXT_INST; | ||
| 2630 | } | ||
| 2631 | |||
| 2632 | PLD_INST : { | ||
| 2633 | // Not implemented. PLD is a hint instruction, so it's optional. | ||
| 2634 | |||
| 2635 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2636 | INC_PC(sizeof(pld_inst)); | ||
| 2637 | FETCH_INST; | ||
| 2638 | GOTO_NEXT_INST; | ||
| 2639 | } | ||
| 2640 | |||
| 2641 | QADD_INST: | ||
| 2642 | QDADD_INST: | ||
| 2643 | QDSUB_INST: | ||
| 2644 | QSUB_INST : { | ||
| 2645 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2646 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2647 | const u8 op1 = inst_cream->op1; | ||
| 2648 | const u32 rm_val = RM; | ||
| 2649 | const u32 rn_val = RN; | ||
| 2650 | |||
| 2651 | u32 result = 0; | ||
| 2652 | |||
| 2653 | // QADD | ||
| 2654 | if (op1 == 0x00) { | ||
| 2655 | result = rm_val + rn_val; | ||
| 2656 | |||
| 2657 | if (AddOverflow(rm_val, rn_val, result)) { | ||
| 2658 | result = POS(result) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2659 | cpu->Cpsr |= (1 << 27); | ||
| 2660 | } | ||
| 2661 | } | ||
| 2662 | // QSUB | ||
| 2663 | else if (op1 == 0x01) { | ||
| 2664 | result = rm_val - rn_val; | ||
| 2665 | |||
| 2666 | if (SubOverflow(rm_val, rn_val, result)) { | ||
| 2667 | result = POS(result) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2668 | cpu->Cpsr |= (1 << 27); | ||
| 2669 | } | ||
| 2670 | } | ||
| 2671 | // QDADD | ||
| 2672 | else if (op1 == 0x02) { | ||
| 2673 | u32 mul = (rn_val * 2); | ||
| 2674 | |||
| 2675 | if (AddOverflow(rn_val, rn_val, rn_val * 2)) { | ||
| 2676 | mul = POS(mul) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2677 | cpu->Cpsr |= (1 << 27); | ||
| 2678 | } | ||
| 2679 | |||
| 2680 | result = mul + rm_val; | ||
| 2681 | |||
| 2682 | if (AddOverflow(rm_val, mul, result)) { | ||
| 2683 | result = POS(result) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2684 | cpu->Cpsr |= (1 << 27); | ||
| 2685 | } | ||
| 2686 | } | ||
| 2687 | // QDSUB | ||
| 2688 | else if (op1 == 0x03) { | ||
| 2689 | u32 mul = (rn_val * 2); | ||
| 2690 | |||
| 2691 | if (AddOverflow(rn_val, rn_val, mul)) { | ||
| 2692 | mul = POS(mul) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2693 | cpu->Cpsr |= (1 << 27); | ||
| 2694 | } | ||
| 2695 | |||
| 2696 | result = rm_val - mul; | ||
| 2697 | |||
| 2698 | if (SubOverflow(rm_val, mul, result)) { | ||
| 2699 | result = POS(result) ? 0x80000000 : 0x7FFFFFFF; | ||
| 2700 | cpu->Cpsr |= (1 << 27); | ||
| 2701 | } | ||
| 2702 | } | ||
| 2703 | |||
| 2704 | RD = result; | ||
| 2705 | } | ||
| 2706 | |||
| 2707 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2708 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2709 | FETCH_INST; | ||
| 2710 | GOTO_NEXT_INST; | ||
| 2711 | } | ||
| 2712 | |||
| 2713 | QADD8_INST: | ||
| 2714 | QADD16_INST: | ||
| 2715 | QADDSUBX_INST: | ||
| 2716 | QSUB8_INST: | ||
| 2717 | QSUB16_INST: | ||
| 2718 | QSUBADDX_INST : { | ||
| 2719 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2720 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2721 | const u16 rm_lo = (RM & 0xFFFF); | ||
| 2722 | const u16 rm_hi = ((RM >> 16) & 0xFFFF); | ||
| 2723 | const u16 rn_lo = (RN & 0xFFFF); | ||
| 2724 | const u16 rn_hi = ((RN >> 16) & 0xFFFF); | ||
| 2725 | const u8 op2 = inst_cream->op2; | ||
| 2726 | |||
| 2727 | u16 lo_result = 0; | ||
| 2728 | u16 hi_result = 0; | ||
| 2729 | |||
| 2730 | // QADD16 | ||
| 2731 | if (op2 == 0x00) { | ||
| 2732 | lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo); | ||
| 2733 | hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi); | ||
| 2734 | } | ||
| 2735 | // QASX | ||
| 2736 | else if (op2 == 0x01) { | ||
| 2737 | lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi); | ||
| 2738 | hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo); | ||
| 2739 | } | ||
| 2740 | // QSAX | ||
| 2741 | else if (op2 == 0x02) { | ||
| 2742 | lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi); | ||
| 2743 | hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo); | ||
| 2744 | } | ||
| 2745 | // QSUB16 | ||
| 2746 | else if (op2 == 0x03) { | ||
| 2747 | lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo); | ||
| 2748 | hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi); | ||
| 2749 | } | ||
| 2750 | // QADD8 | ||
| 2751 | else if (op2 == 0x04) { | ||
| 2752 | lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) | | ||
| 2753 | ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8; | ||
| 2754 | hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) | | ||
| 2755 | ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8; | ||
| 2756 | } | ||
| 2757 | // QSUB8 | ||
| 2758 | else if (op2 == 0x07) { | ||
| 2759 | lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) | | ||
| 2760 | ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8; | ||
| 2761 | hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) | | ||
| 2762 | ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8; | ||
| 2763 | } | ||
| 2764 | |||
| 2765 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | ||
| 2766 | } | ||
| 2767 | |||
| 2768 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2769 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2770 | FETCH_INST; | ||
| 2771 | GOTO_NEXT_INST; | ||
| 2772 | } | ||
| 2773 | |||
| 2774 | REV_INST: | ||
| 2775 | REV16_INST: | ||
| 2776 | REVSH_INST : { | ||
| 2777 | |||
| 2778 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2779 | rev_inst* const inst_cream = (rev_inst*)inst_base->component; | ||
| 2780 | |||
| 2781 | const u8 op1 = inst_cream->op1; | ||
| 2782 | const u8 op2 = inst_cream->op2; | ||
| 2783 | |||
| 2784 | // REV | ||
| 2785 | if (op1 == 0x03 && op2 == 0x01) { | ||
| 2786 | RD = ((RM & 0xFF) << 24) | (((RM >> 8) & 0xFF) << 16) | (((RM >> 16) & 0xFF) << 8) | | ||
| 2787 | ((RM >> 24) & 0xFF); | ||
| 2788 | } | ||
| 2789 | // REV16 | ||
| 2790 | else if (op1 == 0x03 && op2 == 0x05) { | ||
| 2791 | RD = ((RM & 0xFF) << 8) | ((RM & 0xFF00) >> 8) | ((RM & 0xFF0000) << 8) | | ||
| 2792 | ((RM & 0xFF000000) >> 8); | ||
| 2793 | } | ||
| 2794 | // REVSH | ||
| 2795 | else if (op1 == 0x07 && op2 == 0x05) { | ||
| 2796 | RD = ((RM & 0xFF) << 8) | ((RM & 0xFF00) >> 8); | ||
| 2797 | if (RD & 0x8000) | ||
| 2798 | RD |= 0xffff0000; | ||
| 2799 | } | ||
| 2800 | } | ||
| 2801 | |||
| 2802 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2803 | INC_PC(sizeof(rev_inst)); | ||
| 2804 | FETCH_INST; | ||
| 2805 | GOTO_NEXT_INST; | ||
| 2806 | } | ||
| 2807 | |||
| 2808 | RFE_INST : { | ||
| 2809 | // RFE is unconditional | ||
| 2810 | ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; | ||
| 2811 | |||
| 2812 | u32 address = 0; | ||
| 2813 | inst_cream->get_addr(cpu, inst_cream->inst, address); | ||
| 2814 | |||
| 2815 | cpu->Cpsr = cpu->ReadMemory32(address); | ||
| 2816 | cpu->Reg[15] = cpu->ReadMemory32(address + 4); | ||
| 2817 | |||
| 2818 | INC_PC(sizeof(ldst_inst)); | ||
| 2819 | goto DISPATCH; | ||
| 2820 | } | ||
| 2821 | |||
| 2822 | RSB_INST : { | ||
| 2823 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2824 | rsb_inst* const inst_cream = (rsb_inst*)inst_base->component; | ||
| 2825 | |||
| 2826 | u32 rn_val = RN; | ||
| 2827 | if (inst_cream->Rn == 15) | ||
| 2828 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 2829 | |||
| 2830 | bool carry; | ||
| 2831 | bool overflow; | ||
| 2832 | RD = AddWithCarry(~rn_val, SHIFTER_OPERAND, 1, &carry, &overflow); | ||
| 2833 | |||
| 2834 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 2835 | if (CurrentModeHasSPSR) { | ||
| 2836 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2837 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2838 | LOAD_NZCVT; | ||
| 2839 | } | ||
| 2840 | } else if (inst_cream->S) { | ||
| 2841 | UPDATE_NFLAG(RD); | ||
| 2842 | UPDATE_ZFLAG(RD); | ||
| 2843 | cpu->CFlag = carry; | ||
| 2844 | cpu->VFlag = overflow; | ||
| 2845 | } | ||
| 2846 | if (inst_cream->Rd == 15) { | ||
| 2847 | INC_PC(sizeof(rsb_inst)); | ||
| 2848 | goto DISPATCH; | ||
| 2849 | } | ||
| 2850 | } | ||
| 2851 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2852 | INC_PC(sizeof(rsb_inst)); | ||
| 2853 | FETCH_INST; | ||
| 2854 | GOTO_NEXT_INST; | ||
| 2855 | } | ||
| 2856 | RSC_INST : { | ||
| 2857 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2858 | rsc_inst* const inst_cream = (rsc_inst*)inst_base->component; | ||
| 2859 | |||
| 2860 | u32 rn_val = RN; | ||
| 2861 | if (inst_cream->Rn == 15) | ||
| 2862 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 2863 | |||
| 2864 | bool carry; | ||
| 2865 | bool overflow; | ||
| 2866 | RD = AddWithCarry(~rn_val, SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); | ||
| 2867 | |||
| 2868 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 2869 | if (CurrentModeHasSPSR) { | ||
| 2870 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 2871 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 2872 | LOAD_NZCVT; | ||
| 2873 | } | ||
| 2874 | } else if (inst_cream->S) { | ||
| 2875 | UPDATE_NFLAG(RD); | ||
| 2876 | UPDATE_ZFLAG(RD); | ||
| 2877 | cpu->CFlag = carry; | ||
| 2878 | cpu->VFlag = overflow; | ||
| 2879 | } | ||
| 2880 | if (inst_cream->Rd == 15) { | ||
| 2881 | INC_PC(sizeof(rsc_inst)); | ||
| 2882 | goto DISPATCH; | ||
| 2883 | } | ||
| 2884 | } | ||
| 2885 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2886 | INC_PC(sizeof(rsc_inst)); | ||
| 2887 | FETCH_INST; | ||
| 2888 | GOTO_NEXT_INST; | ||
| 2889 | } | ||
| 2890 | |||
| 2891 | SADD8_INST: | ||
| 2892 | SSUB8_INST: | ||
| 2893 | SADD16_INST: | ||
| 2894 | SADDSUBX_INST: | ||
| 2895 | SSUBADDX_INST: | ||
| 2896 | SSUB16_INST : { | ||
| 2897 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 2898 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 2899 | const u8 op2 = inst_cream->op2; | ||
| 2900 | |||
| 2901 | if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) { | ||
| 2902 | const s16 rn_lo = (RN & 0xFFFF); | ||
| 2903 | const s16 rn_hi = ((RN >> 16) & 0xFFFF); | ||
| 2904 | const s16 rm_lo = (RM & 0xFFFF); | ||
| 2905 | const s16 rm_hi = ((RM >> 16) & 0xFFFF); | ||
| 2906 | |||
| 2907 | s32 lo_result = 0; | ||
| 2908 | s32 hi_result = 0; | ||
| 2909 | |||
| 2910 | // SADD16 | ||
| 2911 | if (inst_cream->op2 == 0x00) { | ||
| 2912 | lo_result = (rn_lo + rm_lo); | ||
| 2913 | hi_result = (rn_hi + rm_hi); | ||
| 2914 | } | ||
| 2915 | // SASX | ||
| 2916 | else if (op2 == 0x01) { | ||
| 2917 | lo_result = (rn_lo - rm_hi); | ||
| 2918 | hi_result = (rn_hi + rm_lo); | ||
| 2919 | } | ||
| 2920 | // SSAX | ||
| 2921 | else if (op2 == 0x02) { | ||
| 2922 | lo_result = (rn_lo + rm_hi); | ||
| 2923 | hi_result = (rn_hi - rm_lo); | ||
| 2924 | } | ||
| 2925 | // SSUB16 | ||
| 2926 | else if (op2 == 0x03) { | ||
| 2927 | lo_result = (rn_lo - rm_lo); | ||
| 2928 | hi_result = (rn_hi - rm_hi); | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | ||
| 2932 | |||
| 2933 | if (lo_result >= 0) { | ||
| 2934 | cpu->Cpsr |= (1 << 16); | ||
| 2935 | cpu->Cpsr |= (1 << 17); | ||
| 2936 | } else { | ||
| 2937 | cpu->Cpsr &= ~(1 << 16); | ||
| 2938 | cpu->Cpsr &= ~(1 << 17); | ||
| 2939 | } | ||
| 2940 | |||
| 2941 | if (hi_result >= 0) { | ||
| 2942 | cpu->Cpsr |= (1 << 18); | ||
| 2943 | cpu->Cpsr |= (1 << 19); | ||
| 2944 | } else { | ||
| 2945 | cpu->Cpsr &= ~(1 << 18); | ||
| 2946 | cpu->Cpsr &= ~(1 << 19); | ||
| 2947 | } | ||
| 2948 | } else if (op2 == 0x04 || op2 == 0x07) { | ||
| 2949 | s32 lo_val1, lo_val2; | ||
| 2950 | s32 hi_val1, hi_val2; | ||
| 2951 | |||
| 2952 | // SADD8 | ||
| 2953 | if (op2 == 0x04) { | ||
| 2954 | lo_val1 = (s32)(s8)(RN & 0xFF) + (s32)(s8)(RM & 0xFF); | ||
| 2955 | lo_val2 = (s32)(s8)((RN >> 8) & 0xFF) + (s32)(s8)((RM >> 8) & 0xFF); | ||
| 2956 | hi_val1 = (s32)(s8)((RN >> 16) & 0xFF) + (s32)(s8)((RM >> 16) & 0xFF); | ||
| 2957 | hi_val2 = (s32)(s8)((RN >> 24) & 0xFF) + (s32)(s8)((RM >> 24) & 0xFF); | ||
| 2958 | } | ||
| 2959 | // SSUB8 | ||
| 2960 | else { | ||
| 2961 | lo_val1 = (s32)(s8)(RN & 0xFF) - (s32)(s8)(RM & 0xFF); | ||
| 2962 | lo_val2 = (s32)(s8)((RN >> 8) & 0xFF) - (s32)(s8)((RM >> 8) & 0xFF); | ||
| 2963 | hi_val1 = (s32)(s8)((RN >> 16) & 0xFF) - (s32)(s8)((RM >> 16) & 0xFF); | ||
| 2964 | hi_val2 = (s32)(s8)((RN >> 24) & 0xFF) - (s32)(s8)((RM >> 24) & 0xFF); | ||
| 2965 | } | ||
| 2966 | |||
| 2967 | RD = ((lo_val1 & 0xFF) | ((lo_val2 & 0xFF) << 8) | ((hi_val1 & 0xFF) << 16) | | ||
| 2968 | ((hi_val2 & 0xFF) << 24)); | ||
| 2969 | |||
| 2970 | if (lo_val1 >= 0) | ||
| 2971 | cpu->Cpsr |= (1 << 16); | ||
| 2972 | else | ||
| 2973 | cpu->Cpsr &= ~(1 << 16); | ||
| 2974 | |||
| 2975 | if (lo_val2 >= 0) | ||
| 2976 | cpu->Cpsr |= (1 << 17); | ||
| 2977 | else | ||
| 2978 | cpu->Cpsr &= ~(1 << 17); | ||
| 2979 | |||
| 2980 | if (hi_val1 >= 0) | ||
| 2981 | cpu->Cpsr |= (1 << 18); | ||
| 2982 | else | ||
| 2983 | cpu->Cpsr &= ~(1 << 18); | ||
| 2984 | |||
| 2985 | if (hi_val2 >= 0) | ||
| 2986 | cpu->Cpsr |= (1 << 19); | ||
| 2987 | else | ||
| 2988 | cpu->Cpsr &= ~(1 << 19); | ||
| 2989 | } | ||
| 2990 | } | ||
| 2991 | |||
| 2992 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 2993 | INC_PC(sizeof(generic_arm_inst)); | ||
| 2994 | FETCH_INST; | ||
| 2995 | GOTO_NEXT_INST; | ||
| 2996 | } | ||
| 2997 | |||
| 2998 | SBC_INST : { | ||
| 2999 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3000 | sbc_inst* const inst_cream = (sbc_inst*)inst_base->component; | ||
| 3001 | |||
| 3002 | u32 rn_val = RN; | ||
| 3003 | if (inst_cream->Rn == 15) | ||
| 3004 | rn_val += 2 * cpu->GetInstructionSize(); | ||
| 3005 | |||
| 3006 | bool carry; | ||
| 3007 | bool overflow; | ||
| 3008 | RD = AddWithCarry(rn_val, ~SHIFTER_OPERAND, cpu->CFlag, &carry, &overflow); | ||
| 3009 | |||
| 3010 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 3011 | if (CurrentModeHasSPSR) { | ||
| 3012 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 3013 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 3014 | LOAD_NZCVT; | ||
| 3015 | } | ||
| 3016 | } else if (inst_cream->S) { | ||
| 3017 | UPDATE_NFLAG(RD); | ||
| 3018 | UPDATE_ZFLAG(RD); | ||
| 3019 | cpu->CFlag = carry; | ||
| 3020 | cpu->VFlag = overflow; | ||
| 3021 | } | ||
| 3022 | if (inst_cream->Rd == 15) { | ||
| 3023 | INC_PC(sizeof(sbc_inst)); | ||
| 3024 | goto DISPATCH; | ||
| 3025 | } | ||
| 3026 | } | ||
| 3027 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3028 | INC_PC(sizeof(sbc_inst)); | ||
| 3029 | FETCH_INST; | ||
| 3030 | GOTO_NEXT_INST; | ||
| 3031 | } | ||
| 3032 | |||
| 3033 | SEL_INST : { | ||
| 3034 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3035 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3036 | |||
| 3037 | const u32 to = RM; | ||
| 3038 | const u32 from = RN; | ||
| 3039 | const u32 cpsr = cpu->Cpsr; | ||
| 3040 | |||
| 3041 | u32 result; | ||
| 3042 | if (cpsr & (1 << 16)) | ||
| 3043 | result = from & 0xff; | ||
| 3044 | else | ||
| 3045 | result = to & 0xff; | ||
| 3046 | |||
| 3047 | if (cpsr & (1 << 17)) | ||
| 3048 | result |= from & 0x0000ff00; | ||
| 3049 | else | ||
| 3050 | result |= to & 0x0000ff00; | ||
| 3051 | |||
| 3052 | if (cpsr & (1 << 18)) | ||
| 3053 | result |= from & 0x00ff0000; | ||
| 3054 | else | ||
| 3055 | result |= to & 0x00ff0000; | ||
| 3056 | |||
| 3057 | if (cpsr & (1 << 19)) | ||
| 3058 | result |= from & 0xff000000; | ||
| 3059 | else | ||
| 3060 | result |= to & 0xff000000; | ||
| 3061 | |||
| 3062 | RD = result; | ||
| 3063 | } | ||
| 3064 | |||
| 3065 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3066 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3067 | FETCH_INST; | ||
| 3068 | GOTO_NEXT_INST; | ||
| 3069 | } | ||
| 3070 | |||
| 3071 | SETEND_INST : { | ||
| 3072 | // SETEND is unconditional | ||
| 3073 | setend_inst* const inst_cream = (setend_inst*)inst_base->component; | ||
| 3074 | const bool big_endian = (inst_cream->set_bigend == 1); | ||
| 3075 | |||
| 3076 | if (big_endian) | ||
| 3077 | cpu->Cpsr |= (1 << 9); | ||
| 3078 | else | ||
| 3079 | cpu->Cpsr &= ~(1 << 9); | ||
| 3080 | |||
| 3081 | LOG_WARNING(Core_ARM, "SETEND %s executed", big_endian ? "BE" : "LE"); | ||
| 3082 | |||
| 3083 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3084 | INC_PC(sizeof(setend_inst)); | ||
| 3085 | FETCH_INST; | ||
| 3086 | GOTO_NEXT_INST; | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | SEV_INST : { | ||
| 3090 | // Stubbed, as SEV is a hint instruction. | ||
| 3091 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3092 | LOG_TRACE(Core_ARM, "SEV executed."); | ||
| 3093 | } | ||
| 3094 | |||
| 3095 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3096 | INC_PC_STUB; | ||
| 3097 | FETCH_INST; | ||
| 3098 | GOTO_NEXT_INST; | ||
| 3099 | } | ||
| 3100 | |||
| 3101 | SHADD8_INST: | ||
| 3102 | SHADD16_INST: | ||
| 3103 | SHADDSUBX_INST: | ||
| 3104 | SHSUB8_INST: | ||
| 3105 | SHSUB16_INST: | ||
| 3106 | SHSUBADDX_INST : { | ||
| 3107 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3108 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3109 | |||
| 3110 | const u8 op2 = inst_cream->op2; | ||
| 3111 | const u32 rm_val = RM; | ||
| 3112 | const u32 rn_val = RN; | ||
| 3113 | |||
| 3114 | if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) { | ||
| 3115 | s32 lo_result = 0; | ||
| 3116 | s32 hi_result = 0; | ||
| 3117 | |||
| 3118 | // SHADD16 | ||
| 3119 | if (op2 == 0x00) { | ||
| 3120 | lo_result = ((s16)(rn_val & 0xFFFF) + (s16)(rm_val & 0xFFFF)) >> 1; | ||
| 3121 | hi_result = ((s16)((rn_val >> 16) & 0xFFFF) + (s16)((rm_val >> 16) & 0xFFFF)) >> 1; | ||
| 3122 | } | ||
| 3123 | // SHASX | ||
| 3124 | else if (op2 == 0x01) { | ||
| 3125 | lo_result = ((s16)(rn_val & 0xFFFF) - (s16)((rm_val >> 16) & 0xFFFF)) >> 1; | ||
| 3126 | hi_result = ((s16)((rn_val >> 16) & 0xFFFF) + (s16)(rm_val & 0xFFFF)) >> 1; | ||
| 3127 | } | ||
| 3128 | // SHSAX | ||
| 3129 | else if (op2 == 0x02) { | ||
| 3130 | lo_result = ((s16)(rn_val & 0xFFFF) + (s16)((rm_val >> 16) & 0xFFFF)) >> 1; | ||
| 3131 | hi_result = ((s16)((rn_val >> 16) & 0xFFFF) - (s16)(rm_val & 0xFFFF)) >> 1; | ||
| 3132 | } | ||
| 3133 | // SHSUB16 | ||
| 3134 | else if (op2 == 0x03) { | ||
| 3135 | lo_result = ((s16)(rn_val & 0xFFFF) - (s16)(rm_val & 0xFFFF)) >> 1; | ||
| 3136 | hi_result = ((s16)((rn_val >> 16) & 0xFFFF) - (s16)((rm_val >> 16) & 0xFFFF)) >> 1; | ||
| 3137 | } | ||
| 3138 | |||
| 3139 | RD = ((lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16)); | ||
| 3140 | } else if (op2 == 0x04 || op2 == 0x07) { | ||
| 3141 | s16 lo_val1, lo_val2; | ||
| 3142 | s16 hi_val1, hi_val2; | ||
| 3143 | |||
| 3144 | // SHADD8 | ||
| 3145 | if (op2 == 0x04) { | ||
| 3146 | lo_val1 = ((s8)(rn_val & 0xFF) + (s8)(rm_val & 0xFF)) >> 1; | ||
| 3147 | lo_val2 = ((s8)((rn_val >> 8) & 0xFF) + (s8)((rm_val >> 8) & 0xFF)) >> 1; | ||
| 3148 | |||
| 3149 | hi_val1 = ((s8)((rn_val >> 16) & 0xFF) + (s8)((rm_val >> 16) & 0xFF)) >> 1; | ||
| 3150 | hi_val2 = ((s8)((rn_val >> 24) & 0xFF) + (s8)((rm_val >> 24) & 0xFF)) >> 1; | ||
| 3151 | } | ||
| 3152 | // SHSUB8 | ||
| 3153 | else { | ||
| 3154 | lo_val1 = ((s8)(rn_val & 0xFF) - (s8)(rm_val & 0xFF)) >> 1; | ||
| 3155 | lo_val2 = ((s8)((rn_val >> 8) & 0xFF) - (s8)((rm_val >> 8) & 0xFF)) >> 1; | ||
| 3156 | |||
| 3157 | hi_val1 = ((s8)((rn_val >> 16) & 0xFF) - (s8)((rm_val >> 16) & 0xFF)) >> 1; | ||
| 3158 | hi_val2 = ((s8)((rn_val >> 24) & 0xFF) - (s8)((rm_val >> 24) & 0xFF)) >> 1; | ||
| 3159 | } | ||
| 3160 | |||
| 3161 | RD = (lo_val1 & 0xFF) | ((lo_val2 & 0xFF) << 8) | ((hi_val1 & 0xFF) << 16) | | ||
| 3162 | ((hi_val2 & 0xFF) << 24); | ||
| 3163 | } | ||
| 3164 | } | ||
| 3165 | |||
| 3166 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3167 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3168 | FETCH_INST; | ||
| 3169 | GOTO_NEXT_INST; | ||
| 3170 | } | ||
| 3171 | |||
| 3172 | SMLA_INST : { | ||
| 3173 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3174 | smla_inst* inst_cream = (smla_inst*)inst_base->component; | ||
| 3175 | s32 operand1, operand2; | ||
| 3176 | if (inst_cream->x == 0) | ||
| 3177 | operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); | ||
| 3178 | else | ||
| 3179 | operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); | ||
| 3180 | |||
| 3181 | if (inst_cream->y == 0) | ||
| 3182 | operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); | ||
| 3183 | else | ||
| 3184 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); | ||
| 3185 | |||
| 3186 | u32 product = operand1 * operand2; | ||
| 3187 | u32 result = product + RN; | ||
| 3188 | if (AddOverflow(product, RN, result)) | ||
| 3189 | cpu->Cpsr |= (1 << 27); | ||
| 3190 | RD = result; | ||
| 3191 | } | ||
| 3192 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3193 | INC_PC(sizeof(smla_inst)); | ||
| 3194 | FETCH_INST; | ||
| 3195 | GOTO_NEXT_INST; | ||
| 3196 | } | ||
| 3197 | |||
| 3198 | SMLAD_INST: | ||
| 3199 | SMLSD_INST: | ||
| 3200 | SMUAD_INST: | ||
| 3201 | SMUSD_INST : { | ||
| 3202 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3203 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 3204 | const u8 op2 = inst_cream->op2; | ||
| 3205 | |||
| 3206 | u32 rm_val = cpu->Reg[inst_cream->Rm]; | ||
| 3207 | const u32 rn_val = cpu->Reg[inst_cream->Rn]; | ||
| 3208 | |||
| 3209 | if (inst_cream->m) | ||
| 3210 | rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); | ||
| 3211 | |||
| 3212 | const s16 rm_lo = (rm_val & 0xFFFF); | ||
| 3213 | const s16 rm_hi = ((rm_val >> 16) & 0xFFFF); | ||
| 3214 | const s16 rn_lo = (rn_val & 0xFFFF); | ||
| 3215 | const s16 rn_hi = ((rn_val >> 16) & 0xFFFF); | ||
| 3216 | |||
| 3217 | const u32 product1 = (rn_lo * rm_lo); | ||
| 3218 | const u32 product2 = (rn_hi * rm_hi); | ||
| 3219 | |||
| 3220 | // SMUAD and SMLAD | ||
| 3221 | if (BIT(op2, 1) == 0) { | ||
| 3222 | u32 rd_val = (product1 + product2); | ||
| 3223 | |||
| 3224 | if (inst_cream->Ra != 15) { | ||
| 3225 | rd_val += cpu->Reg[inst_cream->Ra]; | ||
| 3226 | |||
| 3227 | if (ARMul_AddOverflowQ(product1 + product2, cpu->Reg[inst_cream->Ra])) | ||
| 3228 | cpu->Cpsr |= (1 << 27); | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | RD = rd_val; | ||
| 3232 | |||
| 3233 | if (ARMul_AddOverflowQ(product1, product2)) | ||
| 3234 | cpu->Cpsr |= (1 << 27); | ||
| 3235 | } | ||
| 3236 | // SMUSD and SMLSD | ||
| 3237 | else { | ||
| 3238 | u32 rd_val = (product1 - product2); | ||
| 3239 | |||
| 3240 | if (inst_cream->Ra != 15) { | ||
| 3241 | rd_val += cpu->Reg[inst_cream->Ra]; | ||
| 3242 | |||
| 3243 | if (ARMul_AddOverflowQ(product1 - product2, cpu->Reg[inst_cream->Ra])) | ||
| 3244 | cpu->Cpsr |= (1 << 27); | ||
| 3245 | } | ||
| 3246 | |||
| 3247 | RD = rd_val; | ||
| 3248 | } | ||
| 3249 | } | ||
| 3250 | |||
| 3251 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3252 | INC_PC(sizeof(smlad_inst)); | ||
| 3253 | FETCH_INST; | ||
| 3254 | GOTO_NEXT_INST; | ||
| 3255 | } | ||
| 3256 | |||
| 3257 | SMLAL_INST : { | ||
| 3258 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3259 | umlal_inst* inst_cream = (umlal_inst*)inst_base->component; | ||
| 3260 | long long int rm = RM; | ||
| 3261 | long long int rs = RS; | ||
| 3262 | if (BIT(rm, 31)) { | ||
| 3263 | rm |= 0xffffffff00000000LL; | ||
| 3264 | } | ||
| 3265 | if (BIT(rs, 31)) { | ||
| 3266 | rs |= 0xffffffff00000000LL; | ||
| 3267 | } | ||
| 3268 | long long int rst = rm * rs; | ||
| 3269 | long long int rdhi32 = RDHI; | ||
| 3270 | long long int hilo = (rdhi32 << 32) + RDLO; | ||
| 3271 | rst += hilo; | ||
| 3272 | RDLO = BITS(rst, 0, 31); | ||
| 3273 | RDHI = BITS(rst, 32, 63); | ||
| 3274 | if (inst_cream->S) { | ||
| 3275 | cpu->NFlag = BIT(RDHI, 31); | ||
| 3276 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 3277 | } | ||
| 3278 | } | ||
| 3279 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3280 | INC_PC(sizeof(umlal_inst)); | ||
| 3281 | FETCH_INST; | ||
| 3282 | GOTO_NEXT_INST; | ||
| 3283 | } | ||
| 3284 | |||
| 3285 | SMLALXY_INST : { | ||
| 3286 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3287 | smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component; | ||
| 3288 | |||
| 3289 | u64 operand1 = RN; | ||
| 3290 | u64 operand2 = RM; | ||
| 3291 | |||
| 3292 | if (inst_cream->x != 0) | ||
| 3293 | operand1 >>= 16; | ||
| 3294 | if (inst_cream->y != 0) | ||
| 3295 | operand2 >>= 16; | ||
| 3296 | operand1 &= 0xFFFF; | ||
| 3297 | if (operand1 & 0x8000) | ||
| 3298 | operand1 -= 65536; | ||
| 3299 | operand2 &= 0xFFFF; | ||
| 3300 | if (operand2 & 0x8000) | ||
| 3301 | operand2 -= 65536; | ||
| 3302 | |||
| 3303 | u64 dest = ((u64)RDHI << 32 | RDLO) + (operand1 * operand2); | ||
| 3304 | RDLO = (dest & 0xFFFFFFFF); | ||
| 3305 | RDHI = ((dest >> 32) & 0xFFFFFFFF); | ||
| 3306 | } | ||
| 3307 | |||
| 3308 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3309 | INC_PC(sizeof(smlalxy_inst)); | ||
| 3310 | FETCH_INST; | ||
| 3311 | GOTO_NEXT_INST; | ||
| 3312 | } | ||
| 3313 | |||
| 3314 | SMLAW_INST : { | ||
| 3315 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3316 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 3317 | |||
| 3318 | const u32 rm_val = RM; | ||
| 3319 | const u32 rn_val = RN; | ||
| 3320 | const u32 ra_val = cpu->Reg[inst_cream->Ra]; | ||
| 3321 | const bool high = (inst_cream->m == 1); | ||
| 3322 | |||
| 3323 | const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF); | ||
| 3324 | const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16); | ||
| 3325 | |||
| 3326 | RD = BITS(result, 16, 47); | ||
| 3327 | |||
| 3328 | if ((result >> 16) != (s32)RD) | ||
| 3329 | cpu->Cpsr |= (1 << 27); | ||
| 3330 | } | ||
| 3331 | |||
| 3332 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3333 | INC_PC(sizeof(smlad_inst)); | ||
| 3334 | FETCH_INST; | ||
| 3335 | GOTO_NEXT_INST; | ||
| 3336 | } | ||
| 3337 | |||
| 3338 | SMLALD_INST: | ||
| 3339 | SMLSLD_INST : { | ||
| 3340 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3341 | smlald_inst* const inst_cream = (smlald_inst*)inst_base->component; | ||
| 3342 | |||
| 3343 | const bool do_swap = (inst_cream->swap == 1); | ||
| 3344 | const u32 rdlo_val = RDLO; | ||
| 3345 | const u32 rdhi_val = RDHI; | ||
| 3346 | const u32 rn_val = RN; | ||
| 3347 | u32 rm_val = RM; | ||
| 3348 | |||
| 3349 | if (do_swap) | ||
| 3350 | rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); | ||
| 3351 | |||
| 3352 | const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); | ||
| 3353 | const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); | ||
| 3354 | s64 result; | ||
| 3355 | |||
| 3356 | // SMLALD | ||
| 3357 | if (BIT(inst_cream->op2, 1) == 0) { | ||
| 3358 | result = (product1 + product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); | ||
| 3359 | } | ||
| 3360 | // SMLSLD | ||
| 3361 | else { | ||
| 3362 | result = (product1 - product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32)); | ||
| 3363 | } | ||
| 3364 | |||
| 3365 | RDLO = (result & 0xFFFFFFFF); | ||
| 3366 | RDHI = ((result >> 32) & 0xFFFFFFFF); | ||
| 3367 | } | ||
| 3368 | |||
| 3369 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3370 | INC_PC(sizeof(smlald_inst)); | ||
| 3371 | FETCH_INST; | ||
| 3372 | GOTO_NEXT_INST; | ||
| 3373 | } | ||
| 3374 | |||
| 3375 | SMMLA_INST: | ||
| 3376 | SMMLS_INST: | ||
| 3377 | SMMUL_INST : { | ||
| 3378 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3379 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 3380 | |||
| 3381 | const u32 rm_val = RM; | ||
| 3382 | const u32 rn_val = RN; | ||
| 3383 | const bool do_round = (inst_cream->m == 1); | ||
| 3384 | |||
| 3385 | // Assume SMMUL by default. | ||
| 3386 | s64 result = (s64)(s32)rn_val * (s64)(s32)rm_val; | ||
| 3387 | |||
| 3388 | if (inst_cream->Ra != 15) { | ||
| 3389 | const u32 ra_val = cpu->Reg[inst_cream->Ra]; | ||
| 3390 | |||
| 3391 | // SMMLA, otherwise SMMLS | ||
| 3392 | if (BIT(inst_cream->op2, 1) == 0) | ||
| 3393 | result += ((s64)ra_val << 32); | ||
| 3394 | else | ||
| 3395 | result = ((s64)ra_val << 32) - result; | ||
| 3396 | } | ||
| 3397 | |||
| 3398 | if (do_round) | ||
| 3399 | result += 0x80000000; | ||
| 3400 | |||
| 3401 | RD = ((result >> 32) & 0xFFFFFFFF); | ||
| 3402 | } | ||
| 3403 | |||
| 3404 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3405 | INC_PC(sizeof(smlad_inst)); | ||
| 3406 | FETCH_INST; | ||
| 3407 | GOTO_NEXT_INST; | ||
| 3408 | } | ||
| 3409 | |||
| 3410 | SMUL_INST : { | ||
| 3411 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3412 | smul_inst* inst_cream = (smul_inst*)inst_base->component; | ||
| 3413 | u32 operand1, operand2; | ||
| 3414 | if (inst_cream->x == 0) | ||
| 3415 | operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); | ||
| 3416 | else | ||
| 3417 | operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); | ||
| 3418 | |||
| 3419 | if (inst_cream->y == 0) | ||
| 3420 | operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); | ||
| 3421 | else | ||
| 3422 | operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); | ||
| 3423 | RD = operand1 * operand2; | ||
| 3424 | } | ||
| 3425 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3426 | INC_PC(sizeof(smul_inst)); | ||
| 3427 | FETCH_INST; | ||
| 3428 | GOTO_NEXT_INST; | ||
| 3429 | } | ||
| 3430 | SMULL_INST : { | ||
| 3431 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3432 | umull_inst* inst_cream = (umull_inst*)inst_base->component; | ||
| 3433 | s64 rm = RM; | ||
| 3434 | s64 rs = RS; | ||
| 3435 | if (BIT(rm, 31)) { | ||
| 3436 | rm |= 0xffffffff00000000LL; | ||
| 3437 | } | ||
| 3438 | if (BIT(rs, 31)) { | ||
| 3439 | rs |= 0xffffffff00000000LL; | ||
| 3440 | } | ||
| 3441 | s64 rst = rm * rs; | ||
| 3442 | RDHI = BITS(rst, 32, 63); | ||
| 3443 | RDLO = BITS(rst, 0, 31); | ||
| 3444 | |||
| 3445 | if (inst_cream->S) { | ||
| 3446 | cpu->NFlag = BIT(RDHI, 31); | ||
| 3447 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 3448 | } | ||
| 3449 | } | ||
| 3450 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3451 | INC_PC(sizeof(umull_inst)); | ||
| 3452 | FETCH_INST; | ||
| 3453 | GOTO_NEXT_INST; | ||
| 3454 | } | ||
| 3455 | |||
| 3456 | SMULW_INST : { | ||
| 3457 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3458 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 3459 | |||
| 3460 | s16 rm = (inst_cream->m == 1) ? ((RM >> 16) & 0xFFFF) : (RM & 0xFFFF); | ||
| 3461 | |||
| 3462 | s64 result = (s64)rm * (s64)(s32)RN; | ||
| 3463 | RD = BITS(result, 16, 47); | ||
| 3464 | } | ||
| 3465 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3466 | INC_PC(sizeof(smlad_inst)); | ||
| 3467 | FETCH_INST; | ||
| 3468 | GOTO_NEXT_INST; | ||
| 3469 | } | ||
| 3470 | |||
| 3471 | SRS_INST : { | ||
| 3472 | // SRS is unconditional | ||
| 3473 | ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; | ||
| 3474 | |||
| 3475 | u32 address = 0; | ||
| 3476 | inst_cream->get_addr(cpu, inst_cream->inst, address); | ||
| 3477 | |||
| 3478 | cpu->WriteMemory32(address + 0, cpu->Reg[14]); | ||
| 3479 | cpu->WriteMemory32(address + 4, cpu->Spsr_copy); | ||
| 3480 | |||
| 3481 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3482 | INC_PC(sizeof(ldst_inst)); | ||
| 3483 | FETCH_INST; | ||
| 3484 | GOTO_NEXT_INST; | ||
| 3485 | } | ||
| 3486 | |||
| 3487 | SSAT_INST : { | ||
| 3488 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3489 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 3490 | |||
| 3491 | u8 shift_type = inst_cream->shift_type; | ||
| 3492 | u8 shift_amount = inst_cream->imm5; | ||
| 3493 | u32 rn_val = RN; | ||
| 3494 | |||
| 3495 | // 32-bit ASR is encoded as an amount of 0. | ||
| 3496 | if (shift_type == 1 && shift_amount == 0) | ||
| 3497 | shift_amount = 31; | ||
| 3498 | |||
| 3499 | if (shift_type == 0) | ||
| 3500 | rn_val <<= shift_amount; | ||
| 3501 | else if (shift_type == 1) | ||
| 3502 | rn_val = ((s32)rn_val >> shift_amount); | ||
| 3503 | |||
| 3504 | bool saturated = false; | ||
| 3505 | rn_val = ARMul_SignedSatQ(rn_val, inst_cream->sat_imm, &saturated); | ||
| 3506 | |||
| 3507 | if (saturated) | ||
| 3508 | cpu->Cpsr |= (1 << 27); | ||
| 3509 | |||
| 3510 | RD = rn_val; | ||
| 3511 | } | ||
| 3512 | |||
| 3513 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3514 | INC_PC(sizeof(ssat_inst)); | ||
| 3515 | FETCH_INST; | ||
| 3516 | GOTO_NEXT_INST; | ||
| 3517 | } | ||
| 3518 | |||
| 3519 | SSAT16_INST : { | ||
| 3520 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3521 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 3522 | const u8 saturate_to = inst_cream->sat_imm; | ||
| 3523 | |||
| 3524 | bool sat1 = false; | ||
| 3525 | bool sat2 = false; | ||
| 3526 | |||
| 3527 | RD = (ARMul_SignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) | | ||
| 3528 | ARMul_SignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16; | ||
| 3529 | |||
| 3530 | if (sat1 || sat2) | ||
| 3531 | cpu->Cpsr |= (1 << 27); | ||
| 3532 | } | ||
| 3533 | |||
| 3534 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3535 | INC_PC(sizeof(ssat_inst)); | ||
| 3536 | FETCH_INST; | ||
| 3537 | GOTO_NEXT_INST; | ||
| 3538 | } | ||
| 3539 | |||
| 3540 | STC_INST : { | ||
| 3541 | // Instruction not implemented | ||
| 3542 | // LOG_CRITICAL(Core_ARM, "unimplemented instruction"); | ||
| 3543 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3544 | INC_PC(sizeof(stc_inst)); | ||
| 3545 | FETCH_INST; | ||
| 3546 | GOTO_NEXT_INST; | ||
| 3547 | } | ||
| 3548 | STM_INST : { | ||
| 3549 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3550 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3551 | unsigned int inst = inst_cream->inst; | ||
| 3552 | |||
| 3553 | unsigned int Rn = BITS(inst, 16, 19); | ||
| 3554 | unsigned int old_RN = cpu->Reg[Rn]; | ||
| 3555 | |||
| 3556 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3557 | if (BIT(inst_cream->inst, 22) == 1) { | ||
| 3558 | for (int i = 0; i < 13; i++) { | ||
| 3559 | if (BIT(inst_cream->inst, i)) { | ||
| 3560 | cpu->WriteMemory32(addr, cpu->Reg[i]); | ||
| 3561 | addr += 4; | ||
| 3562 | } | ||
| 3563 | } | ||
| 3564 | if (BIT(inst_cream->inst, 13)) { | ||
| 3565 | if (cpu->Mode == USER32MODE) | ||
| 3566 | cpu->WriteMemory32(addr, cpu->Reg[13]); | ||
| 3567 | else | ||
| 3568 | cpu->WriteMemory32(addr, cpu->Reg_usr[0]); | ||
| 3569 | |||
| 3570 | addr += 4; | ||
| 3571 | } | ||
| 3572 | if (BIT(inst_cream->inst, 14)) { | ||
| 3573 | if (cpu->Mode == USER32MODE) | ||
| 3574 | cpu->WriteMemory32(addr, cpu->Reg[14]); | ||
| 3575 | else | ||
| 3576 | cpu->WriteMemory32(addr, cpu->Reg_usr[1]); | ||
| 3577 | |||
| 3578 | addr += 4; | ||
| 3579 | } | ||
| 3580 | if (BIT(inst_cream->inst, 15)) { | ||
| 3581 | cpu->WriteMemory32(addr, cpu->Reg[15] + 8); | ||
| 3582 | } | ||
| 3583 | } else { | ||
| 3584 | for (int i = 0; i < 15; i++) { | ||
| 3585 | if (BIT(inst_cream->inst, i)) { | ||
| 3586 | if (i == Rn) | ||
| 3587 | cpu->WriteMemory32(addr, old_RN); | ||
| 3588 | else | ||
| 3589 | cpu->WriteMemory32(addr, cpu->Reg[i]); | ||
| 3590 | |||
| 3591 | addr += 4; | ||
| 3592 | } | ||
| 3593 | } | ||
| 3594 | |||
| 3595 | // Check PC reg | ||
| 3596 | if (BIT(inst_cream->inst, 15)) { | ||
| 3597 | cpu->WriteMemory32(addr, cpu->Reg[15] + 8); | ||
| 3598 | } | ||
| 3599 | } | ||
| 3600 | } | ||
| 3601 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3602 | INC_PC(sizeof(ldst_inst)); | ||
| 3603 | FETCH_INST; | ||
| 3604 | GOTO_NEXT_INST; | ||
| 3605 | } | ||
| 3606 | SXTB_INST : { | ||
| 3607 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3608 | sxtb_inst* inst_cream = (sxtb_inst*)inst_base->component; | ||
| 3609 | |||
| 3610 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); | ||
| 3611 | if (BIT(operand2, 7)) { | ||
| 3612 | operand2 |= 0xffffff00; | ||
| 3613 | } else { | ||
| 3614 | operand2 &= 0xff; | ||
| 3615 | } | ||
| 3616 | RD = operand2; | ||
| 3617 | } | ||
| 3618 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3619 | INC_PC(sizeof(sxtb_inst)); | ||
| 3620 | FETCH_INST; | ||
| 3621 | GOTO_NEXT_INST; | ||
| 3622 | } | ||
| 3623 | STR_INST : { | ||
| 3624 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3625 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3626 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3627 | |||
| 3628 | unsigned int reg = BITS(inst_cream->inst, 12, 15); | ||
| 3629 | unsigned int value = cpu->Reg[reg]; | ||
| 3630 | |||
| 3631 | if (reg == 15) | ||
| 3632 | value += 2 * cpu->GetInstructionSize(); | ||
| 3633 | |||
| 3634 | cpu->WriteMemory32(addr, value); | ||
| 3635 | } | ||
| 3636 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3637 | INC_PC(sizeof(ldst_inst)); | ||
| 3638 | FETCH_INST; | ||
| 3639 | GOTO_NEXT_INST; | ||
| 3640 | } | ||
| 3641 | UXTB_INST : { | ||
| 3642 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3643 | uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component; | ||
| 3644 | RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; | ||
| 3645 | } | ||
| 3646 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3647 | INC_PC(sizeof(uxtb_inst)); | ||
| 3648 | FETCH_INST; | ||
| 3649 | GOTO_NEXT_INST; | ||
| 3650 | } | ||
| 3651 | UXTAB_INST : { | ||
| 3652 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3653 | uxtab_inst* inst_cream = (uxtab_inst*)inst_base->component; | ||
| 3654 | |||
| 3655 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; | ||
| 3656 | RD = RN + operand2; | ||
| 3657 | } | ||
| 3658 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3659 | INC_PC(sizeof(uxtab_inst)); | ||
| 3660 | FETCH_INST; | ||
| 3661 | GOTO_NEXT_INST; | ||
| 3662 | } | ||
| 3663 | STRB_INST : { | ||
| 3664 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3665 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3666 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3667 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | ||
| 3668 | cpu->WriteMemory8(addr, value); | ||
| 3669 | } | ||
| 3670 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3671 | INC_PC(sizeof(ldst_inst)); | ||
| 3672 | FETCH_INST; | ||
| 3673 | GOTO_NEXT_INST; | ||
| 3674 | } | ||
| 3675 | STRBT_INST : { | ||
| 3676 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3677 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3678 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3679 | |||
| 3680 | const u32 previous_mode = cpu->Mode; | ||
| 3681 | const u32 value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | ||
| 3682 | |||
| 3683 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 3684 | cpu->WriteMemory8(addr, value); | ||
| 3685 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 3686 | } | ||
| 3687 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3688 | INC_PC(sizeof(ldst_inst)); | ||
| 3689 | FETCH_INST; | ||
| 3690 | GOTO_NEXT_INST; | ||
| 3691 | } | ||
| 3692 | STRD_INST : { | ||
| 3693 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3694 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3695 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3696 | |||
| 3697 | // The 3DS doesn't have the Large Physical Access Extension (LPAE) | ||
| 3698 | // so STRD wouldn't store these as a single write. | ||
| 3699 | cpu->WriteMemory32(addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]); | ||
| 3700 | cpu->WriteMemory32(addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]); | ||
| 3701 | } | ||
| 3702 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3703 | INC_PC(sizeof(ldst_inst)); | ||
| 3704 | FETCH_INST; | ||
| 3705 | GOTO_NEXT_INST; | ||
| 3706 | } | ||
| 3707 | STREX_INST : { | ||
| 3708 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3709 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3710 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | ||
| 3711 | |||
| 3712 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { | ||
| 3713 | cpu->UnsetExclusiveMemoryAddress(); | ||
| 3714 | cpu->WriteMemory32(write_addr, RM); | ||
| 3715 | RD = 0; | ||
| 3716 | } else { | ||
| 3717 | // Failed to write due to mutex access | ||
| 3718 | RD = 1; | ||
| 3719 | } | ||
| 3720 | } | ||
| 3721 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3722 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3723 | FETCH_INST; | ||
| 3724 | GOTO_NEXT_INST; | ||
| 3725 | } | ||
| 3726 | STREXB_INST : { | ||
| 3727 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3728 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3729 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | ||
| 3730 | |||
| 3731 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { | ||
| 3732 | cpu->UnsetExclusiveMemoryAddress(); | ||
| 3733 | cpu->WriteMemory8(write_addr, cpu->Reg[inst_cream->Rm]); | ||
| 3734 | RD = 0; | ||
| 3735 | } else { | ||
| 3736 | // Failed to write due to mutex access | ||
| 3737 | RD = 1; | ||
| 3738 | } | ||
| 3739 | } | ||
| 3740 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3741 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3742 | FETCH_INST; | ||
| 3743 | GOTO_NEXT_INST; | ||
| 3744 | } | ||
| 3745 | STREXD_INST : { | ||
| 3746 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3747 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3748 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | ||
| 3749 | |||
| 3750 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { | ||
| 3751 | cpu->UnsetExclusiveMemoryAddress(); | ||
| 3752 | |||
| 3753 | const u32 rt = cpu->Reg[inst_cream->Rm + 0]; | ||
| 3754 | const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; | ||
| 3755 | u64 value; | ||
| 3756 | |||
| 3757 | if (cpu->InBigEndianMode()) | ||
| 3758 | value = (((u64)rt << 32) | rt2); | ||
| 3759 | else | ||
| 3760 | value = (((u64)rt2 << 32) | rt); | ||
| 3761 | |||
| 3762 | cpu->WriteMemory64(write_addr, value); | ||
| 3763 | RD = 0; | ||
| 3764 | } else { | ||
| 3765 | // Failed to write due to mutex access | ||
| 3766 | RD = 1; | ||
| 3767 | } | ||
| 3768 | } | ||
| 3769 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3770 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3771 | FETCH_INST; | ||
| 3772 | GOTO_NEXT_INST; | ||
| 3773 | } | ||
| 3774 | STREXH_INST : { | ||
| 3775 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3776 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 3777 | unsigned int write_addr = cpu->Reg[inst_cream->Rn]; | ||
| 3778 | |||
| 3779 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { | ||
| 3780 | cpu->UnsetExclusiveMemoryAddress(); | ||
| 3781 | cpu->WriteMemory16(write_addr, RM); | ||
| 3782 | RD = 0; | ||
| 3783 | } else { | ||
| 3784 | // Failed to write due to mutex access | ||
| 3785 | RD = 1; | ||
| 3786 | } | ||
| 3787 | } | ||
| 3788 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3789 | INC_PC(sizeof(generic_arm_inst)); | ||
| 3790 | FETCH_INST; | ||
| 3791 | GOTO_NEXT_INST; | ||
| 3792 | } | ||
| 3793 | STRH_INST : { | ||
| 3794 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3795 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3796 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3797 | |||
| 3798 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; | ||
| 3799 | cpu->WriteMemory16(addr, value); | ||
| 3800 | } | ||
| 3801 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3802 | INC_PC(sizeof(ldst_inst)); | ||
| 3803 | FETCH_INST; | ||
| 3804 | GOTO_NEXT_INST; | ||
| 3805 | } | ||
| 3806 | STRT_INST : { | ||
| 3807 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3808 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 3809 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | ||
| 3810 | |||
| 3811 | const u32 previous_mode = cpu->Mode; | ||
| 3812 | const u32 rt_index = BITS(inst_cream->inst, 12, 15); | ||
| 3813 | |||
| 3814 | u32 value = cpu->Reg[rt_index]; | ||
| 3815 | if (rt_index == 15) | ||
| 3816 | value += 2 * cpu->GetInstructionSize(); | ||
| 3817 | |||
| 3818 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 3819 | cpu->WriteMemory32(addr, value); | ||
| 3820 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 3821 | } | ||
| 3822 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3823 | INC_PC(sizeof(ldst_inst)); | ||
| 3824 | FETCH_INST; | ||
| 3825 | GOTO_NEXT_INST; | ||
| 3826 | } | ||
| 3827 | SUB_INST : { | ||
| 3828 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3829 | sub_inst* const inst_cream = (sub_inst*)inst_base->component; | ||
| 3830 | |||
| 3831 | u32 rn_val = CHECK_READ_REG15_WA(cpu, inst_cream->Rn); | ||
| 3832 | |||
| 3833 | bool carry; | ||
| 3834 | bool overflow; | ||
| 3835 | RD = AddWithCarry(rn_val, ~SHIFTER_OPERAND, 1, &carry, &overflow); | ||
| 3836 | |||
| 3837 | if (inst_cream->S && (inst_cream->Rd == 15)) { | ||
| 3838 | if (CurrentModeHasSPSR) { | ||
| 3839 | cpu->Cpsr = cpu->Spsr_copy; | ||
| 3840 | cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F); | ||
| 3841 | LOAD_NZCVT; | ||
| 3842 | } | ||
| 3843 | } else if (inst_cream->S) { | ||
| 3844 | UPDATE_NFLAG(RD); | ||
| 3845 | UPDATE_ZFLAG(RD); | ||
| 3846 | cpu->CFlag = carry; | ||
| 3847 | cpu->VFlag = overflow; | ||
| 3848 | } | ||
| 3849 | if (inst_cream->Rd == 15) { | ||
| 3850 | INC_PC(sizeof(sub_inst)); | ||
| 3851 | goto DISPATCH; | ||
| 3852 | } | ||
| 3853 | } | ||
| 3854 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3855 | INC_PC(sizeof(sub_inst)); | ||
| 3856 | FETCH_INST; | ||
| 3857 | GOTO_NEXT_INST; | ||
| 3858 | } | ||
| 3859 | SWI_INST : { | ||
| 3860 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3861 | swi_inst* const inst_cream = (swi_inst*)inst_base->component; | ||
| 3862 | SVC::CallSVC(inst_cream->num & 0xFFFF); | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3866 | INC_PC(sizeof(swi_inst)); | ||
| 3867 | FETCH_INST; | ||
| 3868 | GOTO_NEXT_INST; | ||
| 3869 | } | ||
| 3870 | SWP_INST : { | ||
| 3871 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3872 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | ||
| 3873 | |||
| 3874 | addr = RN; | ||
| 3875 | unsigned int value = cpu->ReadMemory32(addr); | ||
| 3876 | cpu->WriteMemory32(addr, RM); | ||
| 3877 | |||
| 3878 | RD = value; | ||
| 3879 | } | ||
| 3880 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3881 | INC_PC(sizeof(swp_inst)); | ||
| 3882 | FETCH_INST; | ||
| 3883 | GOTO_NEXT_INST; | ||
| 3884 | } | ||
| 3885 | SWPB_INST : { | ||
| 3886 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3887 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | ||
| 3888 | addr = RN; | ||
| 3889 | unsigned int value = cpu->ReadMemory8(addr); | ||
| 3890 | cpu->WriteMemory8(addr, (RM & 0xFF)); | ||
| 3891 | RD = value; | ||
| 3892 | } | ||
| 3893 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3894 | INC_PC(sizeof(swp_inst)); | ||
| 3895 | FETCH_INST; | ||
| 3896 | GOTO_NEXT_INST; | ||
| 3897 | } | ||
| 3898 | SXTAB_INST : { | ||
| 3899 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3900 | sxtab_inst* inst_cream = (sxtab_inst*)inst_base->component; | ||
| 3901 | |||
| 3902 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; | ||
| 3903 | |||
| 3904 | // Sign extend for byte | ||
| 3905 | operand2 = (0x80 & operand2) ? (0xFFFFFF00 | operand2) : operand2; | ||
| 3906 | RD = RN + operand2; | ||
| 3907 | } | ||
| 3908 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3909 | INC_PC(sizeof(uxtab_inst)); | ||
| 3910 | FETCH_INST; | ||
| 3911 | GOTO_NEXT_INST; | ||
| 3912 | } | ||
| 3913 | |||
| 3914 | SXTAB16_INST: | ||
| 3915 | SXTB16_INST : { | ||
| 3916 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3917 | sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component; | ||
| 3918 | |||
| 3919 | const u8 rotation = inst_cream->rotate * 8; | ||
| 3920 | u32 rm_val = RM; | ||
| 3921 | u32 rn_val = RN; | ||
| 3922 | |||
| 3923 | if (rotation) | ||
| 3924 | rm_val = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); | ||
| 3925 | |||
| 3926 | // SXTB16 | ||
| 3927 | if (inst_cream->Rn == 15) { | ||
| 3928 | u32 lo = (u32)(s8)rm_val; | ||
| 3929 | u32 hi = (u32)(s8)(rm_val >> 16); | ||
| 3930 | RD = (lo & 0xFFFF) | (hi << 16); | ||
| 3931 | } | ||
| 3932 | // SXTAB16 | ||
| 3933 | else { | ||
| 3934 | u32 lo = rn_val + (u32)(s8)(rm_val & 0xFF); | ||
| 3935 | u32 hi = (rn_val >> 16) + (u32)(s8)((rm_val >> 16) & 0xFF); | ||
| 3936 | RD = (lo & 0xFFFF) | (hi << 16); | ||
| 3937 | } | ||
| 3938 | } | ||
| 3939 | |||
| 3940 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3941 | INC_PC(sizeof(sxtab_inst)); | ||
| 3942 | FETCH_INST; | ||
| 3943 | GOTO_NEXT_INST; | ||
| 3944 | } | ||
| 3945 | |||
| 3946 | SXTAH_INST : { | ||
| 3947 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3948 | sxtah_inst* inst_cream = (sxtah_inst*)inst_base->component; | ||
| 3949 | |||
| 3950 | unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; | ||
| 3951 | // Sign extend for half | ||
| 3952 | operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2; | ||
| 3953 | RD = RN + operand2; | ||
| 3954 | } | ||
| 3955 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3956 | INC_PC(sizeof(sxtah_inst)); | ||
| 3957 | FETCH_INST; | ||
| 3958 | GOTO_NEXT_INST; | ||
| 3959 | } | ||
| 3960 | |||
| 3961 | TEQ_INST : { | ||
| 3962 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3963 | teq_inst* const inst_cream = (teq_inst*)inst_base->component; | ||
| 3964 | |||
| 3965 | u32 lop = RN; | ||
| 3966 | u32 rop = SHIFTER_OPERAND; | ||
| 3967 | |||
| 3968 | if (inst_cream->Rn == 15) | ||
| 3969 | lop += cpu->GetInstructionSize() * 2; | ||
| 3970 | |||
| 3971 | u32 result = lop ^ rop; | ||
| 3972 | |||
| 3973 | UPDATE_NFLAG(result); | ||
| 3974 | UPDATE_ZFLAG(result); | ||
| 3975 | UPDATE_CFLAG_WITH_SC; | ||
| 3976 | } | ||
| 3977 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3978 | INC_PC(sizeof(teq_inst)); | ||
| 3979 | FETCH_INST; | ||
| 3980 | GOTO_NEXT_INST; | ||
| 3981 | } | ||
| 3982 | TST_INST : { | ||
| 3983 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 3984 | tst_inst* const inst_cream = (tst_inst*)inst_base->component; | ||
| 3985 | |||
| 3986 | u32 lop = RN; | ||
| 3987 | u32 rop = SHIFTER_OPERAND; | ||
| 3988 | |||
| 3989 | if (inst_cream->Rn == 15) | ||
| 3990 | lop += cpu->GetInstructionSize() * 2; | ||
| 3991 | |||
| 3992 | u32 result = lop & rop; | ||
| 3993 | |||
| 3994 | UPDATE_NFLAG(result); | ||
| 3995 | UPDATE_ZFLAG(result); | ||
| 3996 | UPDATE_CFLAG_WITH_SC; | ||
| 3997 | } | ||
| 3998 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 3999 | INC_PC(sizeof(tst_inst)); | ||
| 4000 | FETCH_INST; | ||
| 4001 | GOTO_NEXT_INST; | ||
| 4002 | } | ||
| 4003 | |||
| 4004 | UADD8_INST: | ||
| 4005 | UADD16_INST: | ||
| 4006 | UADDSUBX_INST: | ||
| 4007 | USUB8_INST: | ||
| 4008 | USUB16_INST: | ||
| 4009 | USUBADDX_INST : { | ||
| 4010 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4011 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 4012 | |||
| 4013 | const u8 op2 = inst_cream->op2; | ||
| 4014 | const u32 rm_val = RM; | ||
| 4015 | const u32 rn_val = RN; | ||
| 4016 | |||
| 4017 | s32 lo_result = 0; | ||
| 4018 | s32 hi_result = 0; | ||
| 4019 | |||
| 4020 | // UADD16 | ||
| 4021 | if (op2 == 0x00) { | ||
| 4022 | lo_result = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); | ||
| 4023 | hi_result = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); | ||
| 4024 | |||
| 4025 | if (lo_result & 0xFFFF0000) { | ||
| 4026 | cpu->Cpsr |= (1 << 16); | ||
| 4027 | cpu->Cpsr |= (1 << 17); | ||
| 4028 | } else { | ||
| 4029 | cpu->Cpsr &= ~(1 << 16); | ||
| 4030 | cpu->Cpsr &= ~(1 << 17); | ||
| 4031 | } | ||
| 4032 | |||
| 4033 | if (hi_result & 0xFFFF0000) { | ||
| 4034 | cpu->Cpsr |= (1 << 18); | ||
| 4035 | cpu->Cpsr |= (1 << 19); | ||
| 4036 | } else { | ||
| 4037 | cpu->Cpsr &= ~(1 << 18); | ||
| 4038 | cpu->Cpsr &= ~(1 << 19); | ||
| 4039 | } | ||
| 4040 | } | ||
| 4041 | // UASX | ||
| 4042 | else if (op2 == 0x01) { | ||
| 4043 | lo_result = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); | ||
| 4044 | hi_result = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF); | ||
| 4045 | |||
| 4046 | if (lo_result >= 0) { | ||
| 4047 | cpu->Cpsr |= (1 << 16); | ||
| 4048 | cpu->Cpsr |= (1 << 17); | ||
| 4049 | } else { | ||
| 4050 | cpu->Cpsr &= ~(1 << 16); | ||
| 4051 | cpu->Cpsr &= ~(1 << 17); | ||
| 4052 | } | ||
| 4053 | |||
| 4054 | if (hi_result >= 0x10000) { | ||
| 4055 | cpu->Cpsr |= (1 << 18); | ||
| 4056 | cpu->Cpsr |= (1 << 19); | ||
| 4057 | } else { | ||
| 4058 | cpu->Cpsr &= ~(1 << 18); | ||
| 4059 | cpu->Cpsr &= ~(1 << 19); | ||
| 4060 | } | ||
| 4061 | } | ||
| 4062 | // USAX | ||
| 4063 | else if (op2 == 0x02) { | ||
| 4064 | lo_result = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); | ||
| 4065 | hi_result = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF); | ||
| 4066 | |||
| 4067 | if (lo_result >= 0x10000) { | ||
| 4068 | cpu->Cpsr |= (1 << 16); | ||
| 4069 | cpu->Cpsr |= (1 << 17); | ||
| 4070 | } else { | ||
| 4071 | cpu->Cpsr &= ~(1 << 16); | ||
| 4072 | cpu->Cpsr &= ~(1 << 17); | ||
| 4073 | } | ||
| 4074 | |||
| 4075 | if (hi_result >= 0) { | ||
| 4076 | cpu->Cpsr |= (1 << 18); | ||
| 4077 | cpu->Cpsr |= (1 << 19); | ||
| 4078 | } else { | ||
| 4079 | cpu->Cpsr &= ~(1 << 18); | ||
| 4080 | cpu->Cpsr &= ~(1 << 19); | ||
| 4081 | } | ||
| 4082 | } | ||
| 4083 | // USUB16 | ||
| 4084 | else if (op2 == 0x03) { | ||
| 4085 | lo_result = (rn_val & 0xFFFF) - (rm_val & 0xFFFF); | ||
| 4086 | hi_result = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); | ||
| 4087 | |||
| 4088 | if ((lo_result & 0xFFFF0000) == 0) { | ||
| 4089 | cpu->Cpsr |= (1 << 16); | ||
| 4090 | cpu->Cpsr |= (1 << 17); | ||
| 4091 | } else { | ||
| 4092 | cpu->Cpsr &= ~(1 << 16); | ||
| 4093 | cpu->Cpsr &= ~(1 << 17); | ||
| 4094 | } | ||
| 4095 | |||
| 4096 | if ((hi_result & 0xFFFF0000) == 0) { | ||
| 4097 | cpu->Cpsr |= (1 << 18); | ||
| 4098 | cpu->Cpsr |= (1 << 19); | ||
| 4099 | } else { | ||
| 4100 | cpu->Cpsr &= ~(1 << 18); | ||
| 4101 | cpu->Cpsr &= ~(1 << 19); | ||
| 4102 | } | ||
| 4103 | } | ||
| 4104 | // UADD8 | ||
| 4105 | else if (op2 == 0x04) { | ||
| 4106 | s16 sum1 = (rn_val & 0xFF) + (rm_val & 0xFF); | ||
| 4107 | s16 sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF); | ||
| 4108 | s16 sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF); | ||
| 4109 | s16 sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF); | ||
| 4110 | |||
| 4111 | if (sum1 >= 0x100) | ||
| 4112 | cpu->Cpsr |= (1 << 16); | ||
| 4113 | else | ||
| 4114 | cpu->Cpsr &= ~(1 << 16); | ||
| 4115 | |||
| 4116 | if (sum2 >= 0x100) | ||
| 4117 | cpu->Cpsr |= (1 << 17); | ||
| 4118 | else | ||
| 4119 | cpu->Cpsr &= ~(1 << 17); | ||
| 4120 | |||
| 4121 | if (sum3 >= 0x100) | ||
| 4122 | cpu->Cpsr |= (1 << 18); | ||
| 4123 | else | ||
| 4124 | cpu->Cpsr &= ~(1 << 18); | ||
| 4125 | |||
| 4126 | if (sum4 >= 0x100) | ||
| 4127 | cpu->Cpsr |= (1 << 19); | ||
| 4128 | else | ||
| 4129 | cpu->Cpsr &= ~(1 << 19); | ||
| 4130 | |||
| 4131 | lo_result = ((sum1 & 0xFF) | (sum2 & 0xFF) << 8); | ||
| 4132 | hi_result = ((sum3 & 0xFF) | (sum4 & 0xFF) << 8); | ||
| 4133 | } | ||
| 4134 | // USUB8 | ||
| 4135 | else if (op2 == 0x07) { | ||
| 4136 | s16 diff1 = (rn_val & 0xFF) - (rm_val & 0xFF); | ||
| 4137 | s16 diff2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF); | ||
| 4138 | s16 diff3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF); | ||
| 4139 | s16 diff4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF); | ||
| 4140 | |||
| 4141 | if (diff1 >= 0) | ||
| 4142 | cpu->Cpsr |= (1 << 16); | ||
| 4143 | else | ||
| 4144 | cpu->Cpsr &= ~(1 << 16); | ||
| 4145 | |||
| 4146 | if (diff2 >= 0) | ||
| 4147 | cpu->Cpsr |= (1 << 17); | ||
| 4148 | else | ||
| 4149 | cpu->Cpsr &= ~(1 << 17); | ||
| 4150 | |||
| 4151 | if (diff3 >= 0) | ||
| 4152 | cpu->Cpsr |= (1 << 18); | ||
| 4153 | else | ||
| 4154 | cpu->Cpsr &= ~(1 << 18); | ||
| 4155 | |||
| 4156 | if (diff4 >= 0) | ||
| 4157 | cpu->Cpsr |= (1 << 19); | ||
| 4158 | else | ||
| 4159 | cpu->Cpsr &= ~(1 << 19); | ||
| 4160 | |||
| 4161 | lo_result = (diff1 & 0xFF) | ((diff2 & 0xFF) << 8); | ||
| 4162 | hi_result = (diff3 & 0xFF) | ((diff4 & 0xFF) << 8); | ||
| 4163 | } | ||
| 4164 | |||
| 4165 | RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); | ||
| 4166 | } | ||
| 4167 | |||
| 4168 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4169 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4170 | FETCH_INST; | ||
| 4171 | GOTO_NEXT_INST; | ||
| 4172 | } | ||
| 4173 | |||
| 4174 | UHADD8_INST: | ||
| 4175 | UHADD16_INST: | ||
| 4176 | UHADDSUBX_INST: | ||
| 4177 | UHSUBADDX_INST: | ||
| 4178 | UHSUB8_INST: | ||
| 4179 | UHSUB16_INST : { | ||
| 4180 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4181 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 4182 | const u32 rm_val = RM; | ||
| 4183 | const u32 rn_val = RN; | ||
| 4184 | const u8 op2 = inst_cream->op2; | ||
| 4185 | |||
| 4186 | if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03) { | ||
| 4187 | u32 lo_val = 0; | ||
| 4188 | u32 hi_val = 0; | ||
| 4189 | |||
| 4190 | // UHADD16 | ||
| 4191 | if (op2 == 0x00) { | ||
| 4192 | lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); | ||
| 4193 | hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); | ||
| 4194 | } | ||
| 4195 | // UHASX | ||
| 4196 | else if (op2 == 0x01) { | ||
| 4197 | lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); | ||
| 4198 | hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF); | ||
| 4199 | } | ||
| 4200 | // UHSAX | ||
| 4201 | else if (op2 == 0x02) { | ||
| 4202 | lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF); | ||
| 4203 | hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF); | ||
| 4204 | } | ||
| 4205 | // UHSUB16 | ||
| 4206 | else if (op2 == 0x03) { | ||
| 4207 | lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF); | ||
| 4208 | hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF); | ||
| 4209 | } | ||
| 4210 | |||
| 4211 | lo_val >>= 1; | ||
| 4212 | hi_val >>= 1; | ||
| 4213 | |||
| 4214 | RD = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16); | ||
| 4215 | } else if (op2 == 0x04 || op2 == 0x07) { | ||
| 4216 | u32 sum1; | ||
| 4217 | u32 sum2; | ||
| 4218 | u32 sum3; | ||
| 4219 | u32 sum4; | ||
| 4220 | |||
| 4221 | // UHADD8 | ||
| 4222 | if (op2 == 0x04) { | ||
| 4223 | sum1 = (rn_val & 0xFF) + (rm_val & 0xFF); | ||
| 4224 | sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF); | ||
| 4225 | sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF); | ||
| 4226 | sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF); | ||
| 4227 | } | ||
| 4228 | // UHSUB8 | ||
| 4229 | else { | ||
| 4230 | sum1 = (rn_val & 0xFF) - (rm_val & 0xFF); | ||
| 4231 | sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF); | ||
| 4232 | sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF); | ||
| 4233 | sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF); | ||
| 4234 | } | ||
| 4235 | |||
| 4236 | sum1 >>= 1; | ||
| 4237 | sum2 >>= 1; | ||
| 4238 | sum3 >>= 1; | ||
| 4239 | sum4 >>= 1; | ||
| 4240 | |||
| 4241 | RD = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) | | ||
| 4242 | ((sum4 & 0xFF) << 24); | ||
| 4243 | } | ||
| 4244 | } | ||
| 4245 | |||
| 4246 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4247 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4248 | FETCH_INST; | ||
| 4249 | GOTO_NEXT_INST; | ||
| 4250 | } | ||
| 4251 | |||
| 4252 | UMAAL_INST : { | ||
| 4253 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4254 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 4255 | const u64 rm = RM; | ||
| 4256 | const u64 rn = RN; | ||
| 4257 | const u64 rd_lo = RDLO; | ||
| 4258 | const u64 rd_hi = RDHI; | ||
| 4259 | const u64 result = (rm * rn) + rd_lo + rd_hi; | ||
| 4260 | |||
| 4261 | RDLO = (result & 0xFFFFFFFF); | ||
| 4262 | RDHI = ((result >> 32) & 0xFFFFFFFF); | ||
| 4263 | } | ||
| 4264 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4265 | INC_PC(sizeof(umaal_inst)); | ||
| 4266 | FETCH_INST; | ||
| 4267 | GOTO_NEXT_INST; | ||
| 4268 | } | ||
| 4269 | UMLAL_INST : { | ||
| 4270 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4271 | umlal_inst* inst_cream = (umlal_inst*)inst_base->component; | ||
| 4272 | unsigned long long int rm = RM; | ||
| 4273 | unsigned long long int rs = RS; | ||
| 4274 | unsigned long long int rst = rm * rs; | ||
| 4275 | unsigned long long int add = ((unsigned long long)RDHI) << 32; | ||
| 4276 | add += RDLO; | ||
| 4277 | rst += add; | ||
| 4278 | RDLO = BITS(rst, 0, 31); | ||
| 4279 | RDHI = BITS(rst, 32, 63); | ||
| 4280 | |||
| 4281 | if (inst_cream->S) { | ||
| 4282 | cpu->NFlag = BIT(RDHI, 31); | ||
| 4283 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 4284 | } | ||
| 4285 | } | ||
| 4286 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4287 | INC_PC(sizeof(umlal_inst)); | ||
| 4288 | FETCH_INST; | ||
| 4289 | GOTO_NEXT_INST; | ||
| 4290 | } | ||
| 4291 | UMULL_INST : { | ||
| 4292 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4293 | umull_inst* inst_cream = (umull_inst*)inst_base->component; | ||
| 4294 | unsigned long long int rm = RM; | ||
| 4295 | unsigned long long int rs = RS; | ||
| 4296 | unsigned long long int rst = rm * rs; | ||
| 4297 | RDHI = BITS(rst, 32, 63); | ||
| 4298 | RDLO = BITS(rst, 0, 31); | ||
| 4299 | |||
| 4300 | if (inst_cream->S) { | ||
| 4301 | cpu->NFlag = BIT(RDHI, 31); | ||
| 4302 | cpu->ZFlag = (RDHI == 0 && RDLO == 0); | ||
| 4303 | } | ||
| 4304 | } | ||
| 4305 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4306 | INC_PC(sizeof(umull_inst)); | ||
| 4307 | FETCH_INST; | ||
| 4308 | GOTO_NEXT_INST; | ||
| 4309 | } | ||
| 4310 | B_2_THUMB : { | ||
| 4311 | b_2_thumb* inst_cream = (b_2_thumb*)inst_base->component; | ||
| 4312 | cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 4313 | INC_PC(sizeof(b_2_thumb)); | ||
| 4314 | goto DISPATCH; | ||
| 4315 | } | ||
| 4316 | B_COND_THUMB : { | ||
| 4317 | b_cond_thumb* inst_cream = (b_cond_thumb*)inst_base->component; | ||
| 4318 | |||
| 4319 | if (CondPassed(cpu, inst_cream->cond)) | ||
| 4320 | cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 4321 | else | ||
| 4322 | cpu->Reg[15] += 2; | ||
| 4323 | |||
| 4324 | INC_PC(sizeof(b_cond_thumb)); | ||
| 4325 | goto DISPATCH; | ||
| 4326 | } | ||
| 4327 | BL_1_THUMB : { | ||
| 4328 | bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component; | ||
| 4329 | cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; | ||
| 4330 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4331 | INC_PC(sizeof(bl_1_thumb)); | ||
| 4332 | FETCH_INST; | ||
| 4333 | GOTO_NEXT_INST; | ||
| 4334 | } | ||
| 4335 | BL_2_THUMB : { | ||
| 4336 | bl_2_thumb* inst_cream = (bl_2_thumb*)inst_base->component; | ||
| 4337 | int tmp = ((cpu->Reg[15] + 2) | 1); | ||
| 4338 | cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm); | ||
| 4339 | cpu->Reg[14] = tmp; | ||
| 4340 | INC_PC(sizeof(bl_2_thumb)); | ||
| 4341 | goto DISPATCH; | ||
| 4342 | } | ||
| 4343 | BLX_1_THUMB : { | ||
| 4344 | // BLX 1 for armv5t and above | ||
| 4345 | u32 tmp = cpu->Reg[15]; | ||
| 4346 | blx_1_thumb* inst_cream = (blx_1_thumb*)inst_base->component; | ||
| 4347 | cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC; | ||
| 4348 | cpu->Reg[14] = ((tmp + 2) | 1); | ||
| 4349 | cpu->TFlag = 0; | ||
| 4350 | INC_PC(sizeof(blx_1_thumb)); | ||
| 4351 | goto DISPATCH; | ||
| 4352 | } | ||
| 4353 | |||
| 4354 | UQADD8_INST: | ||
| 4355 | UQADD16_INST: | ||
| 4356 | UQADDSUBX_INST: | ||
| 4357 | UQSUB8_INST: | ||
| 4358 | UQSUB16_INST: | ||
| 4359 | UQSUBADDX_INST : { | ||
| 4360 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4361 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 4362 | |||
| 4363 | const u8 op2 = inst_cream->op2; | ||
| 4364 | const u32 rm_val = RM; | ||
| 4365 | const u32 rn_val = RN; | ||
| 4366 | |||
| 4367 | u16 lo_val = 0; | ||
| 4368 | u16 hi_val = 0; | ||
| 4369 | |||
| 4370 | // UQADD16 | ||
| 4371 | if (op2 == 0x00) { | ||
| 4372 | lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); | ||
| 4373 | hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); | ||
| 4374 | } | ||
| 4375 | // UQASX | ||
| 4376 | else if (op2 == 0x01) { | ||
| 4377 | lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); | ||
| 4378 | hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); | ||
| 4379 | } | ||
| 4380 | // UQSAX | ||
| 4381 | else if (op2 == 0x02) { | ||
| 4382 | lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF); | ||
| 4383 | hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF); | ||
| 4384 | } | ||
| 4385 | // UQSUB16 | ||
| 4386 | else if (op2 == 0x03) { | ||
| 4387 | lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF); | ||
| 4388 | hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF); | ||
| 4389 | } | ||
| 4390 | // UQADD8 | ||
| 4391 | else if (op2 == 0x04) { | ||
| 4392 | lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) | | ||
| 4393 | ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8; | ||
| 4394 | hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) | | ||
| 4395 | ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8; | ||
| 4396 | } | ||
| 4397 | // UQSUB8 | ||
| 4398 | else { | ||
| 4399 | lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) | | ||
| 4400 | ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8; | ||
| 4401 | hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) | | ||
| 4402 | ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8; | ||
| 4403 | } | ||
| 4404 | |||
| 4405 | RD = ((lo_val & 0xFFFF) | hi_val << 16); | ||
| 4406 | } | ||
| 4407 | |||
| 4408 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4409 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4410 | FETCH_INST; | ||
| 4411 | GOTO_NEXT_INST; | ||
| 4412 | } | ||
| 4413 | |||
| 4414 | USAD8_INST: | ||
| 4415 | USADA8_INST : { | ||
| 4416 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4417 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 4418 | |||
| 4419 | const u8 ra_idx = inst_cream->Ra; | ||
| 4420 | const u32 rm_val = RM; | ||
| 4421 | const u32 rn_val = RN; | ||
| 4422 | |||
| 4423 | const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF); | ||
| 4424 | const u8 diff2 = | ||
| 4425 | ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF); | ||
| 4426 | const u8 diff3 = | ||
| 4427 | ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF); | ||
| 4428 | const u8 diff4 = | ||
| 4429 | ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF); | ||
| 4430 | |||
| 4431 | u32 finalDif = (diff1 + diff2 + diff3 + diff4); | ||
| 4432 | |||
| 4433 | // Op is USADA8 if true. | ||
| 4434 | if (ra_idx != 15) | ||
| 4435 | finalDif += cpu->Reg[ra_idx]; | ||
| 4436 | |||
| 4437 | RD = finalDif; | ||
| 4438 | } | ||
| 4439 | |||
| 4440 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4441 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4442 | FETCH_INST; | ||
| 4443 | GOTO_NEXT_INST; | ||
| 4444 | } | ||
| 4445 | |||
| 4446 | USAT_INST : { | ||
| 4447 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4448 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 4449 | |||
| 4450 | u8 shift_type = inst_cream->shift_type; | ||
| 4451 | u8 shift_amount = inst_cream->imm5; | ||
| 4452 | u32 rn_val = RN; | ||
| 4453 | |||
| 4454 | // 32-bit ASR is encoded as an amount of 0. | ||
| 4455 | if (shift_type == 1 && shift_amount == 0) | ||
| 4456 | shift_amount = 31; | ||
| 4457 | |||
| 4458 | if (shift_type == 0) | ||
| 4459 | rn_val <<= shift_amount; | ||
| 4460 | else if (shift_type == 1) | ||
| 4461 | rn_val = ((s32)rn_val >> shift_amount); | ||
| 4462 | |||
| 4463 | bool saturated = false; | ||
| 4464 | rn_val = ARMul_UnsignedSatQ(rn_val, inst_cream->sat_imm, &saturated); | ||
| 4465 | |||
| 4466 | if (saturated) | ||
| 4467 | cpu->Cpsr |= (1 << 27); | ||
| 4468 | |||
| 4469 | RD = rn_val; | ||
| 4470 | } | ||
| 4471 | |||
| 4472 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4473 | INC_PC(sizeof(ssat_inst)); | ||
| 4474 | FETCH_INST; | ||
| 4475 | GOTO_NEXT_INST; | ||
| 4476 | } | ||
| 4477 | |||
| 4478 | USAT16_INST : { | ||
| 4479 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4480 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 4481 | const u8 saturate_to = inst_cream->sat_imm; | ||
| 4482 | |||
| 4483 | bool sat1 = false; | ||
| 4484 | bool sat2 = false; | ||
| 4485 | |||
| 4486 | RD = (ARMul_UnsignedSatQ((s16)RN, saturate_to, &sat1) & 0xFFFF) | | ||
| 4487 | ARMul_UnsignedSatQ((s32)RN >> 16, saturate_to, &sat2) << 16; | ||
| 4488 | |||
| 4489 | if (sat1 || sat2) | ||
| 4490 | cpu->Cpsr |= (1 << 27); | ||
| 4491 | } | ||
| 4492 | |||
| 4493 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4494 | INC_PC(sizeof(ssat_inst)); | ||
| 4495 | FETCH_INST; | ||
| 4496 | GOTO_NEXT_INST; | ||
| 4497 | } | ||
| 4498 | |||
| 4499 | UXTAB16_INST: | ||
| 4500 | UXTB16_INST : { | ||
| 4501 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4502 | uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component; | ||
| 4503 | |||
| 4504 | const u8 rn_idx = inst_cream->Rn; | ||
| 4505 | const u32 rm_val = RM; | ||
| 4506 | const u32 rotation = inst_cream->rotate * 8; | ||
| 4507 | const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation)); | ||
| 4508 | |||
| 4509 | // UXTB16, otherwise UXTAB16 | ||
| 4510 | if (rn_idx == 15) { | ||
| 4511 | RD = rotated_rm & 0x00FF00FF; | ||
| 4512 | } else { | ||
| 4513 | const u32 rn_val = RN; | ||
| 4514 | const u8 lo_rotated = (rotated_rm & 0xFF); | ||
| 4515 | const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated; | ||
| 4516 | const u8 hi_rotated = (rotated_rm >> 16) & 0xFF; | ||
| 4517 | const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated; | ||
| 4518 | |||
| 4519 | RD = ((hi_result << 16) | (lo_result & 0xFFFF)); | ||
| 4520 | } | ||
| 4521 | } | ||
| 4522 | |||
| 4523 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4524 | INC_PC(sizeof(uxtab_inst)); | ||
| 4525 | FETCH_INST; | ||
| 4526 | GOTO_NEXT_INST; | ||
| 4527 | } | ||
| 4528 | |||
| 4529 | WFE_INST : { | ||
| 4530 | // Stubbed, as WFE is a hint instruction. | ||
| 4531 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4532 | LOG_TRACE(Core_ARM, "WFE executed."); | ||
| 4533 | } | ||
| 4534 | |||
| 4535 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4536 | INC_PC_STUB; | ||
| 4537 | FETCH_INST; | ||
| 4538 | GOTO_NEXT_INST; | ||
| 4539 | } | ||
| 4540 | |||
| 4541 | WFI_INST : { | ||
| 4542 | // Stubbed, as WFI is a hint instruction. | ||
| 4543 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4544 | LOG_TRACE(Core_ARM, "WFI executed."); | ||
| 4545 | } | ||
| 4546 | |||
| 4547 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4548 | INC_PC_STUB; | ||
| 4549 | FETCH_INST; | ||
| 4550 | GOTO_NEXT_INST; | ||
| 4551 | } | ||
| 4552 | |||
| 4553 | YIELD_INST : { | ||
| 4554 | // Stubbed, as YIELD is a hint instruction. | ||
| 4555 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 4556 | LOG_TRACE(Core_ARM, "YIELD executed."); | ||
| 4557 | } | ||
| 4558 | |||
| 4559 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 4560 | INC_PC_STUB; | ||
| 4561 | FETCH_INST; | ||
| 4562 | GOTO_NEXT_INST; | ||
| 4563 | } | ||
| 4564 | |||
| 4565 | #define VFP_INTERPRETER_IMPL | ||
| 4566 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 4567 | #undef VFP_INTERPRETER_IMPL | ||
| 4568 | |||
| 4569 | END : { | ||
| 4570 | SAVE_NZCVT; | ||
| 4571 | cpu->NumInstrsToExecute = 0; | ||
| 4572 | return num_instrs; | ||
| 4573 | } | ||
| 4574 | INIT_INST_LENGTH : { | ||
| 4575 | cpu->NumInstrsToExecute = 0; | ||
| 4576 | return num_instrs; | ||
| 4577 | } | ||
| 4578 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h deleted file mode 100644 index 7a46dcc94..000000000 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.h +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | struct ARMul_State; | ||
| 8 | |||
| 9 | unsigned InterpreterMainLoop(ARMul_State* state); | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h deleted file mode 100644 index 8eb694fee..000000000 --- a/src/core/arm/dyncom/arm_dyncom_run.h +++ /dev/null | |||
| @@ -1,48 +0,0 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of the GNU General Public License | ||
| 5 | * as published by the Free Software Foundation; either version 2 | ||
| 6 | * of the License, or (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program; if not, write to the Free Software | ||
| 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #pragma once | ||
| 20 | |||
| 21 | #include "core/arm/skyeye_common/armstate.h" | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Checks if the PC is being read, and if so, word-aligns it. | ||
| 25 | * Used with address calculations. | ||
| 26 | * | ||
| 27 | * @param cpu The ARM CPU state instance. | ||
| 28 | * @param Rn The register being read. | ||
| 29 | * | ||
| 30 | * @return If the PC is being read, then the word-aligned PC value is returned. | ||
| 31 | * If the PC is not being read, then the value stored in the register is returned. | ||
| 32 | */ | ||
| 33 | inline u32 CHECK_READ_REG15_WA(const ARMul_State* cpu, int Rn) { | ||
| 34 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Reads the PC. Used for data processing operations that use the PC. | ||
| 39 | * | ||
| 40 | * @param cpu The ARM CPU state instance. | ||
| 41 | * @param Rn The register being read. | ||
| 42 | * | ||
| 43 | * @return If the PC is being read, then the incremented PC value is returned. | ||
| 44 | * If the PC is not being read, then the values stored in the register is returned. | ||
| 45 | */ | ||
| 46 | inline u32 CHECK_READ_REG15(const ARMul_State* cpu, int Rn) { | ||
| 47 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | ||
| 48 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp deleted file mode 100644 index 2a3dd0f53..000000000 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ /dev/null | |||
| @@ -1,390 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | |||
| 7 | // We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding | ||
| 8 | // ARM instruction, and using the existing ARM simulator. | ||
| 9 | |||
| 10 | #include "core/arm/dyncom/arm_dyncom_thumb.h" | ||
| 11 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 12 | |||
| 13 | // Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, | ||
| 14 | // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions | ||
| 15 | // allows easier simulation of the special dual BL instruction. | ||
| 16 | |||
| 17 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { | ||
| 18 | ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED; | ||
| 19 | u32 tinstr = GetThumbInstruction(instr, addr); | ||
| 20 | |||
| 21 | *ainstr = 0xDEADC0DE; // Debugging to catch non updates | ||
| 22 | |||
| 23 | switch ((tinstr & 0xF800) >> 11) { | ||
| 24 | case 0: // LSL | ||
| 25 | case 1: // LSR | ||
| 26 | case 2: // ASR | ||
| 27 | *ainstr = 0xE1B00000 // base opcode | ||
| 28 | | ((tinstr & 0x1800) >> (11 - 5)) // shift type | ||
| 29 | | ((tinstr & 0x07C0) << (7 - 6)) // imm5 | ||
| 30 | | ((tinstr & 0x0038) >> 3) // Rs | ||
| 31 | | ((tinstr & 0x0007) << 12); // Rd | ||
| 32 | break; | ||
| 33 | |||
| 34 | case 3: // ADD/SUB | ||
| 35 | { | ||
| 36 | static const u32 subset[4] = { | ||
| 37 | 0xE0900000, // ADDS Rd,Rs,Rn | ||
| 38 | 0xE0500000, // SUBS Rd,Rs,Rn | ||
| 39 | 0xE2900000, // ADDS Rd,Rs,#imm3 | ||
| 40 | 0xE2500000 // SUBS Rd,Rs,#imm3 | ||
| 41 | }; | ||
| 42 | // It is quicker indexing into a table, than performing switch or conditionals: | ||
| 43 | *ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode | ||
| 44 | | ((tinstr & 0x01C0) >> 6) // Rn or imm3 | ||
| 45 | | ((tinstr & 0x0038) << (16 - 3)) // Rs | ||
| 46 | | ((tinstr & 0x0007) << (12 - 0)); // Rd | ||
| 47 | } break; | ||
| 48 | |||
| 49 | case 4: // MOV | ||
| 50 | case 5: // CMP | ||
| 51 | case 6: // ADD | ||
| 52 | case 7: // SUB | ||
| 53 | { | ||
| 54 | static const u32 subset[4] = { | ||
| 55 | 0xE3B00000, // MOVS Rd,#imm8 | ||
| 56 | 0xE3500000, // CMP Rd,#imm8 | ||
| 57 | 0xE2900000, // ADDS Rd,Rd,#imm8 | ||
| 58 | 0xE2500000, // SUBS Rd,Rd,#imm8 | ||
| 59 | }; | ||
| 60 | |||
| 61 | *ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode | ||
| 62 | | ((tinstr & 0x00FF) >> 0) // imm8 | ||
| 63 | | ((tinstr & 0x0700) << (16 - 8)) // Rn | ||
| 64 | | ((tinstr & 0x0700) << (12 - 8)); // Rd | ||
| 65 | } break; | ||
| 66 | |||
| 67 | case 8: // Arithmetic and high register transfers | ||
| 68 | |||
| 69 | // TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of | ||
| 70 | // different ARM encodings, we could save the following conditional, and just have one | ||
| 71 | // large subset | ||
| 72 | |||
| 73 | if ((tinstr & (1 << 10)) == 0) { | ||
| 74 | enum otype { t_norm, t_shift, t_neg, t_mul }; | ||
| 75 | |||
| 76 | static const struct { | ||
| 77 | u32 opcode; | ||
| 78 | otype type; | ||
| 79 | } subset[16] = { | ||
| 80 | {0xE0100000, t_norm}, // ANDS Rd,Rd,Rs | ||
| 81 | {0xE0300000, t_norm}, // EORS Rd,Rd,Rs | ||
| 82 | {0xE1B00010, t_shift}, // MOVS Rd,Rd,LSL Rs | ||
| 83 | {0xE1B00030, t_shift}, // MOVS Rd,Rd,LSR Rs | ||
| 84 | {0xE1B00050, t_shift}, // MOVS Rd,Rd,ASR Rs | ||
| 85 | {0xE0B00000, t_norm}, // ADCS Rd,Rd,Rs | ||
| 86 | {0xE0D00000, t_norm}, // SBCS Rd,Rd,Rs | ||
| 87 | {0xE1B00070, t_shift}, // MOVS Rd,Rd,ROR Rs | ||
| 88 | {0xE1100000, t_norm}, // TST Rd,Rs | ||
| 89 | {0xE2700000, t_neg}, // RSBS Rd,Rs,#0 | ||
| 90 | {0xE1500000, t_norm}, // CMP Rd,Rs | ||
| 91 | {0xE1700000, t_norm}, // CMN Rd,Rs | ||
| 92 | {0xE1900000, t_norm}, // ORRS Rd,Rd,Rs | ||
| 93 | {0xE0100090, t_mul}, // MULS Rd,Rd,Rs | ||
| 94 | {0xE1D00000, t_norm}, // BICS Rd,Rd,Rs | ||
| 95 | {0xE1F00000, t_norm} // MVNS Rd,Rs | ||
| 96 | }; | ||
| 97 | |||
| 98 | *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base | ||
| 99 | |||
| 100 | switch (subset[(tinstr & 0x03C0) >> 6].type) { | ||
| 101 | case t_norm: | ||
| 102 | *ainstr |= ((tinstr & 0x0007) << 16) // Rn | ||
| 103 | | ((tinstr & 0x0007) << 12) // Rd | ||
| 104 | | ((tinstr & 0x0038) >> 3); // Rs | ||
| 105 | break; | ||
| 106 | case t_shift: | ||
| 107 | *ainstr |= ((tinstr & 0x0007) << 12) // Rd | ||
| 108 | | ((tinstr & 0x0007) >> 0) // Rm | ||
| 109 | | ((tinstr & 0x0038) << (8 - 3)); // Rs | ||
| 110 | break; | ||
| 111 | case t_neg: | ||
| 112 | *ainstr |= ((tinstr & 0x0007) << 12) // Rd | ||
| 113 | | ((tinstr & 0x0038) << (16 - 3)); // Rn | ||
| 114 | break; | ||
| 115 | case t_mul: | ||
| 116 | *ainstr |= ((tinstr & 0x0007) << 16) // Rd | ||
| 117 | | ((tinstr & 0x0007) << 8) // Rs | ||
| 118 | | ((tinstr & 0x0038) >> 3); // Rm | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | } else { | ||
| 122 | u32 Rd = ((tinstr & 0x0007) >> 0); | ||
| 123 | u32 Rs = ((tinstr & 0x0078) >> 3); | ||
| 124 | |||
| 125 | if (tinstr & (1 << 7)) | ||
| 126 | Rd += 8; | ||
| 127 | |||
| 128 | switch ((tinstr & 0x03C0) >> 6) { | ||
| 129 | case 0x0: // ADD Rd,Rd,Rs | ||
| 130 | case 0x1: // ADD Rd,Rd,Hs | ||
| 131 | case 0x2: // ADD Hd,Hd,Rs | ||
| 132 | case 0x3: // ADD Hd,Hd,Hs | ||
| 133 | *ainstr = 0xE0800000 // base | ||
| 134 | | (Rd << 16) // Rn | ||
| 135 | | (Rd << 12) // Rd | ||
| 136 | | (Rs << 0); // Rm | ||
| 137 | break; | ||
| 138 | case 0x4: // CMP Rd,Rs | ||
| 139 | case 0x5: // CMP Rd,Hs | ||
| 140 | case 0x6: // CMP Hd,Rs | ||
| 141 | case 0x7: // CMP Hd,Hs | ||
| 142 | *ainstr = 0xE1500000 // base | ||
| 143 | | (Rd << 16) // Rn | ||
| 144 | | (Rs << 0); // Rm | ||
| 145 | break; | ||
| 146 | case 0x8: // MOV Rd,Rs | ||
| 147 | case 0x9: // MOV Rd,Hs | ||
| 148 | case 0xA: // MOV Hd,Rs | ||
| 149 | case 0xB: // MOV Hd,Hs | ||
| 150 | *ainstr = 0xE1A00000 // base | ||
| 151 | | (Rd << 12) // Rd | ||
| 152 | | (Rs << 0); // Rm | ||
| 153 | break; | ||
| 154 | case 0xC: // BX Rs | ||
| 155 | case 0xD: // BX Hs | ||
| 156 | *ainstr = 0xE12FFF10 // base | ||
| 157 | | ((tinstr & 0x0078) >> 3); // Rd | ||
| 158 | break; | ||
| 159 | case 0xE: // BLX | ||
| 160 | case 0xF: // BLX | ||
| 161 | *ainstr = 0xE1200030 // base | ||
| 162 | | (Rs << 0); // Rm | ||
| 163 | break; | ||
| 164 | } | ||
| 165 | } | ||
| 166 | break; | ||
| 167 | |||
| 168 | case 9: // LDR Rd,[PC,#imm8] | ||
| 169 | *ainstr = 0xE59F0000 // base | ||
| 170 | | ((tinstr & 0x0700) << (12 - 8)) // Rd | ||
| 171 | | ((tinstr & 0x00FF) << (2 - 0)); // off8 | ||
| 172 | break; | ||
| 173 | |||
| 174 | case 10: | ||
| 175 | case 11: { | ||
| 176 | static const u32 subset[8] = { | ||
| 177 | 0xE7800000, // STR Rd,[Rb,Ro] | ||
| 178 | 0xE18000B0, // STRH Rd,[Rb,Ro] | ||
| 179 | 0xE7C00000, // STRB Rd,[Rb,Ro] | ||
| 180 | 0xE19000D0, // LDRSB Rd,[Rb,Ro] | ||
| 181 | 0xE7900000, // LDR Rd,[Rb,Ro] | ||
| 182 | 0xE19000B0, // LDRH Rd,[Rb,Ro] | ||
| 183 | 0xE7D00000, // LDRB Rd,[Rb,Ro] | ||
| 184 | 0xE19000F0 // LDRSH Rd,[Rb,Ro] | ||
| 185 | }; | ||
| 186 | |||
| 187 | *ainstr = subset[(tinstr & 0xE00) >> 9] // base | ||
| 188 | | ((tinstr & 0x0007) << (12 - 0)) // Rd | ||
| 189 | | ((tinstr & 0x0038) << (16 - 3)) // Rb | ||
| 190 | | ((tinstr & 0x01C0) >> 6); // Ro | ||
| 191 | } break; | ||
| 192 | |||
| 193 | case 12: // STR Rd,[Rb,#imm5] | ||
| 194 | case 13: // LDR Rd,[Rb,#imm5] | ||
| 195 | case 14: // STRB Rd,[Rb,#imm5] | ||
| 196 | case 15: // LDRB Rd,[Rb,#imm5] | ||
| 197 | { | ||
| 198 | static const u32 subset[4] = { | ||
| 199 | 0xE5800000, // STR Rd,[Rb,#imm5] | ||
| 200 | 0xE5900000, // LDR Rd,[Rb,#imm5] | ||
| 201 | 0xE5C00000, // STRB Rd,[Rb,#imm5] | ||
| 202 | 0xE5D00000 // LDRB Rd,[Rb,#imm5] | ||
| 203 | }; | ||
| 204 | // The offset range defends on whether we are transferring a byte or word value: | ||
| 205 | *ainstr = subset[(tinstr & 0x1800) >> 11] // base | ||
| 206 | | ((tinstr & 0x0007) << (12 - 0)) // Rd | ||
| 207 | | ((tinstr & 0x0038) << (16 - 3)) // Rb | ||
| 208 | | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5 | ||
| 209 | } break; | ||
| 210 | |||
| 211 | case 16: // STRH Rd,[Rb,#imm5] | ||
| 212 | case 17: // LDRH Rd,[Rb,#imm5] | ||
| 213 | *ainstr = ((tinstr & (1 << 11)) // base | ||
| 214 | ? 0xE1D000B0 // LDRH | ||
| 215 | : 0xE1C000B0) // STRH | ||
| 216 | | ((tinstr & 0x0007) << (12 - 0)) // Rd | ||
| 217 | | ((tinstr & 0x0038) << (16 - 3)) // Rb | ||
| 218 | | ((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble | ||
| 219 | | ((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble | ||
| 220 | break; | ||
| 221 | |||
| 222 | case 18: // STR Rd,[SP,#imm8] | ||
| 223 | case 19: // LDR Rd,[SP,#imm8] | ||
| 224 | *ainstr = ((tinstr & (1 << 11)) // base | ||
| 225 | ? 0xE59D0000 // LDR | ||
| 226 | : 0xE58D0000) // STR | ||
| 227 | | ((tinstr & 0x0700) << (12 - 8)) // Rd | ||
| 228 | | ((tinstr & 0x00FF) << 2); // off8 | ||
| 229 | break; | ||
| 230 | |||
| 231 | case 20: // ADD Rd,PC,#imm8 | ||
| 232 | case 21: // ADD Rd,SP,#imm8 | ||
| 233 | |||
| 234 | if ((tinstr & (1 << 11)) == 0) { | ||
| 235 | |||
| 236 | // NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the | ||
| 237 | // rotate immediate field, so no shift of off8 is needed. | ||
| 238 | |||
| 239 | *ainstr = 0xE28F0F00 // base | ||
| 240 | | ((tinstr & 0x0700) << (12 - 8)) // Rd | ||
| 241 | | (tinstr & 0x00FF); // off8 | ||
| 242 | } else { | ||
| 243 | // We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is | ||
| 244 | // needed. | ||
| 245 | *ainstr = 0xE28D0F00 // base | ||
| 246 | | ((tinstr & 0x0700) << (12 - 8)) // Rd | ||
| 247 | | (tinstr & 0x00FF); // off8 | ||
| 248 | } | ||
| 249 | break; | ||
| 250 | |||
| 251 | case 22: | ||
| 252 | case 23: | ||
| 253 | if ((tinstr & 0x0F00) == 0x0000) { | ||
| 254 | // NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30): | ||
| 255 | *ainstr = ((tinstr & (1 << 7)) // base | ||
| 256 | ? 0xE24DDF00 // SUB | ||
| 257 | : 0xE28DDF00) // ADD | ||
| 258 | | (tinstr & 0x007F); // off7 | ||
| 259 | } else if ((tinstr & 0x0F00) == 0x0e00) { | ||
| 260 | // BKPT | ||
| 261 | *ainstr = 0xEF000000 // base | ||
| 262 | | BITS(tinstr, 0, 3) // imm4 field; | ||
| 263 | | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12 | ||
| 264 | } else if ((tinstr & 0x0F00) == 0x0200) { | ||
| 265 | static const u32 subset[4] = { | ||
| 266 | 0xE6BF0070, // SXTH | ||
| 267 | 0xE6AF0070, // SXTB | ||
| 268 | 0xE6FF0070, // UXTH | ||
| 269 | 0xE6EF0070, // UXTB | ||
| 270 | }; | ||
| 271 | |||
| 272 | *ainstr = subset[BITS(tinstr, 6, 7)] // base | ||
| 273 | | (BITS(tinstr, 0, 2) << 12) // Rd | ||
| 274 | | BITS(tinstr, 3, 5); // Rm | ||
| 275 | } else if ((tinstr & 0x0F00) == 0x600) { | ||
| 276 | if (BIT(tinstr, 5) == 0) { | ||
| 277 | // SETEND | ||
| 278 | *ainstr = 0xF1010000 // base | ||
| 279 | | (BIT(tinstr, 3) << 9); // endian specifier | ||
| 280 | } else { | ||
| 281 | // CPS | ||
| 282 | *ainstr = 0xF1080000 // base | ||
| 283 | | (BIT(tinstr, 0) << 6) // fiq bit | ||
| 284 | | (BIT(tinstr, 1) << 7) // irq bit | ||
| 285 | | (BIT(tinstr, 2) << 8) // abort bit | ||
| 286 | | (BIT(tinstr, 4) << 18); // enable bit | ||
| 287 | } | ||
| 288 | } else if ((tinstr & 0x0F00) == 0x0a00) { | ||
| 289 | static const u32 subset[4] = { | ||
| 290 | 0xE6BF0F30, // REV | ||
| 291 | 0xE6BF0FB0, // REV16 | ||
| 292 | 0, // undefined | ||
| 293 | 0xE6FF0FB0, // REVSH | ||
| 294 | }; | ||
| 295 | |||
| 296 | size_t subset_index = BITS(tinstr, 6, 7); | ||
| 297 | |||
| 298 | if (subset_index == 2) { | ||
| 299 | valid = ThumbDecodeStatus::UNDEFINED; | ||
| 300 | } else { | ||
| 301 | *ainstr = subset[subset_index] // base | ||
| 302 | | (BITS(tinstr, 0, 2) << 12) // Rd | ||
| 303 | | BITS(tinstr, 3, 5); // Rm | ||
| 304 | } | ||
| 305 | } else { | ||
| 306 | static const u32 subset[4] = { | ||
| 307 | 0xE92D0000, // STMDB sp!,{rlist} | ||
| 308 | 0xE92D4000, // STMDB sp!,{rlist,lr} | ||
| 309 | 0xE8BD0000, // LDMIA sp!,{rlist} | ||
| 310 | 0xE8BD8000 // LDMIA sp!,{rlist,pc} | ||
| 311 | }; | ||
| 312 | *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base | ||
| 313 | | (tinstr & 0x00FF); // mask8 | ||
| 314 | } | ||
| 315 | break; | ||
| 316 | |||
| 317 | case 24: // STMIA | ||
| 318 | case 25: // LDMIA | ||
| 319 | if (tinstr & (1 << 11)) { | ||
| 320 | unsigned int base = 0xE8900000; | ||
| 321 | unsigned int rn = BITS(tinstr, 8, 10); | ||
| 322 | |||
| 323 | // Writeback | ||
| 324 | if ((tinstr & (1 << rn)) == 0) | ||
| 325 | base |= (1 << 21); | ||
| 326 | |||
| 327 | *ainstr = base // base (LDMIA) | ||
| 328 | | (rn << 16) // Rn | ||
| 329 | | (tinstr & 0x00FF); // Register list | ||
| 330 | } else { | ||
| 331 | *ainstr = 0xE8A00000 // base (STMIA) | ||
| 332 | | (BITS(tinstr, 8, 10) << 16) // Rn | ||
| 333 | | (tinstr & 0x00FF); // Register list | ||
| 334 | } | ||
| 335 | break; | ||
| 336 | |||
| 337 | case 26: // Bcc | ||
| 338 | case 27: // Bcc/SWI | ||
| 339 | if ((tinstr & 0x0F00) == 0x0F00) { | ||
| 340 | // Format 17 : SWI | ||
| 341 | *ainstr = 0xEF000000; | ||
| 342 | // Breakpoint must be handled specially. | ||
| 343 | if ((tinstr & 0x00FF) == 0x18) | ||
| 344 | *ainstr |= ((tinstr & 0x00FF) << 16); | ||
| 345 | // New breakpoint value. See gdb/arm-tdep.c | ||
| 346 | else if ((tinstr & 0x00FF) == 0xFE) | ||
| 347 | *ainstr |= 0x180000; // base |= BKPT mask | ||
| 348 | else | ||
| 349 | *ainstr |= (tinstr & 0x00FF); | ||
| 350 | } else if ((tinstr & 0x0F00) != 0x0E00) | ||
| 351 | valid = ThumbDecodeStatus::BRANCH; | ||
| 352 | else // UNDEFINED : cc=1110(AL) uses different format | ||
| 353 | valid = ThumbDecodeStatus::UNDEFINED; | ||
| 354 | |||
| 355 | break; | ||
| 356 | |||
| 357 | case 28: // B | ||
| 358 | valid = ThumbDecodeStatus::BRANCH; | ||
| 359 | break; | ||
| 360 | |||
| 361 | case 29: | ||
| 362 | if (tinstr & 0x1) | ||
| 363 | valid = ThumbDecodeStatus::UNDEFINED; | ||
| 364 | else | ||
| 365 | valid = ThumbDecodeStatus::BRANCH; | ||
| 366 | break; | ||
| 367 | |||
| 368 | case 30: // BL instruction 1 | ||
| 369 | |||
| 370 | // There is no single ARM instruction equivalent for this Thumb instruction. To keep the | ||
| 371 | // simulation simple (from the user perspective) we check if the following instruction is | ||
| 372 | // the second half of this BL, and if it is we simulate it immediately | ||
| 373 | |||
| 374 | valid = ThumbDecodeStatus::BRANCH; | ||
| 375 | break; | ||
| 376 | |||
| 377 | case 31: // BL instruction 2 | ||
| 378 | |||
| 379 | // There is no single ARM instruction equivalent for this instruction. Also, it should only | ||
| 380 | // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the | ||
| 381 | // simulation of it on its own, with undefined results if r14 is not suitably initialised. | ||
| 382 | |||
| 383 | valid = ThumbDecodeStatus::BRANCH; | ||
| 384 | break; | ||
| 385 | } | ||
| 386 | |||
| 387 | *inst_size = 2; | ||
| 388 | |||
| 389 | return valid; | ||
| 390 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h deleted file mode 100644 index 231e48aa4..000000000 --- a/src/core/arm/dyncom/arm_dyncom_thumb.h +++ /dev/null | |||
| @@ -1,49 +0,0 @@ | |||
| 1 | /* Copyright (C) | ||
| 2 | * 2011 - Michael.Kang blackfin.kang@gmail.com | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of the GNU General Public License | ||
| 5 | * as published by the Free Software Foundation; either version 2 | ||
| 6 | * of the License, or (at your option) any later version. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program; if not, write to the Free Software | ||
| 15 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | /** | ||
| 20 | * @file arm_dyncom_thumb.h | ||
| 21 | * @brief The thumb dyncom | ||
| 22 | * @author Michael.Kang blackfin.kang@gmail.com | ||
| 23 | * @version 78.77 | ||
| 24 | * @date 2011-11-07 | ||
| 25 | */ | ||
| 26 | |||
| 27 | #pragma once | ||
| 28 | |||
| 29 | #include "common/common_types.h" | ||
| 30 | |||
| 31 | enum class ThumbDecodeStatus { | ||
| 32 | UNDEFINED, // Undefined Thumb instruction | ||
| 33 | DECODED, // Instruction decoded to ARM equivalent | ||
| 34 | BRANCH, // Thumb branch (already processed) | ||
| 35 | UNINITIALIZED, | ||
| 36 | }; | ||
| 37 | |||
| 38 | // Translates a Thumb mode instruction into its ARM equivalent. | ||
| 39 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | ||
| 40 | |||
| 41 | inline u32 GetThumbInstruction(u32 instr, u32 address) { | ||
| 42 | // Normally you would need to handle instruction endianness, | ||
| 43 | // however, it is fixed to little-endian on the MPCore, so | ||
| 44 | // there's no need to check for this beforehand. | ||
| 45 | if ((address & 0x3) != 0) | ||
| 46 | return instr >> 16; | ||
| 47 | |||
| 48 | return instr & 0xFFFF; | ||
| 49 | } | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.cpp b/src/core/arm/dyncom/arm_dyncom_trans.cpp deleted file mode 100644 index 9cd6c0dea..000000000 --- a/src/core/arm/dyncom/arm_dyncom_trans.cpp +++ /dev/null | |||
| @@ -1,1887 +0,0 @@ | |||
| 1 | #include <cstdlib> | ||
| 2 | #include "common/assert.h" | ||
| 3 | #include "common/common_types.h" | ||
| 4 | #include "core/arm/dyncom/arm_dyncom_interpreter.h" | ||
| 5 | #include "core/arm/dyncom/arm_dyncom_trans.h" | ||
| 6 | #include "core/arm/skyeye_common/armstate.h" | ||
| 7 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 8 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 9 | |||
| 10 | char trans_cache_buf[TRANS_CACHE_SIZE]; | ||
| 11 | size_t trans_cache_buf_top = 0; | ||
| 12 | |||
| 13 | static void* AllocBuffer(size_t size) { | ||
| 14 | size_t start = trans_cache_buf_top; | ||
| 15 | trans_cache_buf_top += size; | ||
| 16 | ASSERT_MSG(trans_cache_buf_top <= TRANS_CACHE_SIZE, "Translation cache is full!"); | ||
| 17 | return static_cast<void*>(&trans_cache_buf[start]); | ||
| 18 | } | ||
| 19 | |||
| 20 | #define glue(x, y) x##y | ||
| 21 | #define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) | ||
| 22 | |||
| 23 | shtop_fp_t GetShifterOp(unsigned int inst); | ||
| 24 | get_addr_fp_t GetAddressingOp(unsigned int inst); | ||
| 25 | get_addr_fp_t GetAddressingOpLoadStoreT(unsigned int inst); | ||
| 26 | |||
| 27 | static ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) { | ||
| 28 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); | ||
| 29 | adc_inst* inst_cream = (adc_inst*)inst_base->component; | ||
| 30 | |||
| 31 | inst_base->cond = BITS(inst, 28, 31); | ||
| 32 | inst_base->idx = index; | ||
| 33 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 34 | |||
| 35 | inst_cream->I = BIT(inst, 25); | ||
| 36 | inst_cream->S = BIT(inst, 20); | ||
| 37 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 38 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 39 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 40 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 41 | |||
| 42 | if (inst_cream->Rd == 15) | ||
| 43 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 44 | |||
| 45 | return inst_base; | ||
| 46 | } | ||
| 47 | static ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) { | ||
| 48 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); | ||
| 49 | add_inst* inst_cream = (add_inst*)inst_base->component; | ||
| 50 | |||
| 51 | inst_base->cond = BITS(inst, 28, 31); | ||
| 52 | inst_base->idx = index; | ||
| 53 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 54 | |||
| 55 | inst_cream->I = BIT(inst, 25); | ||
| 56 | inst_cream->S = BIT(inst, 20); | ||
| 57 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 58 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 59 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 60 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 61 | |||
| 62 | if (inst_cream->Rd == 15) | ||
| 63 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 64 | |||
| 65 | return inst_base; | ||
| 66 | } | ||
| 67 | static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) { | ||
| 68 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); | ||
| 69 | and_inst* inst_cream = (and_inst*)inst_base->component; | ||
| 70 | |||
| 71 | inst_base->cond = BITS(inst, 28, 31); | ||
| 72 | inst_base->idx = index; | ||
| 73 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 74 | |||
| 75 | inst_cream->I = BIT(inst, 25); | ||
| 76 | inst_cream->S = BIT(inst, 20); | ||
| 77 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 78 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 79 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 80 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 81 | |||
| 82 | if (inst_cream->Rd == 15) | ||
| 83 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 84 | |||
| 85 | return inst_base; | ||
| 86 | } | ||
| 87 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) { | ||
| 88 | #define POSBRANCH ((inst & 0x7fffff) << 2) | ||
| 89 | #define NEGBRANCH ((0xff000000 | (inst & 0xffffff)) << 2) | ||
| 90 | |||
| 91 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); | ||
| 92 | bbl_inst* inst_cream = (bbl_inst*)inst_base->component; | ||
| 93 | |||
| 94 | inst_base->cond = BITS(inst, 28, 31); | ||
| 95 | inst_base->idx = index; | ||
| 96 | inst_base->br = TransExtData::DIRECT_BRANCH; | ||
| 97 | |||
| 98 | if (BIT(inst, 24)) | ||
| 99 | inst_base->br = TransExtData::CALL; | ||
| 100 | |||
| 101 | inst_cream->L = BIT(inst, 24); | ||
| 102 | inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; | ||
| 103 | |||
| 104 | return inst_base; | ||
| 105 | } | ||
| 106 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) { | ||
| 107 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); | ||
| 108 | bic_inst* inst_cream = (bic_inst*)inst_base->component; | ||
| 109 | |||
| 110 | inst_base->cond = BITS(inst, 28, 31); | ||
| 111 | inst_base->idx = index; | ||
| 112 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 113 | |||
| 114 | inst_cream->I = BIT(inst, 25); | ||
| 115 | inst_cream->S = BIT(inst, 20); | ||
| 116 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 117 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 118 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 119 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 120 | |||
| 121 | if (inst_cream->Rd == 15) | ||
| 122 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 123 | return inst_base; | ||
| 124 | } | ||
| 125 | |||
| 126 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) { | ||
| 127 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bkpt_inst)); | ||
| 128 | bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; | ||
| 129 | |||
| 130 | inst_base->cond = BITS(inst, 28, 31); | ||
| 131 | inst_base->idx = index; | ||
| 132 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 133 | |||
| 134 | inst_cream->imm = (BITS(inst, 8, 19) << 4) | BITS(inst, 0, 3); | ||
| 135 | |||
| 136 | return inst_base; | ||
| 137 | } | ||
| 138 | |||
| 139 | static ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) { | ||
| 140 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); | ||
| 141 | blx_inst* inst_cream = (blx_inst*)inst_base->component; | ||
| 142 | |||
| 143 | inst_base->cond = BITS(inst, 28, 31); | ||
| 144 | inst_base->idx = index; | ||
| 145 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 146 | |||
| 147 | inst_cream->inst = inst; | ||
| 148 | if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { | ||
| 149 | inst_cream->val.Rm = BITS(inst, 0, 3); | ||
| 150 | } else { | ||
| 151 | inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); | ||
| 152 | } | ||
| 153 | |||
| 154 | return inst_base; | ||
| 155 | } | ||
| 156 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) { | ||
| 157 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); | ||
| 158 | bx_inst* inst_cream = (bx_inst*)inst_base->component; | ||
| 159 | |||
| 160 | inst_base->cond = BITS(inst, 28, 31); | ||
| 161 | inst_base->idx = index; | ||
| 162 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 163 | |||
| 164 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 165 | |||
| 166 | return inst_base; | ||
| 167 | } | ||
| 168 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index) { | ||
| 169 | return INTERPRETER_TRANSLATE(bx)(inst, index); | ||
| 170 | } | ||
| 171 | |||
| 172 | static ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index) { | ||
| 173 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); | ||
| 174 | cdp_inst* inst_cream = (cdp_inst*)inst_base->component; | ||
| 175 | |||
| 176 | inst_base->cond = BITS(inst, 28, 31); | ||
| 177 | inst_base->idx = index; | ||
| 178 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 179 | |||
| 180 | inst_cream->CRm = BITS(inst, 0, 3); | ||
| 181 | inst_cream->CRd = BITS(inst, 12, 15); | ||
| 182 | inst_cream->CRn = BITS(inst, 16, 19); | ||
| 183 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 184 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 185 | inst_cream->opcode_1 = BITS(inst, 20, 23); | ||
| 186 | inst_cream->inst = inst; | ||
| 187 | |||
| 188 | LOG_TRACE(Core_ARM, "inst %x index %x", inst, index); | ||
| 189 | return inst_base; | ||
| 190 | } | ||
| 191 | static ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) { | ||
| 192 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); | ||
| 193 | inst_base->cond = BITS(inst, 28, 31); | ||
| 194 | inst_base->idx = index; | ||
| 195 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 196 | |||
| 197 | return inst_base; | ||
| 198 | } | ||
| 199 | static ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) { | ||
| 200 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); | ||
| 201 | clz_inst* inst_cream = (clz_inst*)inst_base->component; | ||
| 202 | |||
| 203 | inst_base->cond = BITS(inst, 28, 31); | ||
| 204 | inst_base->idx = index; | ||
| 205 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 206 | |||
| 207 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 208 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 209 | |||
| 210 | return inst_base; | ||
| 211 | } | ||
| 212 | static ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) { | ||
| 213 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); | ||
| 214 | cmn_inst* inst_cream = (cmn_inst*)inst_base->component; | ||
| 215 | |||
| 216 | inst_base->cond = BITS(inst, 28, 31); | ||
| 217 | inst_base->idx = index; | ||
| 218 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 219 | |||
| 220 | inst_cream->I = BIT(inst, 25); | ||
| 221 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 222 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 223 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 224 | |||
| 225 | return inst_base; | ||
| 226 | } | ||
| 227 | static ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) { | ||
| 228 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); | ||
| 229 | cmp_inst* inst_cream = (cmp_inst*)inst_base->component; | ||
| 230 | |||
| 231 | inst_base->cond = BITS(inst, 28, 31); | ||
| 232 | inst_base->idx = index; | ||
| 233 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 234 | |||
| 235 | inst_cream->I = BIT(inst, 25); | ||
| 236 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 237 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 238 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 239 | |||
| 240 | return inst_base; | ||
| 241 | } | ||
| 242 | static ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) { | ||
| 243 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); | ||
| 244 | cps_inst* inst_cream = (cps_inst*)inst_base->component; | ||
| 245 | |||
| 246 | inst_base->cond = BITS(inst, 28, 31); | ||
| 247 | inst_base->idx = index; | ||
| 248 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 249 | |||
| 250 | inst_cream->imod0 = BIT(inst, 18); | ||
| 251 | inst_cream->imod1 = BIT(inst, 19); | ||
| 252 | inst_cream->mmod = BIT(inst, 17); | ||
| 253 | inst_cream->A = BIT(inst, 8); | ||
| 254 | inst_cream->I = BIT(inst, 7); | ||
| 255 | inst_cream->F = BIT(inst, 6); | ||
| 256 | inst_cream->mode = BITS(inst, 0, 4); | ||
| 257 | |||
| 258 | return inst_base; | ||
| 259 | } | ||
| 260 | static ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) { | ||
| 261 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); | ||
| 262 | mov_inst* inst_cream = (mov_inst*)inst_base->component; | ||
| 263 | |||
| 264 | inst_base->cond = BITS(inst, 28, 31); | ||
| 265 | inst_base->idx = index; | ||
| 266 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 267 | |||
| 268 | inst_cream->I = BIT(inst, 25); | ||
| 269 | inst_cream->S = BIT(inst, 20); | ||
| 270 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 271 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 272 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 273 | |||
| 274 | if (inst_cream->Rd == 15) { | ||
| 275 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 276 | } | ||
| 277 | return inst_base; | ||
| 278 | } | ||
| 279 | static ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) { | ||
| 280 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); | ||
| 281 | eor_inst* inst_cream = (eor_inst*)inst_base->component; | ||
| 282 | |||
| 283 | inst_base->cond = BITS(inst, 28, 31); | ||
| 284 | inst_base->idx = index; | ||
| 285 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 286 | |||
| 287 | inst_cream->I = BIT(inst, 25); | ||
| 288 | inst_cream->S = BIT(inst, 20); | ||
| 289 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 290 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 291 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 292 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 293 | |||
| 294 | if (inst_cream->Rd == 15) | ||
| 295 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 296 | |||
| 297 | return inst_base; | ||
| 298 | } | ||
| 299 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) { | ||
| 300 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); | ||
| 301 | inst_base->cond = BITS(inst, 28, 31); | ||
| 302 | inst_base->idx = index; | ||
| 303 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 304 | |||
| 305 | return inst_base; | ||
| 306 | } | ||
| 307 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) { | ||
| 308 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 309 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 310 | |||
| 311 | inst_base->cond = BITS(inst, 28, 31); | ||
| 312 | inst_base->idx = index; | ||
| 313 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 314 | |||
| 315 | inst_cream->inst = inst; | ||
| 316 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 317 | |||
| 318 | if (BIT(inst, 15)) { | ||
| 319 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 320 | } | ||
| 321 | return inst_base; | ||
| 322 | } | ||
| 323 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) { | ||
| 324 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); | ||
| 325 | sxtb_inst* inst_cream = (sxtb_inst*)inst_base->component; | ||
| 326 | |||
| 327 | inst_base->cond = BITS(inst, 28, 31); | ||
| 328 | inst_base->idx = index; | ||
| 329 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 330 | |||
| 331 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 332 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 333 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 334 | |||
| 335 | return inst_base; | ||
| 336 | } | ||
| 337 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) { | ||
| 338 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 339 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 340 | |||
| 341 | inst_base->cond = BITS(inst, 28, 31); | ||
| 342 | inst_base->idx = index; | ||
| 343 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 344 | |||
| 345 | inst_cream->inst = inst; | ||
| 346 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 347 | |||
| 348 | if (BITS(inst, 12, 15) == 15) | ||
| 349 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 350 | |||
| 351 | return inst_base; | ||
| 352 | } | ||
| 353 | |||
| 354 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) { | ||
| 355 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 356 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 357 | |||
| 358 | inst_base->cond = BITS(inst, 28, 31); | ||
| 359 | inst_base->idx = index; | ||
| 360 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 361 | |||
| 362 | inst_cream->inst = inst; | ||
| 363 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 364 | |||
| 365 | if (BITS(inst, 12, 15) == 15) | ||
| 366 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 367 | |||
| 368 | return inst_base; | ||
| 369 | } | ||
| 370 | |||
| 371 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) { | ||
| 372 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); | ||
| 373 | uxth_inst* inst_cream = (uxth_inst*)inst_base->component; | ||
| 374 | |||
| 375 | inst_base->cond = BITS(inst, 28, 31); | ||
| 376 | inst_base->idx = index; | ||
| 377 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 378 | |||
| 379 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 380 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 381 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 382 | |||
| 383 | return inst_base; | ||
| 384 | } | ||
| 385 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) { | ||
| 386 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); | ||
| 387 | uxtah_inst* inst_cream = (uxtah_inst*)inst_base->component; | ||
| 388 | |||
| 389 | inst_base->cond = BITS(inst, 28, 31); | ||
| 390 | inst_base->idx = index; | ||
| 391 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 392 | |||
| 393 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 394 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 395 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 396 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 397 | |||
| 398 | return inst_base; | ||
| 399 | } | ||
| 400 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) { | ||
| 401 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 402 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 403 | |||
| 404 | inst_base->cond = BITS(inst, 28, 31); | ||
| 405 | inst_base->idx = index; | ||
| 406 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 407 | |||
| 408 | inst_cream->inst = inst; | ||
| 409 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 410 | |||
| 411 | return inst_base; | ||
| 412 | } | ||
| 413 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) { | ||
| 414 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 415 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 416 | |||
| 417 | inst_base->cond = BITS(inst, 28, 31); | ||
| 418 | inst_base->idx = index; | ||
| 419 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 420 | |||
| 421 | inst_cream->inst = inst; | ||
| 422 | inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); | ||
| 423 | |||
| 424 | return inst_base; | ||
| 425 | } | ||
| 426 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) { | ||
| 427 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 428 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 429 | |||
| 430 | inst_base->cond = BITS(inst, 28, 31); | ||
| 431 | inst_base->idx = index; | ||
| 432 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 433 | |||
| 434 | inst_cream->inst = inst; | ||
| 435 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 436 | |||
| 437 | return inst_base; | ||
| 438 | } | ||
| 439 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) { | ||
| 440 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 441 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 442 | |||
| 443 | inst_base->cond = BITS(inst, 28, 31); | ||
| 444 | inst_base->idx = index; | ||
| 445 | inst_base->br = (BITS(inst, 12, 15) == 15) ? TransExtData::INDIRECT_BRANCH | ||
| 446 | : TransExtData::NON_BRANCH; // Branch if dest is R15 | ||
| 447 | |||
| 448 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 449 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 450 | |||
| 451 | return inst_base; | ||
| 452 | } | ||
| 453 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) { | ||
| 454 | return INTERPRETER_TRANSLATE(ldrex)(inst, index); | ||
| 455 | } | ||
| 456 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexh)(unsigned int inst, int index) { | ||
| 457 | return INTERPRETER_TRANSLATE(ldrex)(inst, index); | ||
| 458 | } | ||
| 459 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexd)(unsigned int inst, int index) { | ||
| 460 | return INTERPRETER_TRANSLATE(ldrex)(inst, index); | ||
| 461 | } | ||
| 462 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) { | ||
| 463 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 464 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 465 | |||
| 466 | inst_base->cond = BITS(inst, 28, 31); | ||
| 467 | inst_base->idx = index; | ||
| 468 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 469 | |||
| 470 | inst_cream->inst = inst; | ||
| 471 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 472 | |||
| 473 | return inst_base; | ||
| 474 | } | ||
| 475 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) { | ||
| 476 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 477 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 478 | |||
| 479 | inst_base->cond = BITS(inst, 28, 31); | ||
| 480 | inst_base->idx = index; | ||
| 481 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 482 | |||
| 483 | inst_cream->inst = inst; | ||
| 484 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 485 | |||
| 486 | return inst_base; | ||
| 487 | } | ||
| 488 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) { | ||
| 489 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 490 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 491 | |||
| 492 | inst_base->cond = BITS(inst, 28, 31); | ||
| 493 | inst_base->idx = index; | ||
| 494 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 495 | |||
| 496 | inst_cream->inst = inst; | ||
| 497 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 498 | |||
| 499 | return inst_base; | ||
| 500 | } | ||
| 501 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) { | ||
| 502 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 503 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 504 | |||
| 505 | inst_base->cond = BITS(inst, 28, 31); | ||
| 506 | inst_base->idx = index; | ||
| 507 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 508 | |||
| 509 | inst_cream->inst = inst; | ||
| 510 | inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); | ||
| 511 | |||
| 512 | if (BITS(inst, 12, 15) == 15) { | ||
| 513 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 514 | } | ||
| 515 | return inst_base; | ||
| 516 | } | ||
| 517 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) { | ||
| 518 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); | ||
| 519 | mcr_inst* inst_cream = (mcr_inst*)inst_base->component; | ||
| 520 | inst_base->cond = BITS(inst, 28, 31); | ||
| 521 | inst_base->idx = index; | ||
| 522 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 523 | |||
| 524 | inst_cream->crn = BITS(inst, 16, 19); | ||
| 525 | inst_cream->crm = BITS(inst, 0, 3); | ||
| 526 | inst_cream->opcode_1 = BITS(inst, 21, 23); | ||
| 527 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 528 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 529 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 530 | inst_cream->inst = inst; | ||
| 531 | return inst_base; | ||
| 532 | } | ||
| 533 | |||
| 534 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) { | ||
| 535 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mcrr_inst)); | ||
| 536 | mcrr_inst* const inst_cream = (mcrr_inst*)inst_base->component; | ||
| 537 | |||
| 538 | inst_base->cond = BITS(inst, 28, 31); | ||
| 539 | inst_base->idx = index; | ||
| 540 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 541 | |||
| 542 | inst_cream->crm = BITS(inst, 0, 3); | ||
| 543 | inst_cream->opcode_1 = BITS(inst, 4, 7); | ||
| 544 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 545 | inst_cream->rt = BITS(inst, 12, 15); | ||
| 546 | inst_cream->rt2 = BITS(inst, 16, 19); | ||
| 547 | |||
| 548 | return inst_base; | ||
| 549 | } | ||
| 550 | |||
| 551 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) { | ||
| 552 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); | ||
| 553 | mla_inst* inst_cream = (mla_inst*)inst_base->component; | ||
| 554 | |||
| 555 | inst_base->cond = BITS(inst, 28, 31); | ||
| 556 | inst_base->idx = index; | ||
| 557 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 558 | |||
| 559 | inst_cream->S = BIT(inst, 20); | ||
| 560 | inst_cream->Rn = BITS(inst, 12, 15); | ||
| 561 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 562 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 563 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 564 | |||
| 565 | return inst_base; | ||
| 566 | } | ||
| 567 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) { | ||
| 568 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); | ||
| 569 | mov_inst* inst_cream = (mov_inst*)inst_base->component; | ||
| 570 | |||
| 571 | inst_base->cond = BITS(inst, 28, 31); | ||
| 572 | inst_base->idx = index; | ||
| 573 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 574 | |||
| 575 | inst_cream->I = BIT(inst, 25); | ||
| 576 | inst_cream->S = BIT(inst, 20); | ||
| 577 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 578 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 579 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 580 | |||
| 581 | if (inst_cream->Rd == 15) { | ||
| 582 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 583 | } | ||
| 584 | return inst_base; | ||
| 585 | } | ||
| 586 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) { | ||
| 587 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); | ||
| 588 | mrc_inst* inst_cream = (mrc_inst*)inst_base->component; | ||
| 589 | inst_base->cond = BITS(inst, 28, 31); | ||
| 590 | inst_base->idx = index; | ||
| 591 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 592 | |||
| 593 | inst_cream->crn = BITS(inst, 16, 19); | ||
| 594 | inst_cream->crm = BITS(inst, 0, 3); | ||
| 595 | inst_cream->opcode_1 = BITS(inst, 21, 23); | ||
| 596 | inst_cream->opcode_2 = BITS(inst, 5, 7); | ||
| 597 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 598 | inst_cream->cp_num = BITS(inst, 8, 11); | ||
| 599 | inst_cream->inst = inst; | ||
| 600 | return inst_base; | ||
| 601 | } | ||
| 602 | |||
| 603 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index) { | ||
| 604 | return INTERPRETER_TRANSLATE(mcrr)(inst, index); | ||
| 605 | } | ||
| 606 | |||
| 607 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) { | ||
| 608 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); | ||
| 609 | mrs_inst* inst_cream = (mrs_inst*)inst_base->component; | ||
| 610 | |||
| 611 | inst_base->cond = BITS(inst, 28, 31); | ||
| 612 | inst_base->idx = index; | ||
| 613 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 614 | |||
| 615 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 616 | inst_cream->R = BIT(inst, 22); | ||
| 617 | |||
| 618 | return inst_base; | ||
| 619 | } | ||
| 620 | static ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) { | ||
| 621 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); | ||
| 622 | msr_inst* inst_cream = (msr_inst*)inst_base->component; | ||
| 623 | |||
| 624 | inst_base->cond = BITS(inst, 28, 31); | ||
| 625 | inst_base->idx = index; | ||
| 626 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 627 | |||
| 628 | inst_cream->field_mask = BITS(inst, 16, 19); | ||
| 629 | inst_cream->R = BIT(inst, 22); | ||
| 630 | inst_cream->inst = inst; | ||
| 631 | |||
| 632 | return inst_base; | ||
| 633 | } | ||
| 634 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) { | ||
| 635 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); | ||
| 636 | mul_inst* inst_cream = (mul_inst*)inst_base->component; | ||
| 637 | |||
| 638 | inst_base->cond = BITS(inst, 28, 31); | ||
| 639 | inst_base->idx = index; | ||
| 640 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 641 | |||
| 642 | inst_cream->S = BIT(inst, 20); | ||
| 643 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 644 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 645 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 646 | |||
| 647 | return inst_base; | ||
| 648 | } | ||
| 649 | static ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) { | ||
| 650 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); | ||
| 651 | mvn_inst* inst_cream = (mvn_inst*)inst_base->component; | ||
| 652 | |||
| 653 | inst_base->cond = BITS(inst, 28, 31); | ||
| 654 | inst_base->idx = index; | ||
| 655 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 656 | |||
| 657 | inst_cream->I = BIT(inst, 25); | ||
| 658 | inst_cream->S = BIT(inst, 20); | ||
| 659 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 660 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 661 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 662 | |||
| 663 | if (inst_cream->Rd == 15) { | ||
| 664 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 665 | } | ||
| 666 | return inst_base; | ||
| 667 | } | ||
| 668 | static ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) { | ||
| 669 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); | ||
| 670 | orr_inst* inst_cream = (orr_inst*)inst_base->component; | ||
| 671 | |||
| 672 | inst_base->cond = BITS(inst, 28, 31); | ||
| 673 | inst_base->idx = index; | ||
| 674 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 675 | |||
| 676 | inst_cream->I = BIT(inst, 25); | ||
| 677 | inst_cream->S = BIT(inst, 20); | ||
| 678 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 679 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 680 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 681 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 682 | |||
| 683 | if (inst_cream->Rd == 15) | ||
| 684 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 685 | |||
| 686 | return inst_base; | ||
| 687 | } | ||
| 688 | |||
| 689 | // NOP introduced in ARMv6K. | ||
| 690 | static ARM_INST_PTR INTERPRETER_TRANSLATE(nop)(unsigned int inst, int index) { | ||
| 691 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); | ||
| 692 | |||
| 693 | inst_base->cond = BITS(inst, 28, 31); | ||
| 694 | inst_base->idx = index; | ||
| 695 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 696 | |||
| 697 | return inst_base; | ||
| 698 | } | ||
| 699 | |||
| 700 | static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index) { | ||
| 701 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst)); | ||
| 702 | pkh_inst* inst_cream = (pkh_inst*)inst_base->component; | ||
| 703 | |||
| 704 | inst_base->cond = BITS(inst, 28, 31); | ||
| 705 | inst_base->idx = index; | ||
| 706 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 707 | |||
| 708 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 709 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 710 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 711 | inst_cream->imm = BITS(inst, 7, 11); | ||
| 712 | |||
| 713 | return inst_base; | ||
| 714 | } | ||
| 715 | |||
| 716 | static ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index) { | ||
| 717 | return INTERPRETER_TRANSLATE(pkhbt)(inst, index); | ||
| 718 | } | ||
| 719 | |||
| 720 | static ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) { | ||
| 721 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); | ||
| 722 | |||
| 723 | inst_base->cond = BITS(inst, 28, 31); | ||
| 724 | inst_base->idx = index; | ||
| 725 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 726 | |||
| 727 | return inst_base; | ||
| 728 | } | ||
| 729 | |||
| 730 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) { | ||
| 731 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 732 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 733 | |||
| 734 | inst_base->cond = BITS(inst, 28, 31); | ||
| 735 | inst_base->idx = index; | ||
| 736 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 737 | |||
| 738 | inst_cream->op1 = BITS(inst, 21, 22); | ||
| 739 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 740 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 741 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 742 | |||
| 743 | return inst_base; | ||
| 744 | } | ||
| 745 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index) { | ||
| 746 | return INTERPRETER_TRANSLATE(qadd)(inst, index); | ||
| 747 | } | ||
| 748 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index) { | ||
| 749 | return INTERPRETER_TRANSLATE(qadd)(inst, index); | ||
| 750 | } | ||
| 751 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index) { | ||
| 752 | return INTERPRETER_TRANSLATE(qadd)(inst, index); | ||
| 753 | } | ||
| 754 | |||
| 755 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index) { | ||
| 756 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 757 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 758 | |||
| 759 | inst_base->cond = BITS(inst, 28, 31); | ||
| 760 | inst_base->idx = index; | ||
| 761 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 762 | |||
| 763 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 764 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 765 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 766 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 767 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 768 | |||
| 769 | return inst_base; | ||
| 770 | } | ||
| 771 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index) { | ||
| 772 | return INTERPRETER_TRANSLATE(qadd8)(inst, index); | ||
| 773 | } | ||
| 774 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index) { | ||
| 775 | return INTERPRETER_TRANSLATE(qadd8)(inst, index); | ||
| 776 | } | ||
| 777 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index) { | ||
| 778 | return INTERPRETER_TRANSLATE(qadd8)(inst, index); | ||
| 779 | } | ||
| 780 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index) { | ||
| 781 | return INTERPRETER_TRANSLATE(qadd8)(inst, index); | ||
| 782 | } | ||
| 783 | static ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index) { | ||
| 784 | return INTERPRETER_TRANSLATE(qadd8)(inst, index); | ||
| 785 | } | ||
| 786 | |||
| 787 | static ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) { | ||
| 788 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); | ||
| 789 | rev_inst* const inst_cream = (rev_inst*)inst_base->component; | ||
| 790 | |||
| 791 | inst_base->cond = BITS(inst, 28, 31); | ||
| 792 | inst_base->idx = index; | ||
| 793 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 794 | |||
| 795 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 796 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 797 | inst_cream->op1 = BITS(inst, 20, 22); | ||
| 798 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 799 | |||
| 800 | return inst_base; | ||
| 801 | } | ||
| 802 | static ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index) { | ||
| 803 | return INTERPRETER_TRANSLATE(rev)(inst, index); | ||
| 804 | } | ||
| 805 | static ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index) { | ||
| 806 | return INTERPRETER_TRANSLATE(rev)(inst, index); | ||
| 807 | } | ||
| 808 | |||
| 809 | static ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) { | ||
| 810 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 811 | ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; | ||
| 812 | |||
| 813 | inst_base->cond = AL; | ||
| 814 | inst_base->idx = index; | ||
| 815 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 816 | |||
| 817 | inst_cream->inst = inst; | ||
| 818 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 819 | |||
| 820 | return inst_base; | ||
| 821 | } | ||
| 822 | |||
| 823 | static ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) { | ||
| 824 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); | ||
| 825 | rsb_inst* inst_cream = (rsb_inst*)inst_base->component; | ||
| 826 | |||
| 827 | inst_base->cond = BITS(inst, 28, 31); | ||
| 828 | inst_base->idx = index; | ||
| 829 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 830 | |||
| 831 | inst_cream->I = BIT(inst, 25); | ||
| 832 | inst_cream->S = BIT(inst, 20); | ||
| 833 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 834 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 835 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 836 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 837 | |||
| 838 | if (inst_cream->Rd == 15) | ||
| 839 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 840 | |||
| 841 | return inst_base; | ||
| 842 | } | ||
| 843 | static ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) { | ||
| 844 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); | ||
| 845 | rsc_inst* inst_cream = (rsc_inst*)inst_base->component; | ||
| 846 | |||
| 847 | inst_base->cond = BITS(inst, 28, 31); | ||
| 848 | inst_base->idx = index; | ||
| 849 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 850 | |||
| 851 | inst_cream->I = BIT(inst, 25); | ||
| 852 | inst_cream->S = BIT(inst, 20); | ||
| 853 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 854 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 855 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 856 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 857 | |||
| 858 | if (inst_cream->Rd == 15) | ||
| 859 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 860 | |||
| 861 | return inst_base; | ||
| 862 | } | ||
| 863 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index) { | ||
| 864 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 865 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 866 | |||
| 867 | inst_base->cond = BITS(inst, 28, 31); | ||
| 868 | inst_base->idx = index; | ||
| 869 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 870 | |||
| 871 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 872 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 873 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 874 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 875 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 876 | |||
| 877 | return inst_base; | ||
| 878 | } | ||
| 879 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index) { | ||
| 880 | return INTERPRETER_TRANSLATE(sadd8)(inst, index); | ||
| 881 | } | ||
| 882 | static ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index) { | ||
| 883 | return INTERPRETER_TRANSLATE(sadd8)(inst, index); | ||
| 884 | } | ||
| 885 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { | ||
| 886 | return INTERPRETER_TRANSLATE(sadd8)(inst, index); | ||
| 887 | } | ||
| 888 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index) { | ||
| 889 | return INTERPRETER_TRANSLATE(sadd8)(inst, index); | ||
| 890 | } | ||
| 891 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index) { | ||
| 892 | return INTERPRETER_TRANSLATE(sadd8)(inst, index); | ||
| 893 | } | ||
| 894 | |||
| 895 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) { | ||
| 896 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); | ||
| 897 | sbc_inst* inst_cream = (sbc_inst*)inst_base->component; | ||
| 898 | |||
| 899 | inst_base->cond = BITS(inst, 28, 31); | ||
| 900 | inst_base->idx = index; | ||
| 901 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 902 | |||
| 903 | inst_cream->I = BIT(inst, 25); | ||
| 904 | inst_cream->S = BIT(inst, 20); | ||
| 905 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 906 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 907 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 908 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 909 | |||
| 910 | if (inst_cream->Rd == 15) | ||
| 911 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 912 | |||
| 913 | return inst_base; | ||
| 914 | } | ||
| 915 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index) { | ||
| 916 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 917 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 918 | |||
| 919 | inst_base->cond = BITS(inst, 28, 31); | ||
| 920 | inst_base->idx = index; | ||
| 921 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 922 | |||
| 923 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 924 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 925 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 926 | inst_cream->op1 = BITS(inst, 20, 22); | ||
| 927 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 928 | |||
| 929 | return inst_base; | ||
| 930 | } | ||
| 931 | |||
| 932 | static ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) { | ||
| 933 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(setend_inst)); | ||
| 934 | setend_inst* const inst_cream = (setend_inst*)inst_base->component; | ||
| 935 | |||
| 936 | inst_base->cond = AL; | ||
| 937 | inst_base->idx = index; | ||
| 938 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 939 | |||
| 940 | inst_cream->set_bigend = BIT(inst, 9); | ||
| 941 | |||
| 942 | return inst_base; | ||
| 943 | } | ||
| 944 | |||
| 945 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sev)(unsigned int inst, int index) { | ||
| 946 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); | ||
| 947 | |||
| 948 | inst_base->cond = BITS(inst, 28, 31); | ||
| 949 | inst_base->idx = index; | ||
| 950 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 951 | |||
| 952 | return inst_base; | ||
| 953 | } | ||
| 954 | |||
| 955 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) { | ||
| 956 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 957 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 958 | |||
| 959 | inst_base->cond = BITS(inst, 28, 31); | ||
| 960 | inst_base->idx = index; | ||
| 961 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 962 | |||
| 963 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 964 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 965 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 966 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 967 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 968 | |||
| 969 | return inst_base; | ||
| 970 | } | ||
| 971 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index) { | ||
| 972 | return INTERPRETER_TRANSLATE(shadd8)(inst, index); | ||
| 973 | } | ||
| 974 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index) { | ||
| 975 | return INTERPRETER_TRANSLATE(shadd8)(inst, index); | ||
| 976 | } | ||
| 977 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index) { | ||
| 978 | return INTERPRETER_TRANSLATE(shadd8)(inst, index); | ||
| 979 | } | ||
| 980 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index) { | ||
| 981 | return INTERPRETER_TRANSLATE(shadd8)(inst, index); | ||
| 982 | } | ||
| 983 | static ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index) { | ||
| 984 | return INTERPRETER_TRANSLATE(shadd8)(inst, index); | ||
| 985 | } | ||
| 986 | |||
| 987 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) { | ||
| 988 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); | ||
| 989 | smla_inst* inst_cream = (smla_inst*)inst_base->component; | ||
| 990 | |||
| 991 | inst_base->cond = BITS(inst, 28, 31); | ||
| 992 | inst_base->idx = index; | ||
| 993 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 994 | |||
| 995 | inst_cream->x = BIT(inst, 5); | ||
| 996 | inst_cream->y = BIT(inst, 6); | ||
| 997 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 998 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 999 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1000 | inst_cream->Rn = BITS(inst, 12, 15); | ||
| 1001 | |||
| 1002 | return inst_base; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index) { | ||
| 1006 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 1007 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 1008 | |||
| 1009 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1010 | inst_base->idx = index; | ||
| 1011 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1012 | |||
| 1013 | inst_cream->m = BIT(inst, 5); | ||
| 1014 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1015 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1016 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1017 | inst_cream->Ra = BITS(inst, 12, 15); | ||
| 1018 | inst_cream->op1 = BITS(inst, 20, 22); | ||
| 1019 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1020 | |||
| 1021 | return inst_base; | ||
| 1022 | } | ||
| 1023 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index) { | ||
| 1024 | return INTERPRETER_TRANSLATE(smlad)(inst, index); | ||
| 1025 | } | ||
| 1026 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) { | ||
| 1027 | return INTERPRETER_TRANSLATE(smlad)(inst, index); | ||
| 1028 | } | ||
| 1029 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index) { | ||
| 1030 | return INTERPRETER_TRANSLATE(smlad)(inst, index); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) { | ||
| 1034 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | ||
| 1035 | umlal_inst* inst_cream = (umlal_inst*)inst_base->component; | ||
| 1036 | |||
| 1037 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1038 | inst_base->idx = index; | ||
| 1039 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1040 | |||
| 1041 | inst_cream->S = BIT(inst, 20); | ||
| 1042 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1043 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 1044 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1045 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1046 | |||
| 1047 | return inst_base; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) { | ||
| 1051 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlalxy_inst)); | ||
| 1052 | smlalxy_inst* const inst_cream = (smlalxy_inst*)inst_base->component; | ||
| 1053 | |||
| 1054 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1055 | inst_base->idx = index; | ||
| 1056 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1057 | |||
| 1058 | inst_cream->x = BIT(inst, 5); | ||
| 1059 | inst_cream->y = BIT(inst, 6); | ||
| 1060 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1061 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1062 | inst_cream->Rn = BITS(inst, 0, 4); | ||
| 1063 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1064 | |||
| 1065 | return inst_base; | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index) { | ||
| 1069 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 1070 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 1071 | |||
| 1072 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1073 | inst_base->idx = index; | ||
| 1074 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1075 | |||
| 1076 | inst_cream->Ra = BITS(inst, 12, 15); | ||
| 1077 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1078 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1079 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1080 | inst_cream->m = BIT(inst, 6); | ||
| 1081 | |||
| 1082 | return inst_base; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index) { | ||
| 1086 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlald_inst)); | ||
| 1087 | smlald_inst* const inst_cream = (smlald_inst*)inst_base->component; | ||
| 1088 | |||
| 1089 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1090 | inst_base->idx = index; | ||
| 1091 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1092 | |||
| 1093 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1094 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1095 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1096 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1097 | inst_cream->swap = BIT(inst, 5); | ||
| 1098 | inst_cream->op1 = BITS(inst, 20, 22); | ||
| 1099 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1100 | |||
| 1101 | return inst_base; | ||
| 1102 | } | ||
| 1103 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index) { | ||
| 1104 | return INTERPRETER_TRANSLATE(smlald)(inst, index); | ||
| 1105 | } | ||
| 1106 | |||
| 1107 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index) { | ||
| 1108 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 1109 | smlad_inst* const inst_cream = (smlad_inst*)inst_base->component; | ||
| 1110 | |||
| 1111 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1112 | inst_base->idx = index; | ||
| 1113 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1114 | |||
| 1115 | inst_cream->m = BIT(inst, 5); | ||
| 1116 | inst_cream->Ra = BITS(inst, 12, 15); | ||
| 1117 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1118 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1119 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1120 | inst_cream->op1 = BITS(inst, 20, 22); | ||
| 1121 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1122 | |||
| 1123 | return inst_base; | ||
| 1124 | } | ||
| 1125 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index) { | ||
| 1126 | return INTERPRETER_TRANSLATE(smmla)(inst, index); | ||
| 1127 | } | ||
| 1128 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index) { | ||
| 1129 | return INTERPRETER_TRANSLATE(smmla)(inst, index); | ||
| 1130 | } | ||
| 1131 | |||
| 1132 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) { | ||
| 1133 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); | ||
| 1134 | smul_inst* inst_cream = (smul_inst*)inst_base->component; | ||
| 1135 | |||
| 1136 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1137 | inst_base->idx = index; | ||
| 1138 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1139 | |||
| 1140 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1141 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 1142 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1143 | |||
| 1144 | inst_cream->x = BIT(inst, 5); | ||
| 1145 | inst_cream->y = BIT(inst, 6); | ||
| 1146 | |||
| 1147 | return inst_base; | ||
| 1148 | } | ||
| 1149 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) { | ||
| 1150 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); | ||
| 1151 | umull_inst* inst_cream = (umull_inst*)inst_base->component; | ||
| 1152 | |||
| 1153 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1154 | inst_base->idx = index; | ||
| 1155 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1156 | |||
| 1157 | inst_cream->S = BIT(inst, 20); | ||
| 1158 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1159 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 1160 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1161 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1162 | |||
| 1163 | return inst_base; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) { | ||
| 1167 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); | ||
| 1168 | smlad_inst* inst_cream = (smlad_inst*)inst_base->component; | ||
| 1169 | |||
| 1170 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1171 | inst_base->idx = index; | ||
| 1172 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1173 | |||
| 1174 | inst_cream->m = BIT(inst, 6); | ||
| 1175 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1176 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1177 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1178 | |||
| 1179 | return inst_base; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | static ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) { | ||
| 1183 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1184 | ldst_inst* const inst_cream = (ldst_inst*)inst_base->component; | ||
| 1185 | |||
| 1186 | inst_base->cond = AL; | ||
| 1187 | inst_base->idx = index; | ||
| 1188 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1189 | |||
| 1190 | inst_cream->inst = inst; | ||
| 1191 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1192 | |||
| 1193 | return inst_base; | ||
| 1194 | } | ||
| 1195 | |||
| 1196 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index) { | ||
| 1197 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); | ||
| 1198 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 1199 | |||
| 1200 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1201 | inst_base->idx = index; | ||
| 1202 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1203 | |||
| 1204 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1205 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1206 | inst_cream->imm5 = BITS(inst, 7, 11); | ||
| 1207 | inst_cream->sat_imm = BITS(inst, 16, 20); | ||
| 1208 | inst_cream->shift_type = BIT(inst, 6); | ||
| 1209 | |||
| 1210 | return inst_base; | ||
| 1211 | } | ||
| 1212 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) { | ||
| 1213 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst)); | ||
| 1214 | ssat_inst* const inst_cream = (ssat_inst*)inst_base->component; | ||
| 1215 | |||
| 1216 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1217 | inst_base->idx = index; | ||
| 1218 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1219 | |||
| 1220 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1221 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1222 | inst_cream->sat_imm = BITS(inst, 16, 19); | ||
| 1223 | |||
| 1224 | return inst_base; | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) { | ||
| 1228 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); | ||
| 1229 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1230 | inst_base->idx = index; | ||
| 1231 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1232 | |||
| 1233 | return inst_base; | ||
| 1234 | } | ||
| 1235 | static ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) { | ||
| 1236 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1237 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1238 | |||
| 1239 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1240 | inst_base->idx = index; | ||
| 1241 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1242 | |||
| 1243 | inst_cream->inst = inst; | ||
| 1244 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1245 | return inst_base; | ||
| 1246 | } | ||
| 1247 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) { | ||
| 1248 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); | ||
| 1249 | sxtb_inst* inst_cream = (sxtb_inst*)inst_base->component; | ||
| 1250 | |||
| 1251 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1252 | inst_base->idx = index; | ||
| 1253 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1254 | |||
| 1255 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1256 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1257 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1258 | |||
| 1259 | return inst_base; | ||
| 1260 | } | ||
| 1261 | static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) { | ||
| 1262 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1263 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1264 | |||
| 1265 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1266 | inst_base->idx = index; | ||
| 1267 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1268 | |||
| 1269 | inst_cream->inst = inst; | ||
| 1270 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1271 | |||
| 1272 | return inst_base; | ||
| 1273 | } | ||
| 1274 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) { | ||
| 1275 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); | ||
| 1276 | uxth_inst* inst_cream = (uxth_inst*)inst_base->component; | ||
| 1277 | |||
| 1278 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1279 | inst_base->idx = index; | ||
| 1280 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1281 | |||
| 1282 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1283 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1284 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1285 | |||
| 1286 | return inst_base; | ||
| 1287 | } | ||
| 1288 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) { | ||
| 1289 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); | ||
| 1290 | uxtab_inst* inst_cream = (uxtab_inst*)inst_base->component; | ||
| 1291 | |||
| 1292 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1293 | inst_base->idx = index; | ||
| 1294 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1295 | |||
| 1296 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1297 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1298 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1299 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1300 | |||
| 1301 | return inst_base; | ||
| 1302 | } | ||
| 1303 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) { | ||
| 1304 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1305 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1306 | |||
| 1307 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1308 | inst_base->idx = index; | ||
| 1309 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1310 | |||
| 1311 | inst_cream->inst = inst; | ||
| 1312 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1313 | |||
| 1314 | return inst_base; | ||
| 1315 | } | ||
| 1316 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) { | ||
| 1317 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1318 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1319 | |||
| 1320 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1321 | inst_base->idx = index; | ||
| 1322 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1323 | |||
| 1324 | inst_cream->inst = inst; | ||
| 1325 | inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); | ||
| 1326 | |||
| 1327 | return inst_base; | ||
| 1328 | } | ||
| 1329 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index) { | ||
| 1330 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1331 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1332 | |||
| 1333 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1334 | inst_base->idx = index; | ||
| 1335 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1336 | |||
| 1337 | inst_cream->inst = inst; | ||
| 1338 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1339 | |||
| 1340 | return inst_base; | ||
| 1341 | } | ||
| 1342 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) { | ||
| 1343 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 1344 | generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 1345 | |||
| 1346 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1347 | inst_base->idx = index; | ||
| 1348 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1349 | |||
| 1350 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1351 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1352 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1353 | |||
| 1354 | return inst_base; | ||
| 1355 | } | ||
| 1356 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) { | ||
| 1357 | return INTERPRETER_TRANSLATE(strex)(inst, index); | ||
| 1358 | } | ||
| 1359 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strexh)(unsigned int inst, int index) { | ||
| 1360 | return INTERPRETER_TRANSLATE(strex)(inst, index); | ||
| 1361 | } | ||
| 1362 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strexd)(unsigned int inst, int index) { | ||
| 1363 | return INTERPRETER_TRANSLATE(strex)(inst, index); | ||
| 1364 | } | ||
| 1365 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) { | ||
| 1366 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1367 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1368 | |||
| 1369 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1370 | inst_base->idx = index; | ||
| 1371 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1372 | |||
| 1373 | inst_cream->inst = inst; | ||
| 1374 | inst_cream->get_addr = GetAddressingOp(inst); | ||
| 1375 | |||
| 1376 | return inst_base; | ||
| 1377 | } | ||
| 1378 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) { | ||
| 1379 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); | ||
| 1380 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | ||
| 1381 | |||
| 1382 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1383 | inst_base->idx = index; | ||
| 1384 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1385 | |||
| 1386 | inst_cream->inst = inst; | ||
| 1387 | inst_cream->get_addr = GetAddressingOpLoadStoreT(inst); | ||
| 1388 | |||
| 1389 | return inst_base; | ||
| 1390 | } | ||
| 1391 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) { | ||
| 1392 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); | ||
| 1393 | sub_inst* inst_cream = (sub_inst*)inst_base->component; | ||
| 1394 | |||
| 1395 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1396 | inst_base->idx = index; | ||
| 1397 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1398 | |||
| 1399 | inst_cream->I = BIT(inst, 25); | ||
| 1400 | inst_cream->S = BIT(inst, 20); | ||
| 1401 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1402 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1403 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1404 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 1405 | |||
| 1406 | if (inst_cream->Rd == 15) | ||
| 1407 | inst_base->br = TransExtData::INDIRECT_BRANCH; | ||
| 1408 | |||
| 1409 | return inst_base; | ||
| 1410 | } | ||
| 1411 | static ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) { | ||
| 1412 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); | ||
| 1413 | swi_inst* inst_cream = (swi_inst*)inst_base->component; | ||
| 1414 | |||
| 1415 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1416 | inst_base->idx = index; | ||
| 1417 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1418 | |||
| 1419 | inst_cream->num = BITS(inst, 0, 23); | ||
| 1420 | return inst_base; | ||
| 1421 | } | ||
| 1422 | static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) { | ||
| 1423 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); | ||
| 1424 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | ||
| 1425 | |||
| 1426 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1427 | inst_base->idx = index; | ||
| 1428 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1429 | |||
| 1430 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1431 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1432 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1433 | |||
| 1434 | return inst_base; | ||
| 1435 | } | ||
| 1436 | static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index) { | ||
| 1437 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); | ||
| 1438 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | ||
| 1439 | |||
| 1440 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1441 | inst_base->idx = index; | ||
| 1442 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1443 | |||
| 1444 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1445 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1446 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1447 | |||
| 1448 | return inst_base; | ||
| 1449 | } | ||
| 1450 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index) { | ||
| 1451 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); | ||
| 1452 | sxtab_inst* inst_cream = (sxtab_inst*)inst_base->component; | ||
| 1453 | |||
| 1454 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1455 | inst_base->idx = index; | ||
| 1456 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1457 | |||
| 1458 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1459 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1460 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1461 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1462 | |||
| 1463 | return inst_base; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index) { | ||
| 1467 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); | ||
| 1468 | sxtab_inst* const inst_cream = (sxtab_inst*)inst_base->component; | ||
| 1469 | |||
| 1470 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1471 | inst_base->idx = index; | ||
| 1472 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1473 | |||
| 1474 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1475 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1476 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1477 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1478 | |||
| 1479 | return inst_base; | ||
| 1480 | } | ||
| 1481 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index) { | ||
| 1482 | return INTERPRETER_TRANSLATE(sxtab16)(inst, index); | ||
| 1483 | } | ||
| 1484 | |||
| 1485 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index) { | ||
| 1486 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); | ||
| 1487 | sxtah_inst* inst_cream = (sxtah_inst*)inst_base->component; | ||
| 1488 | |||
| 1489 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1490 | inst_base->idx = index; | ||
| 1491 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1492 | |||
| 1493 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1494 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1495 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1496 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1497 | |||
| 1498 | return inst_base; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | static ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) { | ||
| 1502 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); | ||
| 1503 | teq_inst* inst_cream = (teq_inst*)inst_base->component; | ||
| 1504 | |||
| 1505 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1506 | inst_base->idx = index; | ||
| 1507 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1508 | |||
| 1509 | inst_cream->I = BIT(inst, 25); | ||
| 1510 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1511 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1512 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 1513 | |||
| 1514 | return inst_base; | ||
| 1515 | } | ||
| 1516 | static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) { | ||
| 1517 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); | ||
| 1518 | tst_inst* inst_cream = (tst_inst*)inst_base->component; | ||
| 1519 | |||
| 1520 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1521 | inst_base->idx = index; | ||
| 1522 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1523 | |||
| 1524 | inst_cream->I = BIT(inst, 25); | ||
| 1525 | inst_cream->S = BIT(inst, 20); | ||
| 1526 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1527 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1528 | inst_cream->shifter_operand = BITS(inst, 0, 11); | ||
| 1529 | inst_cream->shtop_func = GetShifterOp(inst); | ||
| 1530 | |||
| 1531 | return inst_base; | ||
| 1532 | } | ||
| 1533 | |||
| 1534 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index) { | ||
| 1535 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 1536 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 1537 | |||
| 1538 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1539 | inst_base->idx = index; | ||
| 1540 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1541 | |||
| 1542 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 1543 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1544 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1545 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1546 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1547 | |||
| 1548 | return inst_base; | ||
| 1549 | } | ||
| 1550 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index) { | ||
| 1551 | return INTERPRETER_TRANSLATE(uadd8)(inst, index); | ||
| 1552 | } | ||
| 1553 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index) { | ||
| 1554 | return INTERPRETER_TRANSLATE(uadd8)(inst, index); | ||
| 1555 | } | ||
| 1556 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { | ||
| 1557 | return INTERPRETER_TRANSLATE(uadd8)(inst, index); | ||
| 1558 | } | ||
| 1559 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { | ||
| 1560 | return INTERPRETER_TRANSLATE(uadd8)(inst, index); | ||
| 1561 | } | ||
| 1562 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) { | ||
| 1563 | return INTERPRETER_TRANSLATE(uadd8)(inst, index); | ||
| 1564 | } | ||
| 1565 | |||
| 1566 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index) { | ||
| 1567 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 1568 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 1569 | |||
| 1570 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1571 | inst_base->idx = index; | ||
| 1572 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1573 | |||
| 1574 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 1575 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1576 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1577 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1578 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1579 | |||
| 1580 | return inst_base; | ||
| 1581 | } | ||
| 1582 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index) { | ||
| 1583 | return INTERPRETER_TRANSLATE(uhadd8)(inst, index); | ||
| 1584 | } | ||
| 1585 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index) { | ||
| 1586 | return INTERPRETER_TRANSLATE(uhadd8)(inst, index); | ||
| 1587 | } | ||
| 1588 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index) { | ||
| 1589 | return INTERPRETER_TRANSLATE(uhadd8)(inst, index); | ||
| 1590 | } | ||
| 1591 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index) { | ||
| 1592 | return INTERPRETER_TRANSLATE(uhadd8)(inst, index); | ||
| 1593 | } | ||
| 1594 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index) { | ||
| 1595 | return INTERPRETER_TRANSLATE(uhadd8)(inst, index); | ||
| 1596 | } | ||
| 1597 | static ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index) { | ||
| 1598 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst)); | ||
| 1599 | umaal_inst* const inst_cream = (umaal_inst*)inst_base->component; | ||
| 1600 | |||
| 1601 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1602 | inst_base->idx = index; | ||
| 1603 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1604 | |||
| 1605 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1606 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1607 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1608 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1609 | |||
| 1610 | return inst_base; | ||
| 1611 | } | ||
| 1612 | static ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) { | ||
| 1613 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); | ||
| 1614 | umlal_inst* inst_cream = (umlal_inst*)inst_base->component; | ||
| 1615 | |||
| 1616 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1617 | inst_base->idx = index; | ||
| 1618 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1619 | |||
| 1620 | inst_cream->S = BIT(inst, 20); | ||
| 1621 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1622 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 1623 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1624 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1625 | |||
| 1626 | return inst_base; | ||
| 1627 | } | ||
| 1628 | static ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) { | ||
| 1629 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); | ||
| 1630 | umull_inst* inst_cream = (umull_inst*)inst_base->component; | ||
| 1631 | |||
| 1632 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1633 | inst_base->idx = index; | ||
| 1634 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1635 | |||
| 1636 | inst_cream->S = BIT(inst, 20); | ||
| 1637 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1638 | inst_cream->Rs = BITS(inst, 8, 11); | ||
| 1639 | inst_cream->RdHi = BITS(inst, 16, 19); | ||
| 1640 | inst_cream->RdLo = BITS(inst, 12, 15); | ||
| 1641 | |||
| 1642 | return inst_base; | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | static ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) { | ||
| 1646 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); | ||
| 1647 | b_2_thumb* inst_cream = (b_2_thumb*)inst_base->component; | ||
| 1648 | |||
| 1649 | inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); | ||
| 1650 | |||
| 1651 | inst_base->idx = index; | ||
| 1652 | inst_base->br = TransExtData::DIRECT_BRANCH; | ||
| 1653 | |||
| 1654 | return inst_base; | ||
| 1655 | } | ||
| 1656 | |||
| 1657 | static ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) { | ||
| 1658 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); | ||
| 1659 | b_cond_thumb* inst_cream = (b_cond_thumb*)inst_base->component; | ||
| 1660 | |||
| 1661 | inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); | ||
| 1662 | inst_cream->cond = ((tinst >> 8) & 0xf); | ||
| 1663 | inst_base->idx = index; | ||
| 1664 | inst_base->br = TransExtData::DIRECT_BRANCH; | ||
| 1665 | |||
| 1666 | return inst_base; | ||
| 1667 | } | ||
| 1668 | |||
| 1669 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) { | ||
| 1670 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); | ||
| 1671 | bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component; | ||
| 1672 | |||
| 1673 | inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); | ||
| 1674 | |||
| 1675 | inst_base->idx = index; | ||
| 1676 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1677 | return inst_base; | ||
| 1678 | } | ||
| 1679 | static ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) { | ||
| 1680 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); | ||
| 1681 | bl_2_thumb* inst_cream = (bl_2_thumb*)inst_base->component; | ||
| 1682 | |||
| 1683 | inst_cream->imm = (tinst & 0x07FF) << 1; | ||
| 1684 | |||
| 1685 | inst_base->idx = index; | ||
| 1686 | inst_base->br = TransExtData::DIRECT_BRANCH; | ||
| 1687 | return inst_base; | ||
| 1688 | } | ||
| 1689 | static ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) { | ||
| 1690 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); | ||
| 1691 | blx_1_thumb* inst_cream = (blx_1_thumb*)inst_base->component; | ||
| 1692 | |||
| 1693 | inst_cream->imm = (tinst & 0x07FF) << 1; | ||
| 1694 | inst_cream->instr = tinst; | ||
| 1695 | |||
| 1696 | inst_base->idx = index; | ||
| 1697 | inst_base->br = TransExtData::DIRECT_BRANCH; | ||
| 1698 | return inst_base; | ||
| 1699 | } | ||
| 1700 | |||
| 1701 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index) { | ||
| 1702 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 1703 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 1704 | |||
| 1705 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1706 | inst_base->idx = index; | ||
| 1707 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1708 | |||
| 1709 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1710 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1711 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1712 | inst_cream->op1 = BITS(inst, 20, 21); | ||
| 1713 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1714 | |||
| 1715 | return inst_base; | ||
| 1716 | } | ||
| 1717 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index) { | ||
| 1718 | return INTERPRETER_TRANSLATE(uqadd8)(inst, index); | ||
| 1719 | } | ||
| 1720 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index) { | ||
| 1721 | return INTERPRETER_TRANSLATE(uqadd8)(inst, index); | ||
| 1722 | } | ||
| 1723 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index) { | ||
| 1724 | return INTERPRETER_TRANSLATE(uqadd8)(inst, index); | ||
| 1725 | } | ||
| 1726 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index) { | ||
| 1727 | return INTERPRETER_TRANSLATE(uqadd8)(inst, index); | ||
| 1728 | } | ||
| 1729 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index) { | ||
| 1730 | return INTERPRETER_TRANSLATE(uqadd8)(inst, index); | ||
| 1731 | } | ||
| 1732 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index) { | ||
| 1733 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst)); | ||
| 1734 | generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component; | ||
| 1735 | |||
| 1736 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1737 | inst_base->idx = index; | ||
| 1738 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1739 | |||
| 1740 | inst_cream->op1 = BITS(inst, 20, 24); | ||
| 1741 | inst_cream->op2 = BITS(inst, 5, 7); | ||
| 1742 | inst_cream->Rd = BITS(inst, 16, 19); | ||
| 1743 | inst_cream->Rm = BITS(inst, 8, 11); | ||
| 1744 | inst_cream->Rn = BITS(inst, 0, 3); | ||
| 1745 | inst_cream->Ra = BITS(inst, 12, 15); | ||
| 1746 | |||
| 1747 | return inst_base; | ||
| 1748 | } | ||
| 1749 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index) { | ||
| 1750 | return INTERPRETER_TRANSLATE(usada8)(inst, index); | ||
| 1751 | } | ||
| 1752 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index) { | ||
| 1753 | return INTERPRETER_TRANSLATE(ssat)(inst, index); | ||
| 1754 | } | ||
| 1755 | static ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) { | ||
| 1756 | return INTERPRETER_TRANSLATE(ssat16)(inst, index); | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index) { | ||
| 1760 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); | ||
| 1761 | uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component; | ||
| 1762 | |||
| 1763 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1764 | inst_base->idx = index; | ||
| 1765 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1766 | |||
| 1767 | inst_cream->Rm = BITS(inst, 0, 3); | ||
| 1768 | inst_cream->Rn = BITS(inst, 16, 19); | ||
| 1769 | inst_cream->Rd = BITS(inst, 12, 15); | ||
| 1770 | inst_cream->rotate = BITS(inst, 10, 11); | ||
| 1771 | |||
| 1772 | return inst_base; | ||
| 1773 | } | ||
| 1774 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index) { | ||
| 1775 | return INTERPRETER_TRANSLATE(uxtab16)(inst, index); | ||
| 1776 | } | ||
| 1777 | |||
| 1778 | static ARM_INST_PTR INTERPRETER_TRANSLATE(wfe)(unsigned int inst, int index) { | ||
| 1779 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); | ||
| 1780 | |||
| 1781 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1782 | inst_base->idx = index; | ||
| 1783 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1784 | |||
| 1785 | return inst_base; | ||
| 1786 | } | ||
| 1787 | static ARM_INST_PTR INTERPRETER_TRANSLATE(wfi)(unsigned int inst, int index) { | ||
| 1788 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); | ||
| 1789 | |||
| 1790 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1791 | inst_base->idx = index; | ||
| 1792 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1793 | |||
| 1794 | return inst_base; | ||
| 1795 | } | ||
| 1796 | static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) { | ||
| 1797 | arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst)); | ||
| 1798 | |||
| 1799 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1800 | inst_base->idx = index; | ||
| 1801 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1802 | |||
| 1803 | return inst_base; | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | // Floating point VFPv3 instructions | ||
| 1807 | #define VFP_INTERPRETER_TRANS | ||
| 1808 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 1809 | #undef VFP_INTERPRETER_TRANS | ||
| 1810 | |||
| 1811 | const transop_fp_t arm_instruction_trans[] = { | ||
| 1812 | INTERPRETER_TRANSLATE(vmla), INTERPRETER_TRANSLATE(vmls), INTERPRETER_TRANSLATE(vnmla), | ||
| 1813 | INTERPRETER_TRANSLATE(vnmls), INTERPRETER_TRANSLATE(vnmul), INTERPRETER_TRANSLATE(vmul), | ||
| 1814 | INTERPRETER_TRANSLATE(vadd), INTERPRETER_TRANSLATE(vsub), INTERPRETER_TRANSLATE(vdiv), | ||
| 1815 | INTERPRETER_TRANSLATE(vmovi), INTERPRETER_TRANSLATE(vmovr), INTERPRETER_TRANSLATE(vabs), | ||
| 1816 | INTERPRETER_TRANSLATE(vneg), INTERPRETER_TRANSLATE(vsqrt), INTERPRETER_TRANSLATE(vcmp), | ||
| 1817 | INTERPRETER_TRANSLATE(vcmp2), INTERPRETER_TRANSLATE(vcvtbds), INTERPRETER_TRANSLATE(vcvtbff), | ||
| 1818 | INTERPRETER_TRANSLATE(vcvtbfi), INTERPRETER_TRANSLATE(vmovbrs), INTERPRETER_TRANSLATE(vmsr), | ||
| 1819 | INTERPRETER_TRANSLATE(vmovbrc), INTERPRETER_TRANSLATE(vmrs), INTERPRETER_TRANSLATE(vmovbcr), | ||
| 1820 | INTERPRETER_TRANSLATE(vmovbrrss), INTERPRETER_TRANSLATE(vmovbrrd), INTERPRETER_TRANSLATE(vstr), | ||
| 1821 | INTERPRETER_TRANSLATE(vpush), INTERPRETER_TRANSLATE(vstm), INTERPRETER_TRANSLATE(vpop), | ||
| 1822 | INTERPRETER_TRANSLATE(vldr), INTERPRETER_TRANSLATE(vldm), | ||
| 1823 | |||
| 1824 | INTERPRETER_TRANSLATE(srs), INTERPRETER_TRANSLATE(rfe), INTERPRETER_TRANSLATE(bkpt), | ||
| 1825 | INTERPRETER_TRANSLATE(blx), INTERPRETER_TRANSLATE(cps), INTERPRETER_TRANSLATE(pld), | ||
| 1826 | INTERPRETER_TRANSLATE(setend), INTERPRETER_TRANSLATE(clrex), INTERPRETER_TRANSLATE(rev16), | ||
| 1827 | INTERPRETER_TRANSLATE(usad8), INTERPRETER_TRANSLATE(sxtb), INTERPRETER_TRANSLATE(uxtb), | ||
| 1828 | INTERPRETER_TRANSLATE(sxth), INTERPRETER_TRANSLATE(sxtb16), INTERPRETER_TRANSLATE(uxth), | ||
| 1829 | INTERPRETER_TRANSLATE(uxtb16), INTERPRETER_TRANSLATE(cpy), INTERPRETER_TRANSLATE(uxtab), | ||
| 1830 | INTERPRETER_TRANSLATE(ssub8), INTERPRETER_TRANSLATE(shsub8), INTERPRETER_TRANSLATE(ssubaddx), | ||
| 1831 | INTERPRETER_TRANSLATE(strex), INTERPRETER_TRANSLATE(strexb), INTERPRETER_TRANSLATE(swp), | ||
| 1832 | INTERPRETER_TRANSLATE(swpb), INTERPRETER_TRANSLATE(ssub16), INTERPRETER_TRANSLATE(ssat16), | ||
| 1833 | INTERPRETER_TRANSLATE(shsubaddx), INTERPRETER_TRANSLATE(qsubaddx), | ||
| 1834 | INTERPRETER_TRANSLATE(shaddsubx), INTERPRETER_TRANSLATE(shadd8), INTERPRETER_TRANSLATE(shadd16), | ||
| 1835 | INTERPRETER_TRANSLATE(sel), INTERPRETER_TRANSLATE(saddsubx), INTERPRETER_TRANSLATE(sadd8), | ||
| 1836 | INTERPRETER_TRANSLATE(sadd16), INTERPRETER_TRANSLATE(shsub16), INTERPRETER_TRANSLATE(umaal), | ||
| 1837 | INTERPRETER_TRANSLATE(uxtab16), INTERPRETER_TRANSLATE(usubaddx), INTERPRETER_TRANSLATE(usub8), | ||
| 1838 | INTERPRETER_TRANSLATE(usub16), INTERPRETER_TRANSLATE(usat16), INTERPRETER_TRANSLATE(usada8), | ||
| 1839 | INTERPRETER_TRANSLATE(uqsubaddx), INTERPRETER_TRANSLATE(uqsub8), INTERPRETER_TRANSLATE(uqsub16), | ||
| 1840 | INTERPRETER_TRANSLATE(uqaddsubx), INTERPRETER_TRANSLATE(uqadd8), INTERPRETER_TRANSLATE(uqadd16), | ||
| 1841 | INTERPRETER_TRANSLATE(sxtab), INTERPRETER_TRANSLATE(uhsubaddx), INTERPRETER_TRANSLATE(uhsub8), | ||
| 1842 | INTERPRETER_TRANSLATE(uhsub16), INTERPRETER_TRANSLATE(uhaddsubx), INTERPRETER_TRANSLATE(uhadd8), | ||
| 1843 | INTERPRETER_TRANSLATE(uhadd16), INTERPRETER_TRANSLATE(uaddsubx), INTERPRETER_TRANSLATE(uadd8), | ||
| 1844 | INTERPRETER_TRANSLATE(uadd16), INTERPRETER_TRANSLATE(sxtah), INTERPRETER_TRANSLATE(sxtab16), | ||
| 1845 | INTERPRETER_TRANSLATE(qadd8), INTERPRETER_TRANSLATE(bxj), INTERPRETER_TRANSLATE(clz), | ||
| 1846 | INTERPRETER_TRANSLATE(uxtah), INTERPRETER_TRANSLATE(bx), INTERPRETER_TRANSLATE(rev), | ||
| 1847 | INTERPRETER_TRANSLATE(blx), INTERPRETER_TRANSLATE(revsh), INTERPRETER_TRANSLATE(qadd), | ||
| 1848 | INTERPRETER_TRANSLATE(qadd16), INTERPRETER_TRANSLATE(qaddsubx), INTERPRETER_TRANSLATE(ldrex), | ||
| 1849 | INTERPRETER_TRANSLATE(qdadd), INTERPRETER_TRANSLATE(qdsub), INTERPRETER_TRANSLATE(qsub), | ||
| 1850 | INTERPRETER_TRANSLATE(ldrexb), INTERPRETER_TRANSLATE(qsub8), INTERPRETER_TRANSLATE(qsub16), | ||
| 1851 | INTERPRETER_TRANSLATE(smuad), INTERPRETER_TRANSLATE(smmul), INTERPRETER_TRANSLATE(smusd), | ||
| 1852 | INTERPRETER_TRANSLATE(smlsd), INTERPRETER_TRANSLATE(smlsld), INTERPRETER_TRANSLATE(smmla), | ||
| 1853 | INTERPRETER_TRANSLATE(smmls), INTERPRETER_TRANSLATE(smlald), INTERPRETER_TRANSLATE(smlad), | ||
| 1854 | INTERPRETER_TRANSLATE(smlaw), INTERPRETER_TRANSLATE(smulw), INTERPRETER_TRANSLATE(pkhtb), | ||
| 1855 | INTERPRETER_TRANSLATE(pkhbt), INTERPRETER_TRANSLATE(smul), INTERPRETER_TRANSLATE(smlalxy), | ||
| 1856 | INTERPRETER_TRANSLATE(smla), INTERPRETER_TRANSLATE(mcrr), INTERPRETER_TRANSLATE(mrrc), | ||
| 1857 | INTERPRETER_TRANSLATE(cmp), INTERPRETER_TRANSLATE(tst), INTERPRETER_TRANSLATE(teq), | ||
| 1858 | INTERPRETER_TRANSLATE(cmn), INTERPRETER_TRANSLATE(smull), INTERPRETER_TRANSLATE(umull), | ||
| 1859 | INTERPRETER_TRANSLATE(umlal), INTERPRETER_TRANSLATE(smlal), INTERPRETER_TRANSLATE(mul), | ||
| 1860 | INTERPRETER_TRANSLATE(mla), INTERPRETER_TRANSLATE(ssat), INTERPRETER_TRANSLATE(usat), | ||
| 1861 | INTERPRETER_TRANSLATE(mrs), INTERPRETER_TRANSLATE(msr), INTERPRETER_TRANSLATE(and), | ||
| 1862 | INTERPRETER_TRANSLATE(bic), INTERPRETER_TRANSLATE(ldm), INTERPRETER_TRANSLATE(eor), | ||
| 1863 | INTERPRETER_TRANSLATE(add), INTERPRETER_TRANSLATE(rsb), INTERPRETER_TRANSLATE(rsc), | ||
| 1864 | INTERPRETER_TRANSLATE(sbc), INTERPRETER_TRANSLATE(adc), INTERPRETER_TRANSLATE(sub), | ||
| 1865 | INTERPRETER_TRANSLATE(orr), INTERPRETER_TRANSLATE(mvn), INTERPRETER_TRANSLATE(mov), | ||
| 1866 | INTERPRETER_TRANSLATE(stm), INTERPRETER_TRANSLATE(ldm), INTERPRETER_TRANSLATE(ldrsh), | ||
| 1867 | INTERPRETER_TRANSLATE(stm), INTERPRETER_TRANSLATE(ldm), INTERPRETER_TRANSLATE(ldrsb), | ||
| 1868 | INTERPRETER_TRANSLATE(strd), INTERPRETER_TRANSLATE(ldrh), INTERPRETER_TRANSLATE(strh), | ||
| 1869 | INTERPRETER_TRANSLATE(ldrd), INTERPRETER_TRANSLATE(strt), INTERPRETER_TRANSLATE(strbt), | ||
| 1870 | INTERPRETER_TRANSLATE(ldrbt), INTERPRETER_TRANSLATE(ldrt), INTERPRETER_TRANSLATE(mrc), | ||
| 1871 | INTERPRETER_TRANSLATE(mcr), INTERPRETER_TRANSLATE(msr), INTERPRETER_TRANSLATE(msr), | ||
| 1872 | INTERPRETER_TRANSLATE(msr), INTERPRETER_TRANSLATE(msr), INTERPRETER_TRANSLATE(msr), | ||
| 1873 | INTERPRETER_TRANSLATE(ldrb), INTERPRETER_TRANSLATE(strb), INTERPRETER_TRANSLATE(ldr), | ||
| 1874 | INTERPRETER_TRANSLATE(ldrcond), INTERPRETER_TRANSLATE(str), INTERPRETER_TRANSLATE(cdp), | ||
| 1875 | INTERPRETER_TRANSLATE(stc), INTERPRETER_TRANSLATE(ldc), INTERPRETER_TRANSLATE(ldrexd), | ||
| 1876 | INTERPRETER_TRANSLATE(strexd), INTERPRETER_TRANSLATE(ldrexh), INTERPRETER_TRANSLATE(strexh), | ||
| 1877 | INTERPRETER_TRANSLATE(nop), INTERPRETER_TRANSLATE(yield), INTERPRETER_TRANSLATE(wfe), | ||
| 1878 | INTERPRETER_TRANSLATE(wfi), INTERPRETER_TRANSLATE(sev), INTERPRETER_TRANSLATE(swi), | ||
| 1879 | INTERPRETER_TRANSLATE(bbl), | ||
| 1880 | |||
| 1881 | // All the thumb instructions should be placed the end of table | ||
| 1882 | INTERPRETER_TRANSLATE(b_2_thumb), INTERPRETER_TRANSLATE(b_cond_thumb), | ||
| 1883 | INTERPRETER_TRANSLATE(bl_1_thumb), INTERPRETER_TRANSLATE(bl_2_thumb), | ||
| 1884 | INTERPRETER_TRANSLATE(blx_1_thumb), | ||
| 1885 | }; | ||
| 1886 | |||
| 1887 | const size_t arm_instruction_trans_len = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); | ||
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.h b/src/core/arm/dyncom/arm_dyncom_trans.h deleted file mode 100644 index 632ff2cd6..000000000 --- a/src/core/arm/dyncom/arm_dyncom_trans.h +++ /dev/null | |||
| @@ -1,494 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <cstddef> | ||
| 4 | #include "common/common_types.h" | ||
| 5 | |||
| 6 | struct ARMul_State; | ||
| 7 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); | ||
| 8 | |||
| 9 | enum class TransExtData { | ||
| 10 | COND = (1 << 0), | ||
| 11 | NON_BRANCH = (1 << 1), | ||
| 12 | DIRECT_BRANCH = (1 << 2), | ||
| 13 | INDIRECT_BRANCH = (1 << 3), | ||
| 14 | CALL = (1 << 4), | ||
| 15 | RET = (1 << 5), | ||
| 16 | END_OF_PAGE = (1 << 6), | ||
| 17 | THUMB = (1 << 7), | ||
| 18 | SINGLE_STEP = (1 << 8) | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct arm_inst { | ||
| 22 | unsigned int idx; | ||
| 23 | unsigned int cond; | ||
| 24 | TransExtData br; | ||
| 25 | char component[0]; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct generic_arm_inst { | ||
| 29 | u32 Ra; | ||
| 30 | u32 Rm; | ||
| 31 | u32 Rn; | ||
| 32 | u32 Rd; | ||
| 33 | u8 op1; | ||
| 34 | u8 op2; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct adc_inst { | ||
| 38 | unsigned int I; | ||
| 39 | unsigned int S; | ||
| 40 | unsigned int Rn; | ||
| 41 | unsigned int Rd; | ||
| 42 | unsigned int shifter_operand; | ||
| 43 | shtop_fp_t shtop_func; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct add_inst { | ||
| 47 | unsigned int I; | ||
| 48 | unsigned int S; | ||
| 49 | unsigned int Rn; | ||
| 50 | unsigned int Rd; | ||
| 51 | unsigned int shifter_operand; | ||
| 52 | shtop_fp_t shtop_func; | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct orr_inst { | ||
| 56 | unsigned int I; | ||
| 57 | unsigned int S; | ||
| 58 | unsigned int Rn; | ||
| 59 | unsigned int Rd; | ||
| 60 | unsigned int shifter_operand; | ||
| 61 | shtop_fp_t shtop_func; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct and_inst { | ||
| 65 | unsigned int I; | ||
| 66 | unsigned int S; | ||
| 67 | unsigned int Rn; | ||
| 68 | unsigned int Rd; | ||
| 69 | unsigned int shifter_operand; | ||
| 70 | shtop_fp_t shtop_func; | ||
| 71 | }; | ||
| 72 | |||
| 73 | struct eor_inst { | ||
| 74 | unsigned int I; | ||
| 75 | unsigned int S; | ||
| 76 | unsigned int Rn; | ||
| 77 | unsigned int Rd; | ||
| 78 | unsigned int shifter_operand; | ||
| 79 | shtop_fp_t shtop_func; | ||
| 80 | }; | ||
| 81 | |||
| 82 | struct bbl_inst { | ||
| 83 | unsigned int L; | ||
| 84 | int signed_immed_24; | ||
| 85 | unsigned int next_addr; | ||
| 86 | unsigned int jmp_addr; | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct bx_inst { | ||
| 90 | unsigned int Rm; | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct blx_inst { | ||
| 94 | union { | ||
| 95 | s32 signed_immed_24; | ||
| 96 | u32 Rm; | ||
| 97 | } val; | ||
| 98 | unsigned int inst; | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct clz_inst { | ||
| 102 | unsigned int Rm; | ||
| 103 | unsigned int Rd; | ||
| 104 | }; | ||
| 105 | |||
| 106 | struct cps_inst { | ||
| 107 | unsigned int imod0; | ||
| 108 | unsigned int imod1; | ||
| 109 | unsigned int mmod; | ||
| 110 | unsigned int A, I, F; | ||
| 111 | unsigned int mode; | ||
| 112 | }; | ||
| 113 | |||
| 114 | struct clrex_inst {}; | ||
| 115 | |||
| 116 | struct cpy_inst { | ||
| 117 | unsigned int Rm; | ||
| 118 | unsigned int Rd; | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct bic_inst { | ||
| 122 | unsigned int I; | ||
| 123 | unsigned int S; | ||
| 124 | unsigned int Rn; | ||
| 125 | unsigned int Rd; | ||
| 126 | unsigned int shifter_operand; | ||
| 127 | shtop_fp_t shtop_func; | ||
| 128 | }; | ||
| 129 | |||
| 130 | struct sub_inst { | ||
| 131 | unsigned int I; | ||
| 132 | unsigned int S; | ||
| 133 | unsigned int Rn; | ||
| 134 | unsigned int Rd; | ||
| 135 | unsigned int shifter_operand; | ||
| 136 | shtop_fp_t shtop_func; | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct tst_inst { | ||
| 140 | unsigned int I; | ||
| 141 | unsigned int S; | ||
| 142 | unsigned int Rn; | ||
| 143 | unsigned int Rd; | ||
| 144 | unsigned int shifter_operand; | ||
| 145 | shtop_fp_t shtop_func; | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct cmn_inst { | ||
| 149 | unsigned int I; | ||
| 150 | unsigned int Rn; | ||
| 151 | unsigned int shifter_operand; | ||
| 152 | shtop_fp_t shtop_func; | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct teq_inst { | ||
| 156 | unsigned int I; | ||
| 157 | unsigned int Rn; | ||
| 158 | unsigned int shifter_operand; | ||
| 159 | shtop_fp_t shtop_func; | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct stm_inst { | ||
| 163 | unsigned int inst; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct bkpt_inst { | ||
| 167 | u32 imm; | ||
| 168 | }; | ||
| 169 | |||
| 170 | struct stc_inst {}; | ||
| 171 | |||
| 172 | struct ldc_inst {}; | ||
| 173 | |||
| 174 | struct swi_inst { | ||
| 175 | unsigned int num; | ||
| 176 | }; | ||
| 177 | |||
| 178 | struct cmp_inst { | ||
| 179 | unsigned int I; | ||
| 180 | unsigned int Rn; | ||
| 181 | unsigned int shifter_operand; | ||
| 182 | shtop_fp_t shtop_func; | ||
| 183 | }; | ||
| 184 | |||
| 185 | struct mov_inst { | ||
| 186 | unsigned int I; | ||
| 187 | unsigned int S; | ||
| 188 | unsigned int Rd; | ||
| 189 | unsigned int shifter_operand; | ||
| 190 | shtop_fp_t shtop_func; | ||
| 191 | }; | ||
| 192 | |||
| 193 | struct mvn_inst { | ||
| 194 | unsigned int I; | ||
| 195 | unsigned int S; | ||
| 196 | unsigned int Rd; | ||
| 197 | unsigned int shifter_operand; | ||
| 198 | shtop_fp_t shtop_func; | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct rev_inst { | ||
| 202 | unsigned int Rd; | ||
| 203 | unsigned int Rm; | ||
| 204 | unsigned int op1; | ||
| 205 | unsigned int op2; | ||
| 206 | }; | ||
| 207 | |||
| 208 | struct rsb_inst { | ||
| 209 | unsigned int I; | ||
| 210 | unsigned int S; | ||
| 211 | unsigned int Rn; | ||
| 212 | unsigned int Rd; | ||
| 213 | unsigned int shifter_operand; | ||
| 214 | shtop_fp_t shtop_func; | ||
| 215 | }; | ||
| 216 | |||
| 217 | struct rsc_inst { | ||
| 218 | unsigned int I; | ||
| 219 | unsigned int S; | ||
| 220 | unsigned int Rn; | ||
| 221 | unsigned int Rd; | ||
| 222 | unsigned int shifter_operand; | ||
| 223 | shtop_fp_t shtop_func; | ||
| 224 | }; | ||
| 225 | |||
| 226 | struct sbc_inst { | ||
| 227 | unsigned int I; | ||
| 228 | unsigned int S; | ||
| 229 | unsigned int Rn; | ||
| 230 | unsigned int Rd; | ||
| 231 | unsigned int shifter_operand; | ||
| 232 | shtop_fp_t shtop_func; | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct mul_inst { | ||
| 236 | unsigned int S; | ||
| 237 | unsigned int Rd; | ||
| 238 | unsigned int Rs; | ||
| 239 | unsigned int Rm; | ||
| 240 | }; | ||
| 241 | |||
| 242 | struct smul_inst { | ||
| 243 | unsigned int Rd; | ||
| 244 | unsigned int Rs; | ||
| 245 | unsigned int Rm; | ||
| 246 | unsigned int x; | ||
| 247 | unsigned int y; | ||
| 248 | }; | ||
| 249 | |||
| 250 | struct umull_inst { | ||
| 251 | unsigned int S; | ||
| 252 | unsigned int RdHi; | ||
| 253 | unsigned int RdLo; | ||
| 254 | unsigned int Rs; | ||
| 255 | unsigned int Rm; | ||
| 256 | }; | ||
| 257 | |||
| 258 | struct smlad_inst { | ||
| 259 | unsigned int m; | ||
| 260 | unsigned int Rm; | ||
| 261 | unsigned int Rd; | ||
| 262 | unsigned int Ra; | ||
| 263 | unsigned int Rn; | ||
| 264 | unsigned int op1; | ||
| 265 | unsigned int op2; | ||
| 266 | }; | ||
| 267 | |||
| 268 | struct smla_inst { | ||
| 269 | unsigned int x; | ||
| 270 | unsigned int y; | ||
| 271 | unsigned int Rm; | ||
| 272 | unsigned int Rd; | ||
| 273 | unsigned int Rs; | ||
| 274 | unsigned int Rn; | ||
| 275 | }; | ||
| 276 | |||
| 277 | struct smlalxy_inst { | ||
| 278 | unsigned int x; | ||
| 279 | unsigned int y; | ||
| 280 | unsigned int RdLo; | ||
| 281 | unsigned int RdHi; | ||
| 282 | unsigned int Rm; | ||
| 283 | unsigned int Rn; | ||
| 284 | }; | ||
| 285 | |||
| 286 | struct ssat_inst { | ||
| 287 | unsigned int Rn; | ||
| 288 | unsigned int Rd; | ||
| 289 | unsigned int imm5; | ||
| 290 | unsigned int sat_imm; | ||
| 291 | unsigned int shift_type; | ||
| 292 | }; | ||
| 293 | |||
| 294 | struct umaal_inst { | ||
| 295 | unsigned int Rn; | ||
| 296 | unsigned int Rm; | ||
| 297 | unsigned int RdHi; | ||
| 298 | unsigned int RdLo; | ||
| 299 | }; | ||
| 300 | |||
| 301 | struct umlal_inst { | ||
| 302 | unsigned int S; | ||
| 303 | unsigned int Rm; | ||
| 304 | unsigned int Rs; | ||
| 305 | unsigned int RdHi; | ||
| 306 | unsigned int RdLo; | ||
| 307 | }; | ||
| 308 | |||
| 309 | struct smlal_inst { | ||
| 310 | unsigned int S; | ||
| 311 | unsigned int Rm; | ||
| 312 | unsigned int Rs; | ||
| 313 | unsigned int RdHi; | ||
| 314 | unsigned int RdLo; | ||
| 315 | }; | ||
| 316 | |||
| 317 | struct smlald_inst { | ||
| 318 | unsigned int RdLo; | ||
| 319 | unsigned int RdHi; | ||
| 320 | unsigned int Rm; | ||
| 321 | unsigned int Rn; | ||
| 322 | unsigned int swap; | ||
| 323 | unsigned int op1; | ||
| 324 | unsigned int op2; | ||
| 325 | }; | ||
| 326 | |||
| 327 | struct mla_inst { | ||
| 328 | unsigned int S; | ||
| 329 | unsigned int Rn; | ||
| 330 | unsigned int Rd; | ||
| 331 | unsigned int Rs; | ||
| 332 | unsigned int Rm; | ||
| 333 | }; | ||
| 334 | |||
| 335 | struct mrc_inst { | ||
| 336 | unsigned int opcode_1; | ||
| 337 | unsigned int opcode_2; | ||
| 338 | unsigned int cp_num; | ||
| 339 | unsigned int crn; | ||
| 340 | unsigned int crm; | ||
| 341 | unsigned int Rd; | ||
| 342 | unsigned int inst; | ||
| 343 | }; | ||
| 344 | |||
| 345 | struct mcr_inst { | ||
| 346 | unsigned int opcode_1; | ||
| 347 | unsigned int opcode_2; | ||
| 348 | unsigned int cp_num; | ||
| 349 | unsigned int crn; | ||
| 350 | unsigned int crm; | ||
| 351 | unsigned int Rd; | ||
| 352 | unsigned int inst; | ||
| 353 | }; | ||
| 354 | |||
| 355 | struct mcrr_inst { | ||
| 356 | unsigned int opcode_1; | ||
| 357 | unsigned int cp_num; | ||
| 358 | unsigned int crm; | ||
| 359 | unsigned int rt; | ||
| 360 | unsigned int rt2; | ||
| 361 | }; | ||
| 362 | |||
| 363 | struct mrs_inst { | ||
| 364 | unsigned int R; | ||
| 365 | unsigned int Rd; | ||
| 366 | }; | ||
| 367 | |||
| 368 | struct msr_inst { | ||
| 369 | unsigned int field_mask; | ||
| 370 | unsigned int R; | ||
| 371 | unsigned int inst; | ||
| 372 | }; | ||
| 373 | |||
| 374 | struct pld_inst {}; | ||
| 375 | |||
| 376 | struct sxtb_inst { | ||
| 377 | unsigned int Rd; | ||
| 378 | unsigned int Rm; | ||
| 379 | unsigned int rotate; | ||
| 380 | }; | ||
| 381 | |||
| 382 | struct sxtab_inst { | ||
| 383 | unsigned int Rd; | ||
| 384 | unsigned int Rn; | ||
| 385 | unsigned int Rm; | ||
| 386 | unsigned rotate; | ||
| 387 | }; | ||
| 388 | |||
| 389 | struct sxtah_inst { | ||
| 390 | unsigned int Rd; | ||
| 391 | unsigned int Rn; | ||
| 392 | unsigned int Rm; | ||
| 393 | unsigned int rotate; | ||
| 394 | }; | ||
| 395 | |||
| 396 | struct sxth_inst { | ||
| 397 | unsigned int Rd; | ||
| 398 | unsigned int Rm; | ||
| 399 | unsigned int rotate; | ||
| 400 | }; | ||
| 401 | |||
| 402 | struct uxtab_inst { | ||
| 403 | unsigned int Rn; | ||
| 404 | unsigned int Rd; | ||
| 405 | unsigned int rotate; | ||
| 406 | unsigned int Rm; | ||
| 407 | }; | ||
| 408 | |||
| 409 | struct uxtah_inst { | ||
| 410 | unsigned int Rn; | ||
| 411 | unsigned int Rd; | ||
| 412 | unsigned int rotate; | ||
| 413 | unsigned int Rm; | ||
| 414 | }; | ||
| 415 | |||
| 416 | struct uxth_inst { | ||
| 417 | unsigned int Rd; | ||
| 418 | unsigned int Rm; | ||
| 419 | unsigned int rotate; | ||
| 420 | }; | ||
| 421 | |||
| 422 | struct cdp_inst { | ||
| 423 | unsigned int opcode_1; | ||
| 424 | unsigned int CRn; | ||
| 425 | unsigned int CRd; | ||
| 426 | unsigned int cp_num; | ||
| 427 | unsigned int opcode_2; | ||
| 428 | unsigned int CRm; | ||
| 429 | unsigned int inst; | ||
| 430 | }; | ||
| 431 | |||
| 432 | struct uxtb_inst { | ||
| 433 | unsigned int Rd; | ||
| 434 | unsigned int Rm; | ||
| 435 | unsigned int rotate; | ||
| 436 | }; | ||
| 437 | |||
| 438 | struct swp_inst { | ||
| 439 | unsigned int Rn; | ||
| 440 | unsigned int Rd; | ||
| 441 | unsigned int Rm; | ||
| 442 | }; | ||
| 443 | |||
| 444 | struct setend_inst { | ||
| 445 | unsigned int set_bigend; | ||
| 446 | }; | ||
| 447 | |||
| 448 | struct b_2_thumb { | ||
| 449 | unsigned int imm; | ||
| 450 | }; | ||
| 451 | struct b_cond_thumb { | ||
| 452 | unsigned int imm; | ||
| 453 | unsigned int cond; | ||
| 454 | }; | ||
| 455 | |||
| 456 | struct bl_1_thumb { | ||
| 457 | unsigned int imm; | ||
| 458 | }; | ||
| 459 | struct bl_2_thumb { | ||
| 460 | unsigned int imm; | ||
| 461 | }; | ||
| 462 | struct blx_1_thumb { | ||
| 463 | unsigned int imm; | ||
| 464 | unsigned int instr; | ||
| 465 | }; | ||
| 466 | |||
| 467 | struct pkh_inst { | ||
| 468 | unsigned int Rm; | ||
| 469 | unsigned int Rn; | ||
| 470 | unsigned int Rd; | ||
| 471 | unsigned char imm; | ||
| 472 | }; | ||
| 473 | |||
| 474 | // Floating point VFPv3 structures | ||
| 475 | #define VFP_INTERPRETER_STRUCT | ||
| 476 | #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" | ||
| 477 | #undef VFP_INTERPRETER_STRUCT | ||
| 478 | |||
| 479 | typedef void (*get_addr_fp_t)(ARMul_State* cpu, unsigned int inst, unsigned int& virt_addr); | ||
| 480 | |||
| 481 | struct ldst_inst { | ||
| 482 | unsigned int inst; | ||
| 483 | get_addr_fp_t get_addr; | ||
| 484 | }; | ||
| 485 | |||
| 486 | typedef arm_inst* ARM_INST_PTR; | ||
| 487 | typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); | ||
| 488 | |||
| 489 | extern const transop_fp_t arm_instruction_trans[]; | ||
| 490 | extern const size_t arm_instruction_trans_len; | ||
| 491 | |||
| 492 | #define TRANS_CACHE_SIZE (64 * 1024 * 2000) | ||
| 493 | extern char trans_cache_buf[TRANS_CACHE_SIZE]; | ||
| 494 | extern size_t trans_cache_buf_top; | ||
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h deleted file mode 100644 index 706195a05..000000000 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ /dev/null | |||
| @@ -1,187 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | enum { | ||
| 4 | R0 = 0, | ||
| 5 | R1, | ||
| 6 | R2, | ||
| 7 | R3, | ||
| 8 | R4, | ||
| 9 | R5, | ||
| 10 | R6, | ||
| 11 | R7, | ||
| 12 | R8, | ||
| 13 | R9, | ||
| 14 | R10, | ||
| 15 | R11, | ||
| 16 | R12, | ||
| 17 | R13, | ||
| 18 | LR, | ||
| 19 | R15, // PC, | ||
| 20 | CPSR_REG, | ||
| 21 | SPSR_REG, | ||
| 22 | |||
| 23 | PHYS_PC, | ||
| 24 | R13_USR, | ||
| 25 | R14_USR, | ||
| 26 | R13_SVC, | ||
| 27 | R14_SVC, | ||
| 28 | R13_ABORT, | ||
| 29 | R14_ABORT, | ||
| 30 | R13_UNDEF, | ||
| 31 | R14_UNDEF, | ||
| 32 | R13_IRQ, | ||
| 33 | R14_IRQ, | ||
| 34 | R8_FIRQ, | ||
| 35 | R9_FIRQ, | ||
| 36 | R10_FIRQ, | ||
| 37 | R11_FIRQ, | ||
| 38 | R12_FIRQ, | ||
| 39 | R13_FIRQ, | ||
| 40 | R14_FIRQ, | ||
| 41 | SPSR_INVALID1, | ||
| 42 | SPSR_INVALID2, | ||
| 43 | SPSR_SVC, | ||
| 44 | SPSR_ABORT, | ||
| 45 | SPSR_UNDEF, | ||
| 46 | SPSR_IRQ, | ||
| 47 | SPSR_FIRQ, | ||
| 48 | MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */ | ||
| 49 | BANK_REG, | ||
| 50 | EXCLUSIVE_TAG, | ||
| 51 | EXCLUSIVE_STATE, | ||
| 52 | EXCLUSIVE_RESULT, | ||
| 53 | |||
| 54 | MAX_REG_NUM, | ||
| 55 | }; | ||
| 56 | |||
| 57 | // VFP system registers | ||
| 58 | enum VFPSystemRegister { | ||
| 59 | VFP_FPSID, | ||
| 60 | VFP_FPSCR, | ||
| 61 | VFP_FPEXC, | ||
| 62 | VFP_FPINST, | ||
| 63 | VFP_FPINST2, | ||
| 64 | VFP_MVFR0, | ||
| 65 | VFP_MVFR1, | ||
| 66 | |||
| 67 | // Not an actual register. | ||
| 68 | // All VFP system registers should be defined above this. | ||
| 69 | VFP_SYSTEM_REGISTER_COUNT | ||
| 70 | }; | ||
| 71 | |||
| 72 | enum CP15Register { | ||
| 73 | // c0 - Information registers | ||
| 74 | CP15_MAIN_ID, | ||
| 75 | CP15_CACHE_TYPE, | ||
| 76 | CP15_TCM_STATUS, | ||
| 77 | CP15_TLB_TYPE, | ||
| 78 | CP15_CPU_ID, | ||
| 79 | CP15_PROCESSOR_FEATURE_0, | ||
| 80 | CP15_PROCESSOR_FEATURE_1, | ||
| 81 | CP15_DEBUG_FEATURE_0, | ||
| 82 | CP15_AUXILIARY_FEATURE_0, | ||
| 83 | CP15_MEMORY_MODEL_FEATURE_0, | ||
| 84 | CP15_MEMORY_MODEL_FEATURE_1, | ||
| 85 | CP15_MEMORY_MODEL_FEATURE_2, | ||
| 86 | CP15_MEMORY_MODEL_FEATURE_3, | ||
| 87 | CP15_ISA_FEATURE_0, | ||
| 88 | CP15_ISA_FEATURE_1, | ||
| 89 | CP15_ISA_FEATURE_2, | ||
| 90 | CP15_ISA_FEATURE_3, | ||
| 91 | CP15_ISA_FEATURE_4, | ||
| 92 | |||
| 93 | // c1 - Control registers | ||
| 94 | CP15_CONTROL, | ||
| 95 | CP15_AUXILIARY_CONTROL, | ||
| 96 | CP15_COPROCESSOR_ACCESS_CONTROL, | ||
| 97 | |||
| 98 | // c2 - Translation table registers | ||
| 99 | CP15_TRANSLATION_BASE_TABLE_0, | ||
| 100 | CP15_TRANSLATION_BASE_TABLE_1, | ||
| 101 | CP15_TRANSLATION_BASE_CONTROL, | ||
| 102 | CP15_DOMAIN_ACCESS_CONTROL, | ||
| 103 | CP15_RESERVED, | ||
| 104 | |||
| 105 | // c5 - Fault status registers | ||
| 106 | CP15_FAULT_STATUS, | ||
| 107 | CP15_INSTR_FAULT_STATUS, | ||
| 108 | CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, | ||
| 109 | CP15_INST_FSR, | ||
| 110 | |||
| 111 | // c6 - Fault Address registers | ||
| 112 | CP15_FAULT_ADDRESS, | ||
| 113 | CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, | ||
| 114 | CP15_WFAR, | ||
| 115 | CP15_IFAR, | ||
| 116 | |||
| 117 | // c7 - Cache operation registers | ||
| 118 | CP15_WAIT_FOR_INTERRUPT, | ||
| 119 | CP15_PHYS_ADDRESS, | ||
| 120 | CP15_INVALIDATE_INSTR_CACHE, | ||
| 121 | CP15_INVALIDATE_INSTR_CACHE_USING_MVA, | ||
| 122 | CP15_INVALIDATE_INSTR_CACHE_USING_INDEX, | ||
| 123 | CP15_FLUSH_PREFETCH_BUFFER, | ||
| 124 | CP15_FLUSH_BRANCH_TARGET_CACHE, | ||
| 125 | CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY, | ||
| 126 | CP15_INVALIDATE_DATA_CACHE, | ||
| 127 | CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA, | ||
| 128 | CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, | ||
| 129 | CP15_INVALIDATE_DATA_AND_INSTR_CACHE, | ||
| 130 | CP15_CLEAN_DATA_CACHE, | ||
| 131 | CP15_CLEAN_DATA_CACHE_LINE_USING_MVA, | ||
| 132 | CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX, | ||
| 133 | CP15_DATA_SYNC_BARRIER, | ||
| 134 | CP15_DATA_MEMORY_BARRIER, | ||
| 135 | CP15_CLEAN_AND_INVALIDATE_DATA_CACHE, | ||
| 136 | CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA, | ||
| 137 | CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, | ||
| 138 | |||
| 139 | // c8 - TLB operations | ||
| 140 | CP15_INVALIDATE_ITLB, | ||
| 141 | CP15_INVALIDATE_ITLB_SINGLE_ENTRY, | ||
| 142 | CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH, | ||
| 143 | CP15_INVALIDATE_ITLB_ENTRY_ON_MVA, | ||
| 144 | CP15_INVALIDATE_DTLB, | ||
| 145 | CP15_INVALIDATE_DTLB_SINGLE_ENTRY, | ||
| 146 | CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH, | ||
| 147 | CP15_INVALIDATE_DTLB_ENTRY_ON_MVA, | ||
| 148 | CP15_INVALIDATE_UTLB, | ||
| 149 | CP15_INVALIDATE_UTLB_SINGLE_ENTRY, | ||
| 150 | CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH, | ||
| 151 | CP15_INVALIDATE_UTLB_ENTRY_ON_MVA, | ||
| 152 | |||
| 153 | // c9 - Data cache lockdown register | ||
| 154 | CP15_DATA_CACHE_LOCKDOWN, | ||
| 155 | |||
| 156 | // c10 - TLB/Memory map registers | ||
| 157 | CP15_TLB_LOCKDOWN, | ||
| 158 | CP15_PRIMARY_REGION_REMAP, | ||
| 159 | CP15_NORMAL_REGION_REMAP, | ||
| 160 | |||
| 161 | // c13 - Thread related registers | ||
| 162 | CP15_PID, | ||
| 163 | CP15_CONTEXT_ID, | ||
| 164 | CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write | ||
| 165 | CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) | ||
| 166 | CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. | ||
| 167 | |||
| 168 | // c15 - Performance and TLB lockdown registers | ||
| 169 | CP15_PERFORMANCE_MONITOR_CONTROL, | ||
| 170 | CP15_CYCLE_COUNTER, | ||
| 171 | CP15_COUNT_0, | ||
| 172 | CP15_COUNT_1, | ||
| 173 | CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY, | ||
| 174 | CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY, | ||
| 175 | CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS, | ||
| 176 | CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS, | ||
| 177 | CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE, | ||
| 178 | CP15_TLB_DEBUG_CONTROL, | ||
| 179 | |||
| 180 | // Skyeye defined | ||
| 181 | CP15_TLB_FAULT_ADDR, | ||
| 182 | CP15_TLB_FAULT_STATUS, | ||
| 183 | |||
| 184 | // Not an actual register. | ||
| 185 | // All registers should be defined above this. | ||
| 186 | CP15_REGISTER_COUNT, | ||
| 187 | }; | ||
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp deleted file mode 100644 index 92b644825..000000000 --- a/src/core/arm/skyeye_common/armstate.cpp +++ /dev/null | |||
| @@ -1,597 +0,0 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/swap.h" | ||
| 8 | #include "core/arm/skyeye_common/armstate.h" | ||
| 9 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 11 | #include "core/memory.h" | ||
| 12 | |||
| 13 | ARMul_State::ARMul_State(PrivilegeMode initial_mode) { | ||
| 14 | Reset(); | ||
| 15 | ChangePrivilegeMode(initial_mode); | ||
| 16 | } | ||
| 17 | |||
| 18 | void ARMul_State::ChangePrivilegeMode(u32 new_mode) { | ||
| 19 | if (Mode == new_mode) | ||
| 20 | return; | ||
| 21 | |||
| 22 | if (new_mode != USERBANK) { | ||
| 23 | switch (Mode) { | ||
| 24 | case SYSTEM32MODE: // Shares registers with user mode | ||
| 25 | case USER32MODE: | ||
| 26 | Reg_usr[0] = Reg[13]; | ||
| 27 | Reg_usr[1] = Reg[14]; | ||
| 28 | break; | ||
| 29 | case IRQ32MODE: | ||
| 30 | Reg_irq[0] = Reg[13]; | ||
| 31 | Reg_irq[1] = Reg[14]; | ||
| 32 | Spsr[IRQBANK] = Spsr_copy; | ||
| 33 | break; | ||
| 34 | case SVC32MODE: | ||
| 35 | Reg_svc[0] = Reg[13]; | ||
| 36 | Reg_svc[1] = Reg[14]; | ||
| 37 | Spsr[SVCBANK] = Spsr_copy; | ||
| 38 | break; | ||
| 39 | case ABORT32MODE: | ||
| 40 | Reg_abort[0] = Reg[13]; | ||
| 41 | Reg_abort[1] = Reg[14]; | ||
| 42 | Spsr[ABORTBANK] = Spsr_copy; | ||
| 43 | break; | ||
| 44 | case UNDEF32MODE: | ||
| 45 | Reg_undef[0] = Reg[13]; | ||
| 46 | Reg_undef[1] = Reg[14]; | ||
| 47 | Spsr[UNDEFBANK] = Spsr_copy; | ||
| 48 | break; | ||
| 49 | case FIQ32MODE: | ||
| 50 | std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin()); | ||
| 51 | Spsr[FIQBANK] = Spsr_copy; | ||
| 52 | break; | ||
| 53 | } | ||
| 54 | |||
| 55 | switch (new_mode) { | ||
| 56 | case USER32MODE: | ||
| 57 | Reg[13] = Reg_usr[0]; | ||
| 58 | Reg[14] = Reg_usr[1]; | ||
| 59 | Bank = USERBANK; | ||
| 60 | break; | ||
| 61 | case IRQ32MODE: | ||
| 62 | Reg[13] = Reg_irq[0]; | ||
| 63 | Reg[14] = Reg_irq[1]; | ||
| 64 | Spsr_copy = Spsr[IRQBANK]; | ||
| 65 | Bank = IRQBANK; | ||
| 66 | break; | ||
| 67 | case SVC32MODE: | ||
| 68 | Reg[13] = Reg_svc[0]; | ||
| 69 | Reg[14] = Reg_svc[1]; | ||
| 70 | Spsr_copy = Spsr[SVCBANK]; | ||
| 71 | Bank = SVCBANK; | ||
| 72 | break; | ||
| 73 | case ABORT32MODE: | ||
| 74 | Reg[13] = Reg_abort[0]; | ||
| 75 | Reg[14] = Reg_abort[1]; | ||
| 76 | Spsr_copy = Spsr[ABORTBANK]; | ||
| 77 | Bank = ABORTBANK; | ||
| 78 | break; | ||
| 79 | case UNDEF32MODE: | ||
| 80 | Reg[13] = Reg_undef[0]; | ||
| 81 | Reg[14] = Reg_undef[1]; | ||
| 82 | Spsr_copy = Spsr[UNDEFBANK]; | ||
| 83 | Bank = UNDEFBANK; | ||
| 84 | break; | ||
| 85 | case FIQ32MODE: | ||
| 86 | std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8); | ||
| 87 | Spsr_copy = Spsr[FIQBANK]; | ||
| 88 | Bank = FIQBANK; | ||
| 89 | break; | ||
| 90 | case SYSTEM32MODE: // Shares registers with user mode. | ||
| 91 | Reg[13] = Reg_usr[0]; | ||
| 92 | Reg[14] = Reg_usr[1]; | ||
| 93 | Bank = SYSTEMBANK; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | |||
| 97 | // Set the mode bits in the APSR | ||
| 98 | Cpsr = (Cpsr & ~Mode) | new_mode; | ||
| 99 | Mode = new_mode; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | // Performs a reset | ||
| 104 | void ARMul_State::Reset() { | ||
| 105 | VFPInit(this); | ||
| 106 | |||
| 107 | // Set stack pointer to the top of the stack | ||
| 108 | Reg[13] = 0x10000000; | ||
| 109 | Reg[15] = 0; | ||
| 110 | |||
| 111 | Cpsr = INTBITS | SVC32MODE; | ||
| 112 | Mode = SVC32MODE; | ||
| 113 | Bank = SVCBANK; | ||
| 114 | |||
| 115 | ResetMPCoreCP15Registers(); | ||
| 116 | |||
| 117 | NresetSig = HIGH; | ||
| 118 | NfiqSig = HIGH; | ||
| 119 | NirqSig = HIGH; | ||
| 120 | NtransSig = (Mode & 3) ? HIGH : LOW; | ||
| 121 | abortSig = LOW; | ||
| 122 | |||
| 123 | NumInstrs = 0; | ||
| 124 | Emulate = RUN; | ||
| 125 | } | ||
| 126 | |||
| 127 | // Resets certain MPCore CP15 values to their ARM-defined reset values. | ||
| 128 | void ARMul_State::ResetMPCoreCP15Registers() { | ||
| 129 | // c0 | ||
| 130 | CP15[CP15_MAIN_ID] = 0x410FB024; | ||
| 131 | CP15[CP15_TLB_TYPE] = 0x00000800; | ||
| 132 | CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; | ||
| 133 | CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; | ||
| 134 | CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; | ||
| 135 | CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; | ||
| 136 | CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; | ||
| 137 | CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; | ||
| 138 | CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; | ||
| 139 | CP15[CP15_ISA_FEATURE_0] = 0x00100011; | ||
| 140 | CP15[CP15_ISA_FEATURE_1] = 0x12002111; | ||
| 141 | CP15[CP15_ISA_FEATURE_2] = 0x11221011; | ||
| 142 | CP15[CP15_ISA_FEATURE_3] = 0x01102131; | ||
| 143 | CP15[CP15_ISA_FEATURE_4] = 0x00000141; | ||
| 144 | |||
| 145 | // c1 | ||
| 146 | CP15[CP15_CONTROL] = 0x00054078; | ||
| 147 | CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; | ||
| 148 | CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; | ||
| 149 | |||
| 150 | // c2 | ||
| 151 | CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; | ||
| 152 | CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; | ||
| 153 | CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; | ||
| 154 | |||
| 155 | // c3 | ||
| 156 | CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; | ||
| 157 | |||
| 158 | // c7 | ||
| 159 | CP15[CP15_PHYS_ADDRESS] = 0x00000000; | ||
| 160 | |||
| 161 | // c9 | ||
| 162 | CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; | ||
| 163 | |||
| 164 | // c10 | ||
| 165 | CP15[CP15_TLB_LOCKDOWN] = 0x00000000; | ||
| 166 | CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; | ||
| 167 | CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; | ||
| 168 | |||
| 169 | // c13 | ||
| 170 | CP15[CP15_PID] = 0x00000000; | ||
| 171 | CP15[CP15_CONTEXT_ID] = 0x00000000; | ||
| 172 | CP15[CP15_THREAD_UPRW] = 0x00000000; | ||
| 173 | CP15[CP15_THREAD_URO] = 0x00000000; | ||
| 174 | CP15[CP15_THREAD_PRW] = 0x00000000; | ||
| 175 | |||
| 176 | // c15 | ||
| 177 | CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; | ||
| 178 | CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; | ||
| 179 | CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; | ||
| 180 | CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; | ||
| 181 | CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | ||
| 182 | } | ||
| 183 | |||
| 184 | static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { | ||
| 185 | if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { | ||
| 186 | LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address); | ||
| 187 | GDBStub::Break(true); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | u8 ARMul_State::ReadMemory8(u32 address) const { | ||
| 192 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 193 | |||
| 194 | return Memory::Read8(address); | ||
| 195 | } | ||
| 196 | |||
| 197 | u16 ARMul_State::ReadMemory16(u32 address) const { | ||
| 198 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 199 | |||
| 200 | u16 data = Memory::Read16(address); | ||
| 201 | |||
| 202 | if (InBigEndianMode()) | ||
| 203 | data = Common::swap16(data); | ||
| 204 | |||
| 205 | return data; | ||
| 206 | } | ||
| 207 | |||
| 208 | u32 ARMul_State::ReadMemory32(u32 address) const { | ||
| 209 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 210 | |||
| 211 | u32 data = Memory::Read32(address); | ||
| 212 | |||
| 213 | if (InBigEndianMode()) | ||
| 214 | data = Common::swap32(data); | ||
| 215 | |||
| 216 | return data; | ||
| 217 | } | ||
| 218 | |||
| 219 | u64 ARMul_State::ReadMemory64(u32 address) const { | ||
| 220 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 221 | |||
| 222 | u64 data = Memory::Read64(address); | ||
| 223 | |||
| 224 | if (InBigEndianMode()) | ||
| 225 | data = Common::swap64(data); | ||
| 226 | |||
| 227 | return data; | ||
| 228 | } | ||
| 229 | |||
| 230 | void ARMul_State::WriteMemory8(u32 address, u8 data) { | ||
| 231 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 232 | |||
| 233 | Memory::Write8(address, data); | ||
| 234 | } | ||
| 235 | |||
| 236 | void ARMul_State::WriteMemory16(u32 address, u16 data) { | ||
| 237 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 238 | |||
| 239 | if (InBigEndianMode()) | ||
| 240 | data = Common::swap16(data); | ||
| 241 | |||
| 242 | Memory::Write16(address, data); | ||
| 243 | } | ||
| 244 | |||
| 245 | void ARMul_State::WriteMemory32(u32 address, u32 data) { | ||
| 246 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 247 | |||
| 248 | if (InBigEndianMode()) | ||
| 249 | data = Common::swap32(data); | ||
| 250 | |||
| 251 | Memory::Write32(address, data); | ||
| 252 | } | ||
| 253 | |||
| 254 | void ARMul_State::WriteMemory64(u32 address, u64 data) { | ||
| 255 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 256 | |||
| 257 | if (InBigEndianMode()) | ||
| 258 | data = Common::swap64(data); | ||
| 259 | |||
| 260 | Memory::Write64(address, data); | ||
| 261 | } | ||
| 262 | |||
| 263 | // Reads from the CP15 registers. Used with implementation of the MRC instruction. | ||
| 264 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 265 | // are not implemented. | ||
| 266 | u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const { | ||
| 267 | // Unprivileged registers | ||
| 268 | if (crn == 13 && opcode_1 == 0 && crm == 0) { | ||
| 269 | if (opcode_2 == 2) | ||
| 270 | return CP15[CP15_THREAD_UPRW]; | ||
| 271 | |||
| 272 | if (opcode_2 == 3) | ||
| 273 | return CP15[CP15_THREAD_URO]; | ||
| 274 | } | ||
| 275 | |||
| 276 | if (InAPrivilegedMode()) { | ||
| 277 | if (crn == 0 && opcode_1 == 0) { | ||
| 278 | if (crm == 0) { | ||
| 279 | if (opcode_2 == 0) | ||
| 280 | return CP15[CP15_MAIN_ID]; | ||
| 281 | |||
| 282 | if (opcode_2 == 1) | ||
| 283 | return CP15[CP15_CACHE_TYPE]; | ||
| 284 | |||
| 285 | if (opcode_2 == 3) | ||
| 286 | return CP15[CP15_TLB_TYPE]; | ||
| 287 | |||
| 288 | if (opcode_2 == 5) | ||
| 289 | return CP15[CP15_CPU_ID]; | ||
| 290 | } else if (crm == 1) { | ||
| 291 | if (opcode_2 == 0) | ||
| 292 | return CP15[CP15_PROCESSOR_FEATURE_0]; | ||
| 293 | |||
| 294 | if (opcode_2 == 1) | ||
| 295 | return CP15[CP15_PROCESSOR_FEATURE_1]; | ||
| 296 | |||
| 297 | if (opcode_2 == 2) | ||
| 298 | return CP15[CP15_DEBUG_FEATURE_0]; | ||
| 299 | |||
| 300 | if (opcode_2 == 4) | ||
| 301 | return CP15[CP15_MEMORY_MODEL_FEATURE_0]; | ||
| 302 | |||
| 303 | if (opcode_2 == 5) | ||
| 304 | return CP15[CP15_MEMORY_MODEL_FEATURE_1]; | ||
| 305 | |||
| 306 | if (opcode_2 == 6) | ||
| 307 | return CP15[CP15_MEMORY_MODEL_FEATURE_2]; | ||
| 308 | |||
| 309 | if (opcode_2 == 7) | ||
| 310 | return CP15[CP15_MEMORY_MODEL_FEATURE_3]; | ||
| 311 | } else if (crm == 2) { | ||
| 312 | if (opcode_2 == 0) | ||
| 313 | return CP15[CP15_ISA_FEATURE_0]; | ||
| 314 | |||
| 315 | if (opcode_2 == 1) | ||
| 316 | return CP15[CP15_ISA_FEATURE_1]; | ||
| 317 | |||
| 318 | if (opcode_2 == 2) | ||
| 319 | return CP15[CP15_ISA_FEATURE_2]; | ||
| 320 | |||
| 321 | if (opcode_2 == 3) | ||
| 322 | return CP15[CP15_ISA_FEATURE_3]; | ||
| 323 | |||
| 324 | if (opcode_2 == 4) | ||
| 325 | return CP15[CP15_ISA_FEATURE_4]; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | if (crn == 1 && opcode_1 == 0 && crm == 0) { | ||
| 330 | if (opcode_2 == 0) | ||
| 331 | return CP15[CP15_CONTROL]; | ||
| 332 | |||
| 333 | if (opcode_2 == 1) | ||
| 334 | return CP15[CP15_AUXILIARY_CONTROL]; | ||
| 335 | |||
| 336 | if (opcode_2 == 2) | ||
| 337 | return CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (crn == 2 && opcode_1 == 0 && crm == 0) { | ||
| 341 | if (opcode_2 == 0) | ||
| 342 | return CP15[CP15_TRANSLATION_BASE_TABLE_0]; | ||
| 343 | |||
| 344 | if (opcode_2 == 1) | ||
| 345 | return CP15[CP15_TRANSLATION_BASE_TABLE_1]; | ||
| 346 | |||
| 347 | if (opcode_2 == 2) | ||
| 348 | return CP15[CP15_TRANSLATION_BASE_CONTROL]; | ||
| 349 | } | ||
| 350 | |||
| 351 | if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 352 | return CP15[CP15_DOMAIN_ACCESS_CONTROL]; | ||
| 353 | |||
| 354 | if (crn == 5 && opcode_1 == 0 && crm == 0) { | ||
| 355 | if (opcode_2 == 0) | ||
| 356 | return CP15[CP15_FAULT_STATUS]; | ||
| 357 | |||
| 358 | if (opcode_2 == 1) | ||
| 359 | return CP15[CP15_INSTR_FAULT_STATUS]; | ||
| 360 | } | ||
| 361 | |||
| 362 | if (crn == 6 && opcode_1 == 0 && crm == 0) { | ||
| 363 | if (opcode_2 == 0) | ||
| 364 | return CP15[CP15_FAULT_ADDRESS]; | ||
| 365 | |||
| 366 | if (opcode_2 == 1) | ||
| 367 | return CP15[CP15_WFAR]; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) | ||
| 371 | return CP15[CP15_PHYS_ADDRESS]; | ||
| 372 | |||
| 373 | if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) | ||
| 374 | return CP15[CP15_DATA_CACHE_LOCKDOWN]; | ||
| 375 | |||
| 376 | if (crn == 10 && opcode_1 == 0) { | ||
| 377 | if (crm == 0 && opcode_2 == 0) | ||
| 378 | return CP15[CP15_TLB_LOCKDOWN]; | ||
| 379 | |||
| 380 | if (crm == 2) { | ||
| 381 | if (opcode_2 == 0) | ||
| 382 | return CP15[CP15_PRIMARY_REGION_REMAP]; | ||
| 383 | |||
| 384 | if (opcode_2 == 1) | ||
| 385 | return CP15[CP15_NORMAL_REGION_REMAP]; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | if (crn == 13 && crm == 0) { | ||
| 390 | if (opcode_2 == 0) | ||
| 391 | return CP15[CP15_PID]; | ||
| 392 | |||
| 393 | if (opcode_2 == 1) | ||
| 394 | return CP15[CP15_CONTEXT_ID]; | ||
| 395 | |||
| 396 | if (opcode_2 == 4) | ||
| 397 | return CP15[CP15_THREAD_PRW]; | ||
| 398 | } | ||
| 399 | |||
| 400 | if (crn == 15) { | ||
| 401 | if (opcode_1 == 0 && crm == 12) { | ||
| 402 | if (opcode_2 == 0) | ||
| 403 | return CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; | ||
| 404 | |||
| 405 | if (opcode_2 == 1) | ||
| 406 | return CP15[CP15_CYCLE_COUNTER]; | ||
| 407 | |||
| 408 | if (opcode_2 == 2) | ||
| 409 | return CP15[CP15_COUNT_0]; | ||
| 410 | |||
| 411 | if (opcode_2 == 3) | ||
| 412 | return CP15[CP15_COUNT_1]; | ||
| 413 | } | ||
| 414 | |||
| 415 | if (opcode_1 == 5 && opcode_2 == 2) { | ||
| 416 | if (crm == 5) | ||
| 417 | return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; | ||
| 418 | |||
| 419 | if (crm == 6) | ||
| 420 | return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; | ||
| 421 | |||
| 422 | if (crm == 7) | ||
| 423 | return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; | ||
| 424 | } | ||
| 425 | |||
| 426 | if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) | ||
| 427 | return CP15[CP15_TLB_DEBUG_CONTROL]; | ||
| 428 | } | ||
| 429 | } | ||
| 430 | |||
| 431 | LOG_ERROR(Core_ARM, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", | ||
| 432 | crn, crm, opcode_1, opcode_2); | ||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | // Write to the CP15 registers. Used with implementation of the MCR instruction. | ||
| 437 | // Note that since the 3DS does not have the hypervisor extensions, these registers | ||
| 438 | // are not implemented. | ||
| 439 | void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) { | ||
| 440 | if (InAPrivilegedMode()) { | ||
| 441 | if (crn == 1 && opcode_1 == 0 && crm == 0) { | ||
| 442 | if (opcode_2 == 0) | ||
| 443 | CP15[CP15_CONTROL] = value; | ||
| 444 | else if (opcode_2 == 1) | ||
| 445 | CP15[CP15_AUXILIARY_CONTROL] = value; | ||
| 446 | else if (opcode_2 == 2) | ||
| 447 | CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; | ||
| 448 | } else if (crn == 2 && opcode_1 == 0 && crm == 0) { | ||
| 449 | if (opcode_2 == 0) | ||
| 450 | CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; | ||
| 451 | else if (opcode_2 == 1) | ||
| 452 | CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; | ||
| 453 | else if (opcode_2 == 2) | ||
| 454 | CP15[CP15_TRANSLATION_BASE_CONTROL] = value; | ||
| 455 | } else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { | ||
| 456 | CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; | ||
| 457 | } else if (crn == 5 && opcode_1 == 0 && crm == 0) { | ||
| 458 | if (opcode_2 == 0) | ||
| 459 | CP15[CP15_FAULT_STATUS] = value; | ||
| 460 | else if (opcode_2 == 1) | ||
| 461 | CP15[CP15_INSTR_FAULT_STATUS] = value; | ||
| 462 | } else if (crn == 6 && opcode_1 == 0 && crm == 0) { | ||
| 463 | if (opcode_2 == 0) | ||
| 464 | CP15[CP15_FAULT_ADDRESS] = value; | ||
| 465 | else if (opcode_2 == 1) | ||
| 466 | CP15[CP15_WFAR] = value; | ||
| 467 | } else if (crn == 7 && opcode_1 == 0) { | ||
| 468 | if (crm == 0 && opcode_2 == 4) { | ||
| 469 | CP15[CP15_WAIT_FOR_INTERRUPT] = value; | ||
| 470 | } else if (crm == 4 && opcode_2 == 0) { | ||
| 471 | // NOTE: Not entirely accurate. This should do permission checks. | ||
| 472 | CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); | ||
| 473 | } else if (crm == 5) { | ||
| 474 | if (opcode_2 == 0) | ||
| 475 | CP15[CP15_INVALIDATE_INSTR_CACHE] = value; | ||
| 476 | else if (opcode_2 == 1) | ||
| 477 | CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; | ||
| 478 | else if (opcode_2 == 2) | ||
| 479 | CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; | ||
| 480 | else if (opcode_2 == 6) | ||
| 481 | CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; | ||
| 482 | else if (opcode_2 == 7) | ||
| 483 | CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; | ||
| 484 | } else if (crm == 6) { | ||
| 485 | if (opcode_2 == 0) | ||
| 486 | CP15[CP15_INVALIDATE_DATA_CACHE] = value; | ||
| 487 | else if (opcode_2 == 1) | ||
| 488 | CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 489 | else if (opcode_2 == 2) | ||
| 490 | CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 491 | } else if (crm == 7 && opcode_2 == 0) { | ||
| 492 | CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; | ||
| 493 | } else if (crm == 10) { | ||
| 494 | if (opcode_2 == 0) | ||
| 495 | CP15[CP15_CLEAN_DATA_CACHE] = value; | ||
| 496 | else if (opcode_2 == 1) | ||
| 497 | CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 498 | else if (opcode_2 == 2) | ||
| 499 | CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 500 | } else if (crm == 14) { | ||
| 501 | if (opcode_2 == 0) | ||
| 502 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; | ||
| 503 | else if (opcode_2 == 1) | ||
| 504 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; | ||
| 505 | else if (opcode_2 == 2) | ||
| 506 | CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; | ||
| 507 | } | ||
| 508 | } else if (crn == 8 && opcode_1 == 0) { | ||
| 509 | if (crm == 5) { | ||
| 510 | if (opcode_2 == 0) | ||
| 511 | CP15[CP15_INVALIDATE_ITLB] = value; | ||
| 512 | else if (opcode_2 == 1) | ||
| 513 | CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; | ||
| 514 | else if (opcode_2 == 2) | ||
| 515 | CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 516 | else if (opcode_2 == 3) | ||
| 517 | CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; | ||
| 518 | } else if (crm == 6) { | ||
| 519 | if (opcode_2 == 0) | ||
| 520 | CP15[CP15_INVALIDATE_DTLB] = value; | ||
| 521 | else if (opcode_2 == 1) | ||
| 522 | CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; | ||
| 523 | else if (opcode_2 == 2) | ||
| 524 | CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 525 | else if (opcode_2 == 3) | ||
| 526 | CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; | ||
| 527 | } else if (crm == 7) { | ||
| 528 | if (opcode_2 == 0) | ||
| 529 | CP15[CP15_INVALIDATE_UTLB] = value; | ||
| 530 | else if (opcode_2 == 1) | ||
| 531 | CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; | ||
| 532 | else if (opcode_2 == 2) | ||
| 533 | CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; | ||
| 534 | else if (opcode_2 == 3) | ||
| 535 | CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; | ||
| 536 | } | ||
| 537 | } else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { | ||
| 538 | CP15[CP15_DATA_CACHE_LOCKDOWN] = value; | ||
| 539 | } else if (crn == 10 && opcode_1 == 0) { | ||
| 540 | if (crm == 0 && opcode_2 == 0) { | ||
| 541 | CP15[CP15_TLB_LOCKDOWN] = value; | ||
| 542 | } else if (crm == 2) { | ||
| 543 | if (opcode_2 == 0) | ||
| 544 | CP15[CP15_PRIMARY_REGION_REMAP] = value; | ||
| 545 | else if (opcode_2 == 1) | ||
| 546 | CP15[CP15_NORMAL_REGION_REMAP] = value; | ||
| 547 | } | ||
| 548 | } else if (crn == 13 && opcode_1 == 0 && crm == 0) { | ||
| 549 | if (opcode_2 == 0) | ||
| 550 | CP15[CP15_PID] = value; | ||
| 551 | else if (opcode_2 == 1) | ||
| 552 | CP15[CP15_CONTEXT_ID] = value; | ||
| 553 | else if (opcode_2 == 3) | ||
| 554 | CP15[CP15_THREAD_URO] = value; | ||
| 555 | else if (opcode_2 == 4) | ||
| 556 | CP15[CP15_THREAD_PRW] = value; | ||
| 557 | } else if (crn == 15) { | ||
| 558 | if (opcode_1 == 0 && crm == 12) { | ||
| 559 | if (opcode_2 == 0) | ||
| 560 | CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; | ||
| 561 | else if (opcode_2 == 1) | ||
| 562 | CP15[CP15_CYCLE_COUNTER] = value; | ||
| 563 | else if (opcode_2 == 2) | ||
| 564 | CP15[CP15_COUNT_0] = value; | ||
| 565 | else if (opcode_2 == 3) | ||
| 566 | CP15[CP15_COUNT_1] = value; | ||
| 567 | } else if (opcode_1 == 5) { | ||
| 568 | if (crm == 4) { | ||
| 569 | if (opcode_2 == 2) | ||
| 570 | CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 571 | else if (opcode_2 == 4) | ||
| 572 | CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; | ||
| 573 | } else if (crm == 5 && opcode_2 == 2) { | ||
| 574 | CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; | ||
| 575 | } else if (crm == 6 && opcode_2 == 2) { | ||
| 576 | CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; | ||
| 577 | } else if (crm == 7 && opcode_2 == 2) { | ||
| 578 | CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; | ||
| 579 | } | ||
| 580 | } else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) { | ||
| 581 | CP15[CP15_TLB_DEBUG_CONTROL] = value; | ||
| 582 | } | ||
| 583 | } | ||
| 584 | } | ||
| 585 | |||
| 586 | // Unprivileged registers | ||
| 587 | if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) { | ||
| 588 | CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; | ||
| 589 | } else if (crn == 7 && opcode_1 == 0 && crm == 10) { | ||
| 590 | if (opcode_2 == 4) | ||
| 591 | CP15[CP15_DATA_SYNC_BARRIER] = value; | ||
| 592 | else if (opcode_2 == 5) | ||
| 593 | CP15[CP15_DATA_MEMORY_BARRIER] = value; | ||
| 594 | } else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) { | ||
| 595 | CP15[CP15_THREAD_UPRW] = value; | ||
| 596 | } | ||
| 597 | } | ||
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h deleted file mode 100644 index 893877797..000000000 --- a/src/core/arm/skyeye_common/armstate.h +++ /dev/null | |||
| @@ -1,245 +0,0 @@ | |||
| 1 | /* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #pragma once | ||
| 19 | |||
| 20 | #include <array> | ||
| 21 | #include <unordered_map> | ||
| 22 | #include "common/common_types.h" | ||
| 23 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 24 | |||
| 25 | // Signal levels | ||
| 26 | enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 }; | ||
| 27 | |||
| 28 | // Cache types | ||
| 29 | enum { | ||
| 30 | NONCACHE = 0, | ||
| 31 | DATACACHE = 1, | ||
| 32 | INSTCACHE = 2, | ||
| 33 | }; | ||
| 34 | |||
| 35 | // ARM privilege modes | ||
| 36 | enum PrivilegeMode { | ||
| 37 | USER32MODE = 16, | ||
| 38 | FIQ32MODE = 17, | ||
| 39 | IRQ32MODE = 18, | ||
| 40 | SVC32MODE = 19, | ||
| 41 | ABORT32MODE = 23, | ||
| 42 | UNDEF32MODE = 27, | ||
| 43 | SYSTEM32MODE = 31 | ||
| 44 | }; | ||
| 45 | |||
| 46 | // ARM privilege mode register banks | ||
| 47 | enum { | ||
| 48 | USERBANK = 0, | ||
| 49 | FIQBANK = 1, | ||
| 50 | IRQBANK = 2, | ||
| 51 | SVCBANK = 3, | ||
| 52 | ABORTBANK = 4, | ||
| 53 | UNDEFBANK = 5, | ||
| 54 | DUMMYBANK = 6, | ||
| 55 | SYSTEMBANK = 7 | ||
| 56 | }; | ||
| 57 | |||
| 58 | // Hardware vector addresses | ||
| 59 | enum { | ||
| 60 | ARMResetV = 0, | ||
| 61 | ARMUndefinedInstrV = 4, | ||
| 62 | ARMSWIV = 8, | ||
| 63 | ARMPrefetchAbortV = 12, | ||
| 64 | ARMDataAbortV = 16, | ||
| 65 | ARMAddrExceptnV = 20, | ||
| 66 | ARMIRQV = 24, | ||
| 67 | ARMFIQV = 28, | ||
| 68 | ARMErrorV = 32, // This is an offset, not an address! | ||
| 69 | |||
| 70 | ARMul_ResetV = ARMResetV, | ||
| 71 | ARMul_UndefinedInstrV = ARMUndefinedInstrV, | ||
| 72 | ARMul_SWIV = ARMSWIV, | ||
| 73 | ARMul_PrefetchAbortV = ARMPrefetchAbortV, | ||
| 74 | ARMul_DataAbortV = ARMDataAbortV, | ||
| 75 | ARMul_AddrExceptnV = ARMAddrExceptnV, | ||
| 76 | ARMul_IRQV = ARMIRQV, | ||
| 77 | ARMul_FIQV = ARMFIQV | ||
| 78 | }; | ||
| 79 | |||
| 80 | // Coprocessor status values | ||
| 81 | enum { | ||
| 82 | ARMul_FIRST = 0, | ||
| 83 | ARMul_TRANSFER = 1, | ||
| 84 | ARMul_BUSY = 2, | ||
| 85 | ARMul_DATA = 3, | ||
| 86 | ARMul_INTERRUPT = 4, | ||
| 87 | ARMul_DONE = 0, | ||
| 88 | ARMul_CANT = 1, | ||
| 89 | ARMul_INC = 3 | ||
| 90 | }; | ||
| 91 | |||
| 92 | // Instruction condition codes | ||
| 93 | enum ConditionCode { | ||
| 94 | EQ = 0, | ||
| 95 | NE = 1, | ||
| 96 | CS = 2, | ||
| 97 | CC = 3, | ||
| 98 | MI = 4, | ||
| 99 | PL = 5, | ||
| 100 | VS = 6, | ||
| 101 | VC = 7, | ||
| 102 | HI = 8, | ||
| 103 | LS = 9, | ||
| 104 | GE = 10, | ||
| 105 | LT = 11, | ||
| 106 | GT = 12, | ||
| 107 | LE = 13, | ||
| 108 | AL = 14, | ||
| 109 | NV = 15, | ||
| 110 | }; | ||
| 111 | |||
| 112 | // Flags for use with the APSR. | ||
| 113 | enum : u32 { | ||
| 114 | NBIT = (1U << 31U), | ||
| 115 | ZBIT = (1 << 30), | ||
| 116 | CBIT = (1 << 29), | ||
| 117 | VBIT = (1 << 28), | ||
| 118 | QBIT = (1 << 27), | ||
| 119 | JBIT = (1 << 24), | ||
| 120 | EBIT = (1 << 9), | ||
| 121 | ABIT = (1 << 8), | ||
| 122 | IBIT = (1 << 7), | ||
| 123 | FBIT = (1 << 6), | ||
| 124 | TBIT = (1 << 5), | ||
| 125 | |||
| 126 | // Masks for groups of bits in the APSR. | ||
| 127 | MODEBITS = 0x1F, | ||
| 128 | INTBITS = 0x1C0, | ||
| 129 | }; | ||
| 130 | |||
| 131 | // Values for Emulate. | ||
| 132 | enum { | ||
| 133 | STOP = 0, // Stop | ||
| 134 | CHANGEMODE = 1, // Change mode | ||
| 135 | ONCE = 2, // Execute just one iteration | ||
| 136 | RUN = 3 // Continuous execution | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct ARMul_State final { | ||
| 140 | public: | ||
| 141 | explicit ARMul_State(PrivilegeMode initial_mode); | ||
| 142 | |||
| 143 | void ChangePrivilegeMode(u32 new_mode); | ||
| 144 | void Reset(); | ||
| 145 | |||
| 146 | // Reads/writes data in big/little endian format based on the | ||
| 147 | // state of the E (endian) bit in the APSR. | ||
| 148 | u8 ReadMemory8(u32 address) const; | ||
| 149 | u16 ReadMemory16(u32 address) const; | ||
| 150 | u32 ReadMemory32(u32 address) const; | ||
| 151 | u64 ReadMemory64(u32 address) const; | ||
| 152 | void WriteMemory8(u32 address, u8 data); | ||
| 153 | void WriteMemory16(u32 address, u16 data); | ||
| 154 | void WriteMemory32(u32 address, u32 data); | ||
| 155 | void WriteMemory64(u32 address, u64 data); | ||
| 156 | |||
| 157 | u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; | ||
| 158 | void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); | ||
| 159 | |||
| 160 | // Exclusive memory access functions | ||
| 161 | bool IsExclusiveMemoryAccess(u32 address) const { | ||
| 162 | return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK); | ||
| 163 | } | ||
| 164 | void SetExclusiveMemoryAddress(u32 address) { | ||
| 165 | exclusive_tag = address & RESERVATION_GRANULE_MASK; | ||
| 166 | exclusive_state = true; | ||
| 167 | } | ||
| 168 | void UnsetExclusiveMemoryAddress() { | ||
| 169 | exclusive_tag = 0xFFFFFFFF; | ||
| 170 | exclusive_state = false; | ||
| 171 | } | ||
| 172 | |||
| 173 | // Whether or not the given CPU is in big endian mode (E bit is set) | ||
| 174 | bool InBigEndianMode() const { | ||
| 175 | return (Cpsr & (1 << 9)) != 0; | ||
| 176 | } | ||
| 177 | // Whether or not the given CPU is in a mode other than user mode. | ||
| 178 | bool InAPrivilegedMode() const { | ||
| 179 | return (Mode != USER32MODE); | ||
| 180 | } | ||
| 181 | // Note that for the 3DS, a Thumb instruction will only ever be | ||
| 182 | // two bytes in size. Thus we don't need to worry about ThumbEE | ||
| 183 | // or Thumb-2 where instructions can be 4 bytes in length. | ||
| 184 | u32 GetInstructionSize() const { | ||
| 185 | return TFlag ? 2 : 4; | ||
| 186 | } | ||
| 187 | |||
| 188 | std::array<u32, 16> Reg{}; // The current register file | ||
| 189 | std::array<u32, 2> Reg_usr{}; | ||
| 190 | std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC | ||
| 191 | std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT | ||
| 192 | std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF | ||
| 193 | std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ | ||
| 194 | std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ | ||
| 195 | std::array<u32, 7> Spsr{}; // The exception psr's | ||
| 196 | std::array<u32, CP15_REGISTER_COUNT> CP15{}; | ||
| 197 | |||
| 198 | // FPSID, FPSCR, and FPEXC | ||
| 199 | std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{}; | ||
| 200 | |||
| 201 | // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). | ||
| 202 | // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), | ||
| 203 | // and only 32 singleword registers are accessible (S0-S31). | ||
| 204 | std::array<u32, 64> ExtReg{}; | ||
| 205 | |||
| 206 | u32 Emulate; // To start and stop emulation | ||
| 207 | u32 Cpsr; // The current PSR | ||
| 208 | u32 Spsr_copy; | ||
| 209 | u32 phys_pc; | ||
| 210 | |||
| 211 | u32 Mode; // The current mode | ||
| 212 | u32 Bank; // The current register bank | ||
| 213 | |||
| 214 | u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed | ||
| 215 | unsigned int shifter_carry_out; | ||
| 216 | |||
| 217 | u32 TFlag; // Thumb state | ||
| 218 | |||
| 219 | unsigned long long NumInstrs; // The number of instructions executed | ||
| 220 | unsigned NumInstrsToExecute; | ||
| 221 | |||
| 222 | unsigned NresetSig; // Reset the processor | ||
| 223 | unsigned NfiqSig; | ||
| 224 | unsigned NirqSig; | ||
| 225 | |||
| 226 | unsigned abortSig; | ||
| 227 | unsigned NtransSig; | ||
| 228 | unsigned bigendSig; | ||
| 229 | unsigned syscallSig; | ||
| 230 | |||
| 231 | // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per | ||
| 232 | // process for our purposes), not per ARMul_State (which tracks CPU core state). | ||
| 233 | std::unordered_map<u32, std::size_t> instruction_cache; | ||
| 234 | |||
| 235 | private: | ||
| 236 | void ResetMPCoreCP15Registers(); | ||
| 237 | |||
| 238 | // Defines a reservation granule of 2 words, which protects the first 2 words starting at the | ||
| 239 | // tag. This is the smallest granule allowed by the v7 spec, and is coincidentally just large | ||
| 240 | // enough to support LDR/STREXD. | ||
| 241 | static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; | ||
| 242 | |||
| 243 | u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode | ||
| 244 | bool exclusive_state; | ||
| 245 | }; | ||
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp deleted file mode 100644 index 06aa1b075..000000000 --- a/src/core/arm/skyeye_common/armsupp.cpp +++ /dev/null | |||
| @@ -1,189 +0,0 @@ | |||
| 1 | /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. | ||
| 2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 2 of the License, or | ||
| 7 | (at your option) any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; if not, write to the Free Software | ||
| 16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | ||
| 17 | |||
| 18 | #include "common/logging/log.h" | ||
| 19 | #include "core/arm/skyeye_common/arm_regformat.h" | ||
| 20 | #include "core/arm/skyeye_common/armstate.h" | ||
| 21 | #include "core/arm/skyeye_common/armsupp.h" | ||
| 22 | |||
| 23 | // Unsigned sum of absolute difference | ||
| 24 | u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) { | ||
| 25 | if (left > right) | ||
| 26 | return left - right; | ||
| 27 | |||
| 28 | return right - left; | ||
| 29 | } | ||
| 30 | |||
| 31 | // Add with carry, indicates if a carry-out or signed overflow occurred. | ||
| 32 | u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, | ||
| 33 | bool* overflow_occurred) { | ||
| 34 | u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in; | ||
| 35 | s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in; | ||
| 36 | u64 result = (unsigned_sum & 0xFFFFFFFF); | ||
| 37 | |||
| 38 | if (carry_out_occurred) | ||
| 39 | *carry_out_occurred = (result != unsigned_sum); | ||
| 40 | |||
| 41 | if (overflow_occurred) | ||
| 42 | *overflow_occurred = ((s64)(s32)result != signed_sum); | ||
| 43 | |||
| 44 | return (u32)result; | ||
| 45 | } | ||
| 46 | |||
| 47 | // Compute whether an addition of A and B, giving RESULT, overflowed. | ||
| 48 | bool AddOverflow(u32 a, u32 b, u32 result) { | ||
| 49 | return ((NEG(a) && NEG(b) && POS(result)) || (POS(a) && POS(b) && NEG(result))); | ||
| 50 | } | ||
| 51 | |||
| 52 | // Compute whether a subtraction of A and B, giving RESULT, overflowed. | ||
| 53 | bool SubOverflow(u32 a, u32 b, u32 result) { | ||
| 54 | return ((NEG(a) && POS(b) && POS(result)) || (POS(a) && NEG(b) && NEG(result))); | ||
| 55 | } | ||
| 56 | |||
| 57 | // Returns true if the Q flag should be set as a result of overflow. | ||
| 58 | bool ARMul_AddOverflowQ(u32 a, u32 b) { | ||
| 59 | u32 result = a + b; | ||
| 60 | if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) | ||
| 61 | return true; | ||
| 62 | |||
| 63 | return false; | ||
| 64 | } | ||
| 65 | |||
| 66 | // 8-bit signed saturated addition | ||
| 67 | u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) { | ||
| 68 | u8 result = left + right; | ||
| 69 | |||
| 70 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) { | ||
| 71 | if (left & 0x80) | ||
| 72 | result = 0x80; | ||
| 73 | else | ||
| 74 | result = 0x7F; | ||
| 75 | } | ||
| 76 | |||
| 77 | return result; | ||
| 78 | } | ||
| 79 | |||
| 80 | // 8-bit signed saturated subtraction | ||
| 81 | u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) { | ||
| 82 | u8 result = left - right; | ||
| 83 | |||
| 84 | if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) { | ||
| 85 | if (left & 0x80) | ||
| 86 | result = 0x80; | ||
| 87 | else | ||
| 88 | result = 0x7F; | ||
| 89 | } | ||
| 90 | |||
| 91 | return result; | ||
| 92 | } | ||
| 93 | |||
| 94 | // 16-bit signed saturated addition | ||
| 95 | u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) { | ||
| 96 | u16 result = left + right; | ||
| 97 | |||
| 98 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) { | ||
| 99 | if (left & 0x8000) | ||
| 100 | result = 0x8000; | ||
| 101 | else | ||
| 102 | result = 0x7FFF; | ||
| 103 | } | ||
| 104 | |||
| 105 | return result; | ||
| 106 | } | ||
| 107 | |||
| 108 | // 16-bit signed saturated subtraction | ||
| 109 | u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) { | ||
| 110 | u16 result = left - right; | ||
| 111 | |||
| 112 | if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) { | ||
| 113 | if (left & 0x8000) | ||
| 114 | result = 0x8000; | ||
| 115 | else | ||
| 116 | result = 0x7FFF; | ||
| 117 | } | ||
| 118 | |||
| 119 | return result; | ||
| 120 | } | ||
| 121 | |||
| 122 | // 8-bit unsigned saturated addition | ||
| 123 | u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) { | ||
| 124 | u8 result = left + right; | ||
| 125 | |||
| 126 | if (result < left) | ||
| 127 | result = 0xFF; | ||
| 128 | |||
| 129 | return result; | ||
| 130 | } | ||
| 131 | |||
| 132 | // 16-bit unsigned saturated addition | ||
| 133 | u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) { | ||
| 134 | u16 result = left + right; | ||
| 135 | |||
| 136 | if (result < left) | ||
| 137 | result = 0xFFFF; | ||
| 138 | |||
| 139 | return result; | ||
| 140 | } | ||
| 141 | |||
| 142 | // 8-bit unsigned saturated subtraction | ||
| 143 | u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) { | ||
| 144 | if (left <= right) | ||
| 145 | return 0; | ||
| 146 | |||
| 147 | return left - right; | ||
| 148 | } | ||
| 149 | |||
| 150 | // 16-bit unsigned saturated subtraction | ||
| 151 | u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) { | ||
| 152 | if (left <= right) | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | return left - right; | ||
| 156 | } | ||
| 157 | |||
| 158 | // Signed saturation. | ||
| 159 | u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { | ||
| 160 | const u32 max = (1 << shift) - 1; | ||
| 161 | const s32 top = (value >> shift); | ||
| 162 | |||
| 163 | if (top > 0) { | ||
| 164 | *saturation_occurred = true; | ||
| 165 | return max; | ||
| 166 | } else if (top < -1) { | ||
| 167 | *saturation_occurred = true; | ||
| 168 | return ~max; | ||
| 169 | } | ||
| 170 | |||
| 171 | *saturation_occurred = false; | ||
| 172 | return (u32)value; | ||
| 173 | } | ||
| 174 | |||
| 175 | // Unsigned saturation | ||
| 176 | u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { | ||
| 177 | const u32 max = (1 << shift) - 1; | ||
| 178 | |||
| 179 | if (value < 0) { | ||
| 180 | *saturation_occurred = true; | ||
| 181 | return 0; | ||
| 182 | } else if ((u32)value > max) { | ||
| 183 | *saturation_occurred = true; | ||
| 184 | return max; | ||
| 185 | } | ||
| 186 | |||
| 187 | *saturation_occurred = false; | ||
| 188 | return (u32)value; | ||
| 189 | } | ||
diff --git a/src/core/arm/skyeye_common/armsupp.h b/src/core/arm/skyeye_common/armsupp.h deleted file mode 100644 index bf9299c07..000000000 --- a/src/core/arm/skyeye_common/armsupp.h +++ /dev/null | |||
| @@ -1,32 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) | ||
| 10 | #define BIT(s, n) ((s >> (n)) & 1) | ||
| 11 | |||
| 12 | #define POS(i) ((~(i)) >> 31) | ||
| 13 | #define NEG(i) ((i) >> 31) | ||
| 14 | |||
| 15 | bool AddOverflow(u32, u32, u32); | ||
| 16 | bool SubOverflow(u32, u32, u32); | ||
| 17 | |||
| 18 | u32 AddWithCarry(u32, u32, u32, bool*, bool*); | ||
| 19 | bool ARMul_AddOverflowQ(u32, u32); | ||
| 20 | |||
| 21 | u8 ARMul_SignedSaturatedAdd8(u8, u8); | ||
| 22 | u8 ARMul_SignedSaturatedSub8(u8, u8); | ||
| 23 | u16 ARMul_SignedSaturatedAdd16(u16, u16); | ||
| 24 | u16 ARMul_SignedSaturatedSub16(u16, u16); | ||
| 25 | |||
| 26 | u8 ARMul_UnsignedSaturatedAdd8(u8, u8); | ||
| 27 | u16 ARMul_UnsignedSaturatedAdd16(u16, u16); | ||
| 28 | u8 ARMul_UnsignedSaturatedSub8(u8, u8); | ||
| 29 | u16 ARMul_UnsignedSaturatedSub16(u16, u16); | ||
| 30 | u8 ARMul_UnsignedAbsoluteDifference(u8, u8); | ||
| 31 | u32 ARMul_SignedSatQ(s32, u8, bool*); | ||
| 32 | u32 ARMul_UnsignedSatQ(s32, u8, bool*); | ||
diff --git a/src/core/arm/skyeye_common/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h deleted file mode 100644 index 15b2394eb..000000000 --- a/src/core/arm/skyeye_common/vfp/asm_vfp.h +++ /dev/null | |||
| @@ -1,83 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * arch/arm/include/asm/vfp.h | ||
| 3 | * | ||
| 4 | * VFP register definitions. | ||
| 5 | * First, the standard VFP set. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | // ARM11 MPCore FPSID Information | ||
| 11 | // Note that these are used as values and not as flags. | ||
| 12 | enum : u32 { | ||
| 13 | VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0 | ||
| 14 | VFP_FPSID_SW = 0, // Software emulation bit value | ||
| 15 | VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number | ||
| 16 | VFP_FPSID_PARTNUM = 0x20, // Part number | ||
| 17 | VFP_FPSID_VARIANT = 0xB, // Variant number | ||
| 18 | VFP_FPSID_REVISION = 0x4 // Revision number | ||
| 19 | }; | ||
| 20 | |||
| 21 | // FPEXC bits | ||
| 22 | enum : u32 { | ||
| 23 | FPEXC_EX = (1U << 31U), | ||
| 24 | FPEXC_EN = (1 << 30), | ||
| 25 | FPEXC_DEX = (1 << 29), | ||
| 26 | FPEXC_FP2V = (1 << 28), | ||
| 27 | FPEXC_VV = (1 << 27), | ||
| 28 | FPEXC_TFV = (1 << 26), | ||
| 29 | FPEXC_LENGTH_BIT = (8), | ||
| 30 | FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT), | ||
| 31 | FPEXC_IDF = (1 << 7), | ||
| 32 | FPEXC_IXF = (1 << 4), | ||
| 33 | FPEXC_UFF = (1 << 3), | ||
| 34 | FPEXC_OFF = (1 << 2), | ||
| 35 | FPEXC_DZF = (1 << 1), | ||
| 36 | FPEXC_IOF = (1 << 0), | ||
| 37 | FPEXC_TRAP_MASK = (FPEXC_IDF | FPEXC_IXF | FPEXC_UFF | FPEXC_OFF | FPEXC_DZF | FPEXC_IOF) | ||
| 38 | }; | ||
| 39 | |||
| 40 | // FPSCR Flags | ||
| 41 | enum : u32 { | ||
| 42 | FPSCR_NFLAG = (1U << 31U), // Negative condition flag | ||
| 43 | FPSCR_ZFLAG = (1 << 30), // Zero condition flag | ||
| 44 | FPSCR_CFLAG = (1 << 29), // Carry condition flag | ||
| 45 | FPSCR_VFLAG = (1 << 28), // Overflow condition flag | ||
| 46 | |||
| 47 | FPSCR_QC = (1 << 27), // Cumulative saturation bit | ||
| 48 | FPSCR_AHP = (1 << 26), // Alternative half-precision control bit | ||
| 49 | FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit | ||
| 50 | FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit | ||
| 51 | FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask | ||
| 52 | FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask | ||
| 53 | FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask | ||
| 54 | |||
| 55 | FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable. | ||
| 56 | FPSCR_IXE = (1 << 12), // Inexact exception trap enable | ||
| 57 | FPSCR_UFE = (1 << 11), // Undeflow exception trap enable | ||
| 58 | FPSCR_OFE = (1 << 10), // Overflow exception trap enable | ||
| 59 | FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable | ||
| 60 | FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable | ||
| 61 | |||
| 62 | FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit | ||
| 63 | FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit | ||
| 64 | FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit | ||
| 65 | FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit | ||
| 66 | FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit | ||
| 67 | FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit | ||
| 68 | }; | ||
| 69 | |||
| 70 | // FPSCR bit offsets | ||
| 71 | enum : u32 { | ||
| 72 | FPSCR_RMODE_BIT = 22, | ||
| 73 | FPSCR_STRIDE_BIT = 20, | ||
| 74 | FPSCR_LENGTH_BIT = 16, | ||
| 75 | }; | ||
| 76 | |||
| 77 | // FPSCR rounding modes | ||
| 78 | enum : u32 { | ||
| 79 | FPSCR_ROUND_NEAREST = (0 << 22), | ||
| 80 | FPSCR_ROUND_PLUSINF = (1 << 22), | ||
| 81 | FPSCR_ROUND_MINUSINF = (2 << 22), | ||
| 82 | FPSCR_ROUND_TOZERO = (3 << 22) | ||
| 83 | }; | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp deleted file mode 100644 index 0466b999a..000000000 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ /dev/null | |||
| @@ -1,137 +0,0 @@ | |||
| 1 | /* | ||
| 2 | armvfp.c - ARM VFPv3 emulation unit | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* Note: this file handles interface with arm core and vfp registers */ | ||
| 22 | |||
| 23 | #include "common/common_funcs.h" | ||
| 24 | #include "common/common_types.h" | ||
| 25 | #include "common/logging/log.h" | ||
| 26 | #include "core/arm/skyeye_common/armstate.h" | ||
| 27 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 28 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 29 | |||
| 30 | void VFPInit(ARMul_State* state) { | ||
| 31 | state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN << 24 | VFP_FPSID_SW << 23 | VFP_FPSID_SUBARCH << 16 | | ||
| 32 | VFP_FPSID_PARTNUM << 8 | VFP_FPSID_VARIANT << 4 | VFP_FPSID_REVISION; | ||
| 33 | state->VFP[VFP_FPEXC] = 0; | ||
| 34 | state->VFP[VFP_FPSCR] = 0; | ||
| 35 | |||
| 36 | // ARM11 MPCore instruction register reset values. | ||
| 37 | state->VFP[VFP_FPINST] = 0xEE000A00; | ||
| 38 | state->VFP[VFP_FPINST2] = 0; | ||
| 39 | |||
| 40 | // ARM11 MPCore feature register values. | ||
| 41 | state->VFP[VFP_MVFR0] = 0x11111111; | ||
| 42 | state->VFP[VFP_MVFR1] = 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) { | ||
| 46 | if (to_arm) { | ||
| 47 | *value = state->ExtReg[n]; | ||
| 48 | } else { | ||
| 49 | state->ExtReg[n] = *value; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { | ||
| 54 | if (to_arm) { | ||
| 55 | *value2 = state->ExtReg[n * 2 + 1]; | ||
| 56 | *value1 = state->ExtReg[n * 2]; | ||
| 57 | } else { | ||
| 58 | state->ExtReg[n * 2 + 1] = *value2; | ||
| 59 | state->ExtReg[n * 2] = *value1; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { | ||
| 63 | if (to_arm) { | ||
| 64 | *value1 = state->ExtReg[n + 0]; | ||
| 65 | *value2 = state->ExtReg[n + 1]; | ||
| 66 | } else { | ||
| 67 | state->ExtReg[n + 0] = *value1; | ||
| 68 | state->ExtReg[n + 1] = *value2; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) { | ||
| 73 | if (single) { | ||
| 74 | state->ExtReg[d] = imm; | ||
| 75 | } else { | ||
| 76 | /* Check endian please */ | ||
| 77 | state->ExtReg[d * 2 + 1] = imm; | ||
| 78 | state->ExtReg[d * 2] = 0; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) { | ||
| 82 | if (single) { | ||
| 83 | state->ExtReg[d] = state->ExtReg[m]; | ||
| 84 | } else { | ||
| 85 | /* Check endian please */ | ||
| 86 | state->ExtReg[d * 2 + 1] = state->ExtReg[m * 2 + 1]; | ||
| 87 | state->ExtReg[d * 2] = state->ExtReg[m * 2]; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | /* Miscellaneous functions */ | ||
| 92 | s32 vfp_get_float(ARMul_State* state, unsigned int reg) { | ||
| 93 | LOG_TRACE(Core_ARM, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]); | ||
| 94 | return state->ExtReg[reg]; | ||
| 95 | } | ||
| 96 | |||
| 97 | void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) { | ||
| 98 | LOG_TRACE(Core_ARM, "VFP put float: s%d <= [%08x]", reg, val); | ||
| 99 | state->ExtReg[reg] = val; | ||
| 100 | } | ||
| 101 | |||
| 102 | u64 vfp_get_double(ARMul_State* state, unsigned int reg) { | ||
| 103 | u64 result = ((u64)state->ExtReg[reg * 2 + 1]) << 32 | state->ExtReg[reg * 2]; | ||
| 104 | LOG_TRACE(Core_ARM, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result); | ||
| 105 | return result; | ||
| 106 | } | ||
| 107 | |||
| 108 | void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) { | ||
| 109 | LOG_TRACE(Core_ARM, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, | ||
| 110 | (u32)(val >> 32), (u32)(val & 0xffffffff)); | ||
| 111 | state->ExtReg[reg * 2] = (u32)(val & 0xffffffff); | ||
| 112 | state->ExtReg[reg * 2 + 1] = (u32)(val >> 32); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Process bitmask of exception conditions. (from vfpmodule.c) | ||
| 117 | */ | ||
| 118 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) { | ||
| 119 | LOG_TRACE(Core_ARM, "VFP: raising exceptions %08x", exceptions); | ||
| 120 | |||
| 121 | if (exceptions == VFP_EXCEPTION_ERROR) { | ||
| 122 | LOG_CRITICAL(Core_ARM, "unhandled bounce %x", inst); | ||
| 123 | Crash(); | ||
| 124 | } | ||
| 125 | |||
| 126 | /* | ||
| 127 | * If any of the status flags are set, update the FPSCR. | ||
| 128 | * Comparison instructions always return at least one of | ||
| 129 | * these flags set. | ||
| 130 | */ | ||
| 131 | if (exceptions & (FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG)) | ||
| 132 | fpscr &= ~(FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG); | ||
| 133 | |||
| 134 | fpscr |= exceptions; | ||
| 135 | |||
| 136 | state->VFP[VFP_FPSCR] = fpscr; | ||
| 137 | } | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h deleted file mode 100644 index fe9c4dac8..000000000 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #pragma once | ||
| 22 | |||
| 23 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ | ||
| 24 | |||
| 25 | #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM, "in func %s, " #x " untested", __FUNCTION__); | ||
| 26 | #define CHECK_VFP_ENABLED | ||
| 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 28 | |||
| 29 | void VFPInit(ARMul_State* state); | ||
| 30 | |||
| 31 | s32 vfp_get_float(ARMul_State* state, u32 reg); | ||
| 32 | void vfp_put_float(ARMul_State* state, s32 val, u32 reg); | ||
| 33 | u64 vfp_get_double(ARMul_State* state, u32 reg); | ||
| 34 | void vfp_put_double(ARMul_State* state, u64 val, u32 reg); | ||
| 35 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr); | ||
| 36 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | ||
| 37 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); | ||
| 38 | |||
| 39 | void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value); | ||
| 40 | void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); | ||
| 41 | void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); | ||
| 42 | void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm); | ||
| 43 | void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm); | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h deleted file mode 100644 index 1eba71b48..000000000 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ /dev/null | |||
| @@ -1,433 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * The following code is derivative from Linux Android kernel vfp | ||
| 23 | * floating point support. | ||
| 24 | * | ||
| 25 | * Copyright (C) 2004 ARM Limited. | ||
| 26 | * Written by Deep Blue Solutions Limited. | ||
| 27 | * | ||
| 28 | * This program is free software; you can redistribute it and/or modify | ||
| 29 | * it under the terms of the GNU General Public License version 2 as | ||
| 30 | * published by the Free Software Foundation. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #pragma once | ||
| 34 | |||
| 35 | #include <cstdio> | ||
| 36 | #include "common/common_types.h" | ||
| 37 | #include "core/arm/skyeye_common/armstate.h" | ||
| 38 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 39 | |||
| 40 | #define do_div(n, base) \ | ||
| 41 | { n /= base; } | ||
| 42 | |||
| 43 | enum : u32 { | ||
| 44 | FOP_MASK = 0x00b00040, | ||
| 45 | FOP_FMAC = 0x00000000, | ||
| 46 | FOP_FNMAC = 0x00000040, | ||
| 47 | FOP_FMSC = 0x00100000, | ||
| 48 | FOP_FNMSC = 0x00100040, | ||
| 49 | FOP_FMUL = 0x00200000, | ||
| 50 | FOP_FNMUL = 0x00200040, | ||
| 51 | FOP_FADD = 0x00300000, | ||
| 52 | FOP_FSUB = 0x00300040, | ||
| 53 | FOP_FDIV = 0x00800000, | ||
| 54 | FOP_EXT = 0x00b00040 | ||
| 55 | }; | ||
| 56 | |||
| 57 | #define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) | ||
| 58 | |||
| 59 | enum : u32 { | ||
| 60 | FEXT_MASK = 0x000f0080, | ||
| 61 | FEXT_FCPY = 0x00000000, | ||
| 62 | FEXT_FABS = 0x00000080, | ||
| 63 | FEXT_FNEG = 0x00010000, | ||
| 64 | FEXT_FSQRT = 0x00010080, | ||
| 65 | FEXT_FCMP = 0x00040000, | ||
| 66 | FEXT_FCMPE = 0x00040080, | ||
| 67 | FEXT_FCMPZ = 0x00050000, | ||
| 68 | FEXT_FCMPEZ = 0x00050080, | ||
| 69 | FEXT_FCVT = 0x00070080, | ||
| 70 | FEXT_FUITO = 0x00080000, | ||
| 71 | FEXT_FSITO = 0x00080080, | ||
| 72 | FEXT_FTOUI = 0x000c0000, | ||
| 73 | FEXT_FTOUIZ = 0x000c0080, | ||
| 74 | FEXT_FTOSI = 0x000d0000, | ||
| 75 | FEXT_FTOSIZ = 0x000d0080 | ||
| 76 | }; | ||
| 77 | |||
| 78 | #define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) | ||
| 79 | |||
| 80 | #define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) | ||
| 81 | #define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) | ||
| 82 | #define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) | ||
| 83 | #define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) | ||
| 84 | #define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) | ||
| 85 | #define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) | ||
| 86 | |||
| 87 | #define vfp_single(inst) (((inst)&0x0000f00) == 0xa00) | ||
| 88 | |||
| 89 | inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) { | ||
| 90 | if (shift) { | ||
| 91 | if (shift < 32) | ||
| 92 | val = val >> shift | ((val << (32 - shift)) != 0); | ||
| 93 | else | ||
| 94 | val = val != 0; | ||
| 95 | } | ||
| 96 | return val; | ||
| 97 | } | ||
| 98 | |||
| 99 | inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) { | ||
| 100 | if (shift) { | ||
| 101 | if (shift < 64) | ||
| 102 | val = val >> shift | ((val << (64 - shift)) != 0); | ||
| 103 | else | ||
| 104 | val = val != 0; | ||
| 105 | } | ||
| 106 | return val; | ||
| 107 | } | ||
| 108 | |||
| 109 | inline u32 vfp_hi64to32jamming(u64 val) { | ||
| 110 | u32 v; | ||
| 111 | u32 highval = val >> 32; | ||
| 112 | u32 lowval = val & 0xffffffff; | ||
| 113 | |||
| 114 | if (lowval >= 1) | ||
| 115 | v = highval | 1; | ||
| 116 | else | ||
| 117 | v = highval; | ||
| 118 | |||
| 119 | return v; | ||
| 120 | } | ||
| 121 | |||
| 122 | inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { | ||
| 123 | *resl = nl + ml; | ||
| 124 | *resh = nh + mh; | ||
| 125 | if (*resl < nl) | ||
| 126 | *resh += 1; | ||
| 127 | } | ||
| 128 | |||
| 129 | inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { | ||
| 130 | *resl = nl - ml; | ||
| 131 | *resh = nh - mh; | ||
| 132 | if (*resl > nl) | ||
| 133 | *resh -= 1; | ||
| 134 | } | ||
| 135 | |||
| 136 | inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) { | ||
| 137 | u32 nh, nl, mh, ml; | ||
| 138 | u64 rh, rma, rmb, rl; | ||
| 139 | |||
| 140 | nl = static_cast<u32>(n); | ||
| 141 | ml = static_cast<u32>(m); | ||
| 142 | rl = (u64)nl * ml; | ||
| 143 | |||
| 144 | nh = n >> 32; | ||
| 145 | rma = (u64)nh * ml; | ||
| 146 | |||
| 147 | mh = m >> 32; | ||
| 148 | rmb = (u64)nl * mh; | ||
| 149 | rma += rmb; | ||
| 150 | |||
| 151 | rh = (u64)nh * mh; | ||
| 152 | rh += ((u64)(rma < rmb) << 32) + (rma >> 32); | ||
| 153 | |||
| 154 | rma <<= 32; | ||
| 155 | rl += rma; | ||
| 156 | rh += (rl < rma); | ||
| 157 | |||
| 158 | *resl = rl; | ||
| 159 | *resh = rh; | ||
| 160 | } | ||
| 161 | |||
| 162 | inline void shift64left(u64* resh, u64* resl, u64 n) { | ||
| 163 | *resh = n >> 63; | ||
| 164 | *resl = n << 1; | ||
| 165 | } | ||
| 166 | |||
| 167 | inline u64 vfp_hi64multiply64(u64 n, u64 m) { | ||
| 168 | u64 rh, rl; | ||
| 169 | mul64to128(&rh, &rl, n, m); | ||
| 170 | return rh | (rl != 0); | ||
| 171 | } | ||
| 172 | |||
| 173 | inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) { | ||
| 174 | u64 mh, ml, remh, reml, termh, terml, z; | ||
| 175 | |||
| 176 | if (nh >= m) | ||
| 177 | return ~0ULL; | ||
| 178 | mh = m >> 32; | ||
| 179 | if (mh << 32 <= nh) { | ||
| 180 | z = 0xffffffff00000000ULL; | ||
| 181 | } else { | ||
| 182 | z = nh; | ||
| 183 | do_div(z, mh); | ||
| 184 | z <<= 32; | ||
| 185 | } | ||
| 186 | mul64to128(&termh, &terml, m, z); | ||
| 187 | sub128(&remh, &reml, nh, nl, termh, terml); | ||
| 188 | ml = m << 32; | ||
| 189 | while ((s64)remh < 0) { | ||
| 190 | z -= 0x100000000ULL; | ||
| 191 | add128(&remh, &reml, remh, reml, mh, ml); | ||
| 192 | } | ||
| 193 | remh = (remh << 32) | (reml >> 32); | ||
| 194 | if (mh << 32 <= remh) { | ||
| 195 | z |= 0xffffffff; | ||
| 196 | } else { | ||
| 197 | do_div(remh, mh); | ||
| 198 | z |= remh; | ||
| 199 | } | ||
| 200 | return z; | ||
| 201 | } | ||
| 202 | |||
| 203 | // Operations on unpacked elements | ||
| 204 | #define vfp_sign_negate(sign) (sign ^ 0x8000) | ||
| 205 | |||
| 206 | // Single-precision | ||
| 207 | struct vfp_single { | ||
| 208 | s16 exponent; | ||
| 209 | u16 sign; | ||
| 210 | u32 significand; | ||
| 211 | }; | ||
| 212 | |||
| 213 | // VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa | ||
| 214 | // VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent | ||
| 215 | // VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand | ||
| 216 | // which are not propagated to the float upon packing. | ||
| 217 | #define VFP_SINGLE_MANTISSA_BITS (23) | ||
| 218 | #define VFP_SINGLE_EXPONENT_BITS (8) | ||
| 219 | #define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) | ||
| 220 | #define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) | ||
| 221 | |||
| 222 | // The bit in an unpacked float which indicates that it is a quiet NaN | ||
| 223 | #define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS)) | ||
| 224 | |||
| 225 | // Operations on packed single-precision numbers | ||
| 226 | #define vfp_single_packed_sign(v) ((v)&0x80000000) | ||
| 227 | #define vfp_single_packed_negate(v) ((v) ^ 0x80000000) | ||
| 228 | #define vfp_single_packed_abs(v) ((v) & ~0x80000000) | ||
| 229 | #define vfp_single_packed_exponent(v) \ | ||
| 230 | (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) | ||
| 231 | #define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) | ||
| 232 | |||
| 233 | enum : u32 { | ||
| 234 | VFP_NUMBER = (1 << 0), | ||
| 235 | VFP_ZERO = (1 << 1), | ||
| 236 | VFP_DENORMAL = (1 << 2), | ||
| 237 | VFP_INFINITY = (1 << 3), | ||
| 238 | VFP_NAN = (1 << 4), | ||
| 239 | VFP_NAN_SIGNAL = (1 << 5), | ||
| 240 | |||
| 241 | VFP_QNAN = (VFP_NAN), | ||
| 242 | VFP_SNAN = (VFP_NAN | VFP_NAN_SIGNAL) | ||
| 243 | }; | ||
| 244 | |||
| 245 | inline int vfp_single_type(const vfp_single* s) { | ||
| 246 | int type = VFP_NUMBER; | ||
| 247 | if (s->exponent == 255) { | ||
| 248 | if (s->significand == 0) | ||
| 249 | type = VFP_INFINITY; | ||
| 250 | else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) | ||
| 251 | type = VFP_QNAN; | ||
| 252 | else | ||
| 253 | type = VFP_SNAN; | ||
| 254 | } else if (s->exponent == 0) { | ||
| 255 | if (s->significand == 0) | ||
| 256 | type |= VFP_ZERO; | ||
| 257 | else | ||
| 258 | type |= VFP_DENORMAL; | ||
| 259 | } | ||
| 260 | return type; | ||
| 261 | } | ||
| 262 | |||
| 263 | // Unpack a single-precision float. Note that this returns the magnitude | ||
| 264 | // of the single-precision float mantissa with the 1. if necessary, | ||
| 265 | // aligned to bit 30. | ||
| 266 | inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) { | ||
| 267 | u32 exceptions = 0; | ||
| 268 | s->sign = vfp_single_packed_sign(val) >> 16, s->exponent = vfp_single_packed_exponent(val); | ||
| 269 | |||
| 270 | u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; | ||
| 271 | if (s->exponent && s->exponent != 255) | ||
| 272 | significand |= 0x40000000; | ||
| 273 | s->significand = significand; | ||
| 274 | |||
| 275 | // If flush-to-zero mode is enabled, turn the denormal into zero. | ||
| 276 | // On a VFPv2 architecture, the sign of the zero is always positive. | ||
| 277 | if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) { | ||
| 278 | s->sign = 0; | ||
| 279 | s->exponent = 0; | ||
| 280 | s->significand = 0; | ||
| 281 | exceptions |= FPSCR_IDC; | ||
| 282 | } | ||
| 283 | return exceptions; | ||
| 284 | } | ||
| 285 | |||
| 286 | // Re-pack a single-precision float. This assumes that the float is | ||
| 287 | // already normalised such that the MSB is bit 30, _not_ bit 31. | ||
| 288 | inline s32 vfp_single_pack(const vfp_single* s) { | ||
| 289 | u32 val = (s->sign << 16) + (s->exponent << VFP_SINGLE_MANTISSA_BITS) + | ||
| 290 | (s->significand >> VFP_SINGLE_LOW_BITS); | ||
| 291 | return (s32)val; | ||
| 292 | } | ||
| 293 | |||
| 294 | u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, | ||
| 295 | const char* func); | ||
| 296 | |||
| 297 | // Double-precision | ||
| 298 | struct vfp_double { | ||
| 299 | s16 exponent; | ||
| 300 | u16 sign; | ||
| 301 | u64 significand; | ||
| 302 | }; | ||
| 303 | |||
| 304 | // VFP_REG_ZERO is a special register number for vfp_get_double | ||
| 305 | // which returns (double)0.0. This is useful for the compare with | ||
| 306 | // zero instructions. | ||
| 307 | #ifdef CONFIG_VFPv3 | ||
| 308 | #define VFP_REG_ZERO 32 | ||
| 309 | #else | ||
| 310 | #define VFP_REG_ZERO 16 | ||
| 311 | #endif | ||
| 312 | |||
| 313 | #define VFP_DOUBLE_MANTISSA_BITS (52) | ||
| 314 | #define VFP_DOUBLE_EXPONENT_BITS (11) | ||
| 315 | #define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) | ||
| 316 | #define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) | ||
| 317 | |||
| 318 | // The bit in an unpacked double which indicates that it is a quiet NaN | ||
| 319 | #define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) | ||
| 320 | |||
| 321 | // Operations on packed single-precision numbers | ||
| 322 | #define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) | ||
| 323 | #define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) | ||
| 324 | #define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) | ||
| 325 | #define vfp_double_packed_exponent(v) \ | ||
| 326 | (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) | ||
| 327 | #define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) | ||
| 328 | |||
| 329 | inline int vfp_double_type(const vfp_double* s) { | ||
| 330 | int type = VFP_NUMBER; | ||
| 331 | if (s->exponent == 2047) { | ||
| 332 | if (s->significand == 0) | ||
| 333 | type = VFP_INFINITY; | ||
| 334 | else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) | ||
| 335 | type = VFP_QNAN; | ||
| 336 | else | ||
| 337 | type = VFP_SNAN; | ||
| 338 | } else if (s->exponent == 0) { | ||
| 339 | if (s->significand == 0) | ||
| 340 | type |= VFP_ZERO; | ||
| 341 | else | ||
| 342 | type |= VFP_DENORMAL; | ||
| 343 | } | ||
| 344 | return type; | ||
| 345 | } | ||
| 346 | |||
| 347 | // Unpack a double-precision float. Note that this returns the magnitude | ||
| 348 | // of the double-precision float mantissa with the 1. if necessary, | ||
| 349 | // aligned to bit 62. | ||
| 350 | inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) { | ||
| 351 | u32 exceptions = 0; | ||
| 352 | s->sign = vfp_double_packed_sign(val) >> 48; | ||
| 353 | s->exponent = vfp_double_packed_exponent(val); | ||
| 354 | |||
| 355 | u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; | ||
| 356 | if (s->exponent && s->exponent != 2047) | ||
| 357 | significand |= (1ULL << 62); | ||
| 358 | s->significand = significand; | ||
| 359 | |||
| 360 | // If flush-to-zero mode is enabled, turn the denormal into zero. | ||
| 361 | // On a VFPv2 architecture, the sign of the zero is always positive. | ||
| 362 | if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) { | ||
| 363 | s->sign = 0; | ||
| 364 | s->exponent = 0; | ||
| 365 | s->significand = 0; | ||
| 366 | exceptions |= FPSCR_IDC; | ||
| 367 | } | ||
| 368 | return exceptions; | ||
| 369 | } | ||
| 370 | |||
| 371 | // Re-pack a double-precision float. This assumes that the float is | ||
| 372 | // already normalised such that the MSB is bit 30, _not_ bit 31. | ||
| 373 | inline s64 vfp_double_pack(const vfp_double* s) { | ||
| 374 | u64 val = ((u64)s->sign << 48) + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + | ||
| 375 | (s->significand >> VFP_DOUBLE_LOW_BITS); | ||
| 376 | return (s64)val; | ||
| 377 | } | ||
| 378 | |||
| 379 | u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); | ||
| 380 | |||
| 381 | // A special flag to tell the normalisation code not to normalise. | ||
| 382 | #define VFP_NAN_FLAG 0x100 | ||
| 383 | |||
| 384 | // A bit pattern used to indicate the initial (unset) value of the | ||
| 385 | // exception mask, in case nothing handles an instruction. This | ||
| 386 | // doesn't include the NAN flag, which get masked out before | ||
| 387 | // we check for an error. | ||
| 388 | #define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) | ||
| 389 | |||
| 390 | // A flag to tell vfp instruction type. | ||
| 391 | // OP_SCALAR - This operation always operates in scalar mode | ||
| 392 | // OP_SD - The instruction exceptionally writes to a single precision result. | ||
| 393 | // OP_DD - The instruction exceptionally writes to a double precision result. | ||
| 394 | // OP_SM - The instruction exceptionally reads from a single precision operand. | ||
| 395 | enum : u32 { OP_SCALAR = (1 << 0), OP_SD = (1 << 1), OP_DD = (1 << 1), OP_SM = (1 << 2) }; | ||
| 396 | |||
| 397 | struct op { | ||
| 398 | u32 (*const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr); | ||
| 399 | u32 flags; | ||
| 400 | }; | ||
| 401 | |||
| 402 | inline u32 fls(u32 x) { | ||
| 403 | int r = 32; | ||
| 404 | |||
| 405 | if (!x) | ||
| 406 | return 0; | ||
| 407 | if (!(x & 0xffff0000u)) { | ||
| 408 | x <<= 16; | ||
| 409 | r -= 16; | ||
| 410 | } | ||
| 411 | if (!(x & 0xff000000u)) { | ||
| 412 | x <<= 8; | ||
| 413 | r -= 8; | ||
| 414 | } | ||
| 415 | if (!(x & 0xf0000000u)) { | ||
| 416 | x <<= 4; | ||
| 417 | r -= 4; | ||
| 418 | } | ||
| 419 | if (!(x & 0xc0000000u)) { | ||
| 420 | x <<= 2; | ||
| 421 | r -= 2; | ||
| 422 | } | ||
| 423 | if (!(x & 0x80000000u)) { | ||
| 424 | x <<= 1; | ||
| 425 | r -= 1; | ||
| 426 | } | ||
| 427 | return r; | ||
| 428 | } | ||
| 429 | |||
| 430 | u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); | ||
| 431 | u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); | ||
| 432 | u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions, | ||
| 433 | const char* func); | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp deleted file mode 100644 index e5cb54aab..000000000 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ /dev/null | |||
| @@ -1,1247 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include <algorithm> | ||
| 55 | #include "common/logging/log.h" | ||
| 56 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 57 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 58 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" | ||
| 59 | |||
| 60 | static struct vfp_double vfp_double_default_qnan = { | ||
| 61 | 2047, 0, VFP_DOUBLE_SIGNIFICAND_QNAN, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void vfp_double_dump(const char* str, struct vfp_double* d) { | ||
| 65 | LOG_TRACE(Core_ARM, "VFP: %s: sign=%d exponent=%d significand=%016llx", str, d->sign != 0, | ||
| 66 | d->exponent, d->significand); | ||
| 67 | } | ||
| 68 | |||
| 69 | static void vfp_double_normalise_denormal(struct vfp_double* vd) { | ||
| 70 | int bits = 31 - fls((u32)(vd->significand >> 32)); | ||
| 71 | if (bits == 31) | ||
| 72 | bits = 63 - fls((u32)vd->significand); | ||
| 73 | |||
| 74 | vfp_double_dump("normalise_denormal: in", vd); | ||
| 75 | |||
| 76 | if (bits) { | ||
| 77 | vd->exponent -= bits - 1; | ||
| 78 | vd->significand <<= bits; | ||
| 79 | } | ||
| 80 | |||
| 81 | vfp_double_dump("normalise_denormal: out", vd); | ||
| 82 | } | ||
| 83 | |||
| 84 | u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double* vd, u32 fpscr, | ||
| 85 | u32 exceptions, const char* func) { | ||
| 86 | u64 significand, incr; | ||
| 87 | int exponent, shift, underflow; | ||
| 88 | u32 rmode; | ||
| 89 | |||
| 90 | vfp_double_dump("pack: in", vd); | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Infinities and NaNs are a special case. | ||
| 94 | */ | ||
| 95 | if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) | ||
| 96 | goto pack; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Special-case zero. | ||
| 100 | */ | ||
| 101 | if (vd->significand == 0) { | ||
| 102 | vd->exponent = 0; | ||
| 103 | goto pack; | ||
| 104 | } | ||
| 105 | |||
| 106 | exponent = vd->exponent; | ||
| 107 | significand = vd->significand; | ||
| 108 | |||
| 109 | shift = 32 - fls((u32)(significand >> 32)); | ||
| 110 | if (shift == 32) | ||
| 111 | shift = 64 - fls((u32)significand); | ||
| 112 | if (shift) { | ||
| 113 | exponent -= shift; | ||
| 114 | significand <<= shift; | ||
| 115 | } | ||
| 116 | |||
| 117 | #if 1 | ||
| 118 | vd->exponent = exponent; | ||
| 119 | vd->significand = significand; | ||
| 120 | vfp_double_dump("pack: normalised", vd); | ||
| 121 | #endif | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Tiny number? | ||
| 125 | */ | ||
| 126 | underflow = exponent < 0; | ||
| 127 | if (underflow) { | ||
| 128 | significand = vfp_shiftright64jamming(significand, -exponent); | ||
| 129 | exponent = 0; | ||
| 130 | #if 1 | ||
| 131 | vd->exponent = exponent; | ||
| 132 | vd->significand = significand; | ||
| 133 | vfp_double_dump("pack: tiny number", vd); | ||
| 134 | #endif | ||
| 135 | if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) | ||
| 136 | underflow = 0; | ||
| 137 | |||
| 138 | int type = vfp_double_type(vd); | ||
| 139 | |||
| 140 | if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) { | ||
| 141 | // Flush denormal to positive 0 | ||
| 142 | significand = 0; | ||
| 143 | |||
| 144 | vd->sign = 0; | ||
| 145 | vd->significand = significand; | ||
| 146 | |||
| 147 | underflow = 0; | ||
| 148 | exceptions |= FPSCR_UFC; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | /* | ||
| 153 | * Select rounding increment. | ||
| 154 | */ | ||
| 155 | incr = 0; | ||
| 156 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 157 | |||
| 158 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 159 | incr = 1ULL << VFP_DOUBLE_LOW_BITS; | ||
| 160 | if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) | ||
| 161 | incr -= 1; | ||
| 162 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 163 | incr = 0; | ||
| 164 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | ||
| 165 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | ||
| 166 | |||
| 167 | LOG_TRACE(Core_ARM, "VFP: rounding increment = 0x%08llx", incr); | ||
| 168 | |||
| 169 | /* | ||
| 170 | * Is our rounding going to overflow? | ||
| 171 | */ | ||
| 172 | if ((significand + incr) < significand) { | ||
| 173 | exponent += 1; | ||
| 174 | significand = (significand >> 1) | (significand & 1); | ||
| 175 | incr >>= 1; | ||
| 176 | #if 1 | ||
| 177 | vd->exponent = exponent; | ||
| 178 | vd->significand = significand; | ||
| 179 | vfp_double_dump("pack: overflow", vd); | ||
| 180 | #endif | ||
| 181 | } | ||
| 182 | |||
| 183 | /* | ||
| 184 | * If any of the low bits (which will be shifted out of the | ||
| 185 | * number) are non-zero, the result is inexact. | ||
| 186 | */ | ||
| 187 | if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) | ||
| 188 | exceptions |= FPSCR_IXC; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * Do our rounding. | ||
| 192 | */ | ||
| 193 | significand += incr; | ||
| 194 | |||
| 195 | /* | ||
| 196 | * Infinity? | ||
| 197 | */ | ||
| 198 | if (exponent >= 2046) { | ||
| 199 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 200 | if (incr == 0) { | ||
| 201 | vd->exponent = 2045; | ||
| 202 | vd->significand = 0x7fffffffffffffffULL; | ||
| 203 | } else { | ||
| 204 | vd->exponent = 2047; /* infinity */ | ||
| 205 | vd->significand = 0; | ||
| 206 | } | ||
| 207 | } else { | ||
| 208 | if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) | ||
| 209 | exponent = 0; | ||
| 210 | if (exponent || significand > 0x8000000000000000ULL) | ||
| 211 | underflow = 0; | ||
| 212 | if (underflow) | ||
| 213 | exceptions |= FPSCR_UFC; | ||
| 214 | vd->exponent = exponent; | ||
| 215 | vd->significand = significand >> 1; | ||
| 216 | } | ||
| 217 | |||
| 218 | pack: | ||
| 219 | vfp_double_dump("pack: final", vd); | ||
| 220 | { | ||
| 221 | s64 d = vfp_double_pack(vd); | ||
| 222 | LOG_TRACE(Core_ARM, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, dd, d, exceptions); | ||
| 223 | vfp_put_double(state, d, dd); | ||
| 224 | } | ||
| 225 | return exceptions; | ||
| 226 | } | ||
| 227 | |||
| 228 | /* | ||
| 229 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 230 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 231 | */ | ||
| 232 | static u32 vfp_propagate_nan(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, | ||
| 233 | u32 fpscr) { | ||
| 234 | struct vfp_double* nan; | ||
| 235 | int tn, tm = 0; | ||
| 236 | |||
| 237 | tn = vfp_double_type(vdn); | ||
| 238 | |||
| 239 | if (vdm) | ||
| 240 | tm = vfp_double_type(vdm); | ||
| 241 | |||
| 242 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 243 | /* | ||
| 244 | * Default NaN mode - always returns a quiet NaN | ||
| 245 | */ | ||
| 246 | nan = &vfp_double_default_qnan; | ||
| 247 | else { | ||
| 248 | /* | ||
| 249 | * Contemporary mode - select the first signalling | ||
| 250 | * NAN, or if neither are signalling, the first | ||
| 251 | * quiet NAN. | ||
| 252 | */ | ||
| 253 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 254 | nan = vdn; | ||
| 255 | else | ||
| 256 | nan = vdm; | ||
| 257 | /* | ||
| 258 | * Make the NaN quiet. | ||
| 259 | */ | ||
| 260 | nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 261 | } | ||
| 262 | |||
| 263 | *vdd = *nan; | ||
| 264 | |||
| 265 | /* | ||
| 266 | * If one was a signalling NAN, raise invalid operation. | ||
| 267 | */ | ||
| 268 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Extended operations | ||
| 273 | */ | ||
| 274 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 275 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 276 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); | ||
| 277 | return 0; | ||
| 278 | } | ||
| 279 | |||
| 280 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 281 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 282 | vfp_put_double(state, vfp_get_double(state, dm), dd); | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 287 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 288 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); | ||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 293 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 294 | vfp_double vdm, vdd, *vdp; | ||
| 295 | int ret, tm; | ||
| 296 | u32 exceptions = 0; | ||
| 297 | |||
| 298 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 299 | |||
| 300 | tm = vfp_double_type(&vdm); | ||
| 301 | if (tm & (VFP_NAN | VFP_INFINITY)) { | ||
| 302 | vdp = &vdd; | ||
| 303 | |||
| 304 | if (tm & VFP_NAN) | ||
| 305 | ret = vfp_propagate_nan(vdp, &vdm, nullptr, fpscr); | ||
| 306 | else if (vdm.sign == 0) { | ||
| 307 | sqrt_copy: | ||
| 308 | vdp = &vdm; | ||
| 309 | ret = 0; | ||
| 310 | } else { | ||
| 311 | sqrt_invalid: | ||
| 312 | vdp = &vfp_double_default_qnan; | ||
| 313 | ret = FPSCR_IOC; | ||
| 314 | } | ||
| 315 | vfp_put_double(state, vfp_double_pack(vdp), dd); | ||
| 316 | return ret; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* | ||
| 320 | * sqrt(+/- 0) == +/- 0 | ||
| 321 | */ | ||
| 322 | if (tm & VFP_ZERO) | ||
| 323 | goto sqrt_copy; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * Normalise a denormalised number | ||
| 327 | */ | ||
| 328 | if (tm & VFP_DENORMAL) | ||
| 329 | vfp_double_normalise_denormal(&vdm); | ||
| 330 | |||
| 331 | /* | ||
| 332 | * sqrt(<0) = invalid | ||
| 333 | */ | ||
| 334 | if (vdm.sign) | ||
| 335 | goto sqrt_invalid; | ||
| 336 | |||
| 337 | vfp_double_dump("sqrt", &vdm); | ||
| 338 | |||
| 339 | /* | ||
| 340 | * Estimate the square root. | ||
| 341 | */ | ||
| 342 | vdd.sign = 0; | ||
| 343 | vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; | ||
| 344 | vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; | ||
| 345 | |||
| 346 | vfp_double_dump("sqrt estimate1", &vdd); | ||
| 347 | |||
| 348 | vdm.significand >>= 1 + (vdm.exponent & 1); | ||
| 349 | vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); | ||
| 350 | |||
| 351 | vfp_double_dump("sqrt estimate2", &vdd); | ||
| 352 | |||
| 353 | /* | ||
| 354 | * And now adjust. | ||
| 355 | */ | ||
| 356 | if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { | ||
| 357 | if (vdd.significand < 2) { | ||
| 358 | vdd.significand = ~0ULL; | ||
| 359 | } else { | ||
| 360 | u64 termh, terml, remh, reml; | ||
| 361 | vdm.significand <<= 2; | ||
| 362 | mul64to128(&termh, &terml, vdd.significand, vdd.significand); | ||
| 363 | sub128(&remh, &reml, vdm.significand, 0, termh, terml); | ||
| 364 | while ((s64)remh < 0) { | ||
| 365 | vdd.significand -= 1; | ||
| 366 | shift64left(&termh, &terml, vdd.significand); | ||
| 367 | terml |= 1; | ||
| 368 | add128(&remh, &reml, remh, reml, termh, terml); | ||
| 369 | } | ||
| 370 | vdd.significand |= (remh | reml) != 0; | ||
| 371 | } | ||
| 372 | } | ||
| 373 | vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); | ||
| 374 | |||
| 375 | exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); | ||
| 376 | |||
| 377 | return exceptions; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* | ||
| 381 | * Equal := ZC | ||
| 382 | * Less than := N | ||
| 383 | * Greater than := C | ||
| 384 | * Unordered := CV | ||
| 385 | */ | ||
| 386 | static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) { | ||
| 387 | s64 d, m; | ||
| 388 | u32 ret = 0; | ||
| 389 | |||
| 390 | LOG_TRACE(Core_ARM, "In %s, state=0x%p, fpscr=0x%x", __FUNCTION__, state, fpscr); | ||
| 391 | m = vfp_get_double(state, dm); | ||
| 392 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { | ||
| 393 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | ||
| 394 | if (signal_on_qnan || | ||
| 395 | !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 396 | /* | ||
| 397 | * Signalling NaN, or signalling on quiet NaN | ||
| 398 | */ | ||
| 399 | ret |= FPSCR_IOC; | ||
| 400 | } | ||
| 401 | |||
| 402 | d = vfp_get_double(state, dd); | ||
| 403 | if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { | ||
| 404 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | ||
| 405 | if (signal_on_qnan || | ||
| 406 | !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) | ||
| 407 | /* | ||
| 408 | * Signalling NaN, or signalling on quiet NaN | ||
| 409 | */ | ||
| 410 | ret |= FPSCR_IOC; | ||
| 411 | } | ||
| 412 | |||
| 413 | if (ret == 0) { | ||
| 414 | // printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); | ||
| 415 | if (d == m || vfp_double_packed_abs(d | m) == 0) { | ||
| 416 | /* | ||
| 417 | * equal | ||
| 418 | */ | ||
| 419 | ret |= FPSCR_ZFLAG | FPSCR_CFLAG; | ||
| 420 | // printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); | ||
| 421 | } else if (vfp_double_packed_sign(d ^ m)) { | ||
| 422 | /* | ||
| 423 | * different signs | ||
| 424 | */ | ||
| 425 | if (vfp_double_packed_sign(d)) | ||
| 426 | /* | ||
| 427 | * d is negative, so d < m | ||
| 428 | */ | ||
| 429 | ret |= FPSCR_NFLAG; | ||
| 430 | else | ||
| 431 | /* | ||
| 432 | * d is positive, so d > m | ||
| 433 | */ | ||
| 434 | ret |= FPSCR_CFLAG; | ||
| 435 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { | ||
| 436 | /* | ||
| 437 | * d < m | ||
| 438 | */ | ||
| 439 | ret |= FPSCR_NFLAG; | ||
| 440 | } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { | ||
| 441 | /* | ||
| 442 | * d > m | ||
| 443 | */ | ||
| 444 | ret |= FPSCR_CFLAG; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | LOG_TRACE(Core_ARM, "In %s, state=0x%p, ret=0x%x", __FUNCTION__, state, ret); | ||
| 448 | |||
| 449 | return ret; | ||
| 450 | } | ||
| 451 | |||
| 452 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 453 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 454 | return vfp_compare(state, dd, 0, dm, fpscr); | ||
| 455 | } | ||
| 456 | |||
| 457 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 458 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 459 | return vfp_compare(state, dd, 1, dm, fpscr); | ||
| 460 | } | ||
| 461 | |||
| 462 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 463 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 464 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); | ||
| 465 | } | ||
| 466 | |||
| 467 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 468 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 469 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); | ||
| 470 | } | ||
| 471 | |||
| 472 | static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { | ||
| 473 | struct vfp_double vdm; | ||
| 474 | struct vfp_single vsd; | ||
| 475 | int tm; | ||
| 476 | u32 exceptions = 0; | ||
| 477 | |||
| 478 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 479 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 480 | |||
| 481 | tm = vfp_double_type(&vdm); | ||
| 482 | |||
| 483 | /* | ||
| 484 | * If we have a signalling NaN, signal invalid operation. | ||
| 485 | */ | ||
| 486 | if (tm == VFP_SNAN) | ||
| 487 | exceptions = FPSCR_IOC; | ||
| 488 | |||
| 489 | if (tm & VFP_DENORMAL) | ||
| 490 | vfp_double_normalise_denormal(&vdm); | ||
| 491 | |||
| 492 | vsd.sign = vdm.sign; | ||
| 493 | vsd.significand = vfp_hi64to32jamming(vdm.significand); | ||
| 494 | |||
| 495 | /* | ||
| 496 | * If we have an infinity or a NaN, the exponent must be 255 | ||
| 497 | */ | ||
| 498 | if (tm & (VFP_INFINITY | VFP_NAN)) { | ||
| 499 | vsd.exponent = 255; | ||
| 500 | if (tm == VFP_QNAN) | ||
| 501 | vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 502 | goto pack_nan; | ||
| 503 | } else if (tm & VFP_ZERO) | ||
| 504 | vsd.exponent = 0; | ||
| 505 | else | ||
| 506 | vsd.exponent = vdm.exponent - (1023 - 127); | ||
| 507 | |||
| 508 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); | ||
| 509 | |||
| 510 | pack_nan: | ||
| 511 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 512 | return exceptions; | ||
| 513 | } | ||
| 514 | |||
| 515 | static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 516 | struct vfp_double vdm; | ||
| 517 | u32 m = vfp_get_float(state, dm); | ||
| 518 | |||
| 519 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 520 | vdm.sign = 0; | ||
| 521 | vdm.exponent = 1023 + 63 - 1; | ||
| 522 | vdm.significand = (u64)m; | ||
| 523 | |||
| 524 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); | ||
| 525 | } | ||
| 526 | |||
| 527 | static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 528 | struct vfp_double vdm; | ||
| 529 | u32 m = vfp_get_float(state, dm); | ||
| 530 | |||
| 531 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 532 | vdm.sign = (m & 0x80000000) >> 16; | ||
| 533 | vdm.exponent = 1023 + 63 - 1; | ||
| 534 | vdm.significand = vdm.sign ? (~m + 1) : m; | ||
| 535 | |||
| 536 | return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); | ||
| 537 | } | ||
| 538 | |||
| 539 | static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { | ||
| 540 | struct vfp_double vdm; | ||
| 541 | u32 d, exceptions = 0; | ||
| 542 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 543 | int tm; | ||
| 544 | |||
| 545 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 546 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 547 | |||
| 548 | /* | ||
| 549 | * Do we have a denormalised number? | ||
| 550 | */ | ||
| 551 | tm = vfp_double_type(&vdm); | ||
| 552 | if (tm & VFP_DENORMAL) | ||
| 553 | exceptions |= FPSCR_IDC; | ||
| 554 | |||
| 555 | if (tm & VFP_NAN) | ||
| 556 | vdm.sign = 1; | ||
| 557 | |||
| 558 | if (vdm.exponent >= 1023 + 32) { | ||
| 559 | d = vdm.sign ? 0 : 0xffffffff; | ||
| 560 | exceptions = FPSCR_IOC; | ||
| 561 | } else if (vdm.exponent >= 1023) { | ||
| 562 | int shift = 1023 + 63 - vdm.exponent; | ||
| 563 | u64 rem, incr = 0; | ||
| 564 | |||
| 565 | /* | ||
| 566 | * 2^0 <= m < 2^32-2^8 | ||
| 567 | */ | ||
| 568 | d = (u32)((vdm.significand << 1) >> shift); | ||
| 569 | rem = vdm.significand << (65 - shift); | ||
| 570 | |||
| 571 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 572 | incr = 0x8000000000000000ULL; | ||
| 573 | if ((d & 1) == 0) | ||
| 574 | incr -= 1; | ||
| 575 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 576 | incr = 0; | ||
| 577 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 578 | incr = ~0ULL; | ||
| 579 | } | ||
| 580 | |||
| 581 | if ((rem + incr) < rem) { | ||
| 582 | if (d < 0xffffffff) | ||
| 583 | d += 1; | ||
| 584 | else | ||
| 585 | exceptions |= FPSCR_IOC; | ||
| 586 | } | ||
| 587 | |||
| 588 | if (d && vdm.sign) { | ||
| 589 | d = 0; | ||
| 590 | exceptions |= FPSCR_IOC; | ||
| 591 | } else if (rem) | ||
| 592 | exceptions |= FPSCR_IXC; | ||
| 593 | } else { | ||
| 594 | d = 0; | ||
| 595 | if (vdm.exponent | vdm.significand) { | ||
| 596 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 597 | if (vdm.exponent >= 1022) { | ||
| 598 | d = vdm.sign ? 0 : 1; | ||
| 599 | exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC; | ||
| 600 | } else { | ||
| 601 | exceptions |= FPSCR_IXC; | ||
| 602 | } | ||
| 603 | } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) { | ||
| 604 | d = 1; | ||
| 605 | exceptions |= FPSCR_IXC; | ||
| 606 | } else if (rmode == FPSCR_ROUND_MINUSINF) { | ||
| 607 | exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC; | ||
| 608 | } else { | ||
| 609 | exceptions |= FPSCR_IXC; | ||
| 610 | } | ||
| 611 | } | ||
| 612 | } | ||
| 613 | |||
| 614 | LOG_TRACE(Core_ARM, "VFP: ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); | ||
| 615 | |||
| 616 | vfp_put_float(state, d, sd); | ||
| 617 | |||
| 618 | return exceptions; | ||
| 619 | } | ||
| 620 | |||
| 621 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { | ||
| 622 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 623 | return vfp_double_ftoui(state, sd, unused, dm, | ||
| 624 | (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); | ||
| 625 | } | ||
| 626 | |||
| 627 | static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { | ||
| 628 | struct vfp_double vdm; | ||
| 629 | u32 d, exceptions = 0; | ||
| 630 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 631 | int tm; | ||
| 632 | |||
| 633 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 634 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 635 | vfp_double_dump("VDM", &vdm); | ||
| 636 | |||
| 637 | /* | ||
| 638 | * Do we have denormalised number? | ||
| 639 | */ | ||
| 640 | tm = vfp_double_type(&vdm); | ||
| 641 | if (tm & VFP_DENORMAL) | ||
| 642 | exceptions |= FPSCR_IDC; | ||
| 643 | |||
| 644 | if (tm & VFP_NAN) { | ||
| 645 | d = 0; | ||
| 646 | exceptions |= FPSCR_IOC; | ||
| 647 | } else if (vdm.exponent >= 1023 + 31) { | ||
| 648 | d = 0x7fffffff; | ||
| 649 | if (vdm.sign) | ||
| 650 | d = ~d; | ||
| 651 | exceptions |= FPSCR_IOC; | ||
| 652 | } else if (vdm.exponent >= 1023) { | ||
| 653 | int shift = 1023 + 63 - vdm.exponent; /* 58 */ | ||
| 654 | u64 rem, incr = 0; | ||
| 655 | |||
| 656 | d = (u32)((vdm.significand << 1) >> shift); | ||
| 657 | rem = vdm.significand << (65 - shift); | ||
| 658 | |||
| 659 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 660 | incr = 0x8000000000000000ULL; | ||
| 661 | if ((d & 1) == 0) | ||
| 662 | incr -= 1; | ||
| 663 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 664 | incr = 0; | ||
| 665 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { | ||
| 666 | incr = ~0ULL; | ||
| 667 | } | ||
| 668 | |||
| 669 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 670 | d += 1; | ||
| 671 | if (d > (0x7fffffffU + (vdm.sign != 0))) { | ||
| 672 | d = (0x7fffffffU + (vdm.sign != 0)); | ||
| 673 | exceptions |= FPSCR_IOC; | ||
| 674 | } else if (rem) | ||
| 675 | exceptions |= FPSCR_IXC; | ||
| 676 | |||
| 677 | if (vdm.sign) | ||
| 678 | d = (~d + 1); | ||
| 679 | } else { | ||
| 680 | d = 0; | ||
| 681 | if (vdm.exponent | vdm.significand) { | ||
| 682 | exceptions |= FPSCR_IXC; | ||
| 683 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 684 | if (vdm.exponent >= 1022) { | ||
| 685 | d = vdm.sign ? 0xffffffff : 1; | ||
| 686 | } else { | ||
| 687 | d = 0; | ||
| 688 | } | ||
| 689 | } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) { | ||
| 690 | d = 1; | ||
| 691 | } else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { | ||
| 692 | d = 0xffffffff; | ||
| 693 | } | ||
| 694 | } | ||
| 695 | } | ||
| 696 | |||
| 697 | LOG_TRACE(Core_ARM, "VFP: ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); | ||
| 698 | |||
| 699 | vfp_put_float(state, (s32)d, sd); | ||
| 700 | |||
| 701 | return exceptions; | ||
| 702 | } | ||
| 703 | |||
| 704 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { | ||
| 705 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 706 | return vfp_double_ftosi(state, dd, unused, dm, | ||
| 707 | (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); | ||
| 708 | } | ||
| 709 | |||
| 710 | static struct op fops_ext[] = { | ||
| 711 | {vfp_double_fcpy, 0}, // 0x00000000 - FEXT_FCPY | ||
| 712 | {vfp_double_fabs, 0}, // 0x00000001 - FEXT_FABS | ||
| 713 | {vfp_double_fneg, 0}, // 0x00000002 - FEXT_FNEG | ||
| 714 | {vfp_double_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT | ||
| 715 | {nullptr, 0}, | ||
| 716 | {nullptr, 0}, | ||
| 717 | {nullptr, 0}, | ||
| 718 | {nullptr, 0}, | ||
| 719 | {vfp_double_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP | ||
| 720 | {vfp_double_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE | ||
| 721 | {vfp_double_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ | ||
| 722 | {vfp_double_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ | ||
| 723 | {nullptr, 0}, | ||
| 724 | {nullptr, 0}, | ||
| 725 | {nullptr, 0}, | ||
| 726 | {vfp_double_fcvts, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT | ||
| 727 | {vfp_double_fuito, OP_SCALAR | OP_SM}, // 0x00000010 - FEXT_FUITO | ||
| 728 | {vfp_double_fsito, OP_SCALAR | OP_SM}, // 0x00000011 - FEXT_FSITO | ||
| 729 | {nullptr, 0}, | ||
| 730 | {nullptr, 0}, | ||
| 731 | {nullptr, 0}, | ||
| 732 | {nullptr, 0}, | ||
| 733 | {nullptr, 0}, | ||
| 734 | {nullptr, 0}, | ||
| 735 | {vfp_double_ftoui, OP_SCALAR | OP_SD}, // 0x00000018 - FEXT_FTOUI | ||
| 736 | {vfp_double_ftouiz, OP_SCALAR | OP_SD}, // 0x00000019 - FEXT_FTOUIZ | ||
| 737 | {vfp_double_ftosi, OP_SCALAR | OP_SD}, // 0x0000001A - FEXT_FTOSI | ||
| 738 | {vfp_double_ftosiz, OP_SCALAR | OP_SD}, // 0x0000001B - FEXT_FTOSIZ | ||
| 739 | }; | ||
| 740 | |||
| 741 | static u32 vfp_double_fadd_nonnumber(struct vfp_double* vdd, struct vfp_double* vdn, | ||
| 742 | struct vfp_double* vdm, u32 fpscr) { | ||
| 743 | struct vfp_double* vdp; | ||
| 744 | u32 exceptions = 0; | ||
| 745 | int tn, tm; | ||
| 746 | |||
| 747 | tn = vfp_double_type(vdn); | ||
| 748 | tm = vfp_double_type(vdm); | ||
| 749 | |||
| 750 | if (tn & tm & VFP_INFINITY) { | ||
| 751 | /* | ||
| 752 | * Two infinities. Are they different signs? | ||
| 753 | */ | ||
| 754 | if (vdn->sign ^ vdm->sign) { | ||
| 755 | /* | ||
| 756 | * different signs -> invalid | ||
| 757 | */ | ||
| 758 | exceptions = FPSCR_IOC; | ||
| 759 | vdp = &vfp_double_default_qnan; | ||
| 760 | } else { | ||
| 761 | /* | ||
| 762 | * same signs -> valid | ||
| 763 | */ | ||
| 764 | vdp = vdn; | ||
| 765 | } | ||
| 766 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 767 | /* | ||
| 768 | * One infinity and one number -> infinity | ||
| 769 | */ | ||
| 770 | vdp = vdn; | ||
| 771 | } else { | ||
| 772 | /* | ||
| 773 | * 'n' is a NaN of some type | ||
| 774 | */ | ||
| 775 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 776 | } | ||
| 777 | *vdd = *vdp; | ||
| 778 | return exceptions; | ||
| 779 | } | ||
| 780 | |||
| 781 | u32 vfp_double_add(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, | ||
| 782 | u32 fpscr) { | ||
| 783 | u32 exp_diff; | ||
| 784 | u64 m_sig; | ||
| 785 | |||
| 786 | if (vdn->significand & (1ULL << 63) || vdm->significand & (1ULL << 63)) { | ||
| 787 | LOG_INFO(Core_ARM, "VFP: bad FP values in %s", __func__); | ||
| 788 | vfp_double_dump("VDN", vdn); | ||
| 789 | vfp_double_dump("VDM", vdm); | ||
| 790 | } | ||
| 791 | |||
| 792 | /* | ||
| 793 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 794 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 795 | * This ensures that NaN propagation works correctly. | ||
| 796 | */ | ||
| 797 | if (vdn->exponent < vdm->exponent) { | ||
| 798 | std::swap(vdm, vdn); | ||
| 799 | } | ||
| 800 | |||
| 801 | /* | ||
| 802 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 803 | * infinity or a NaN here. | ||
| 804 | */ | ||
| 805 | if (vdn->exponent == 2047) | ||
| 806 | return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); | ||
| 807 | |||
| 808 | /* | ||
| 809 | * We have two proper numbers, where 'vdn' is the larger magnitude. | ||
| 810 | * | ||
| 811 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 812 | */ | ||
| 813 | *vdd = *vdn; | ||
| 814 | |||
| 815 | /* | ||
| 816 | * Align 'm' with the result. | ||
| 817 | */ | ||
| 818 | exp_diff = vdn->exponent - vdm->exponent; | ||
| 819 | m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); | ||
| 820 | |||
| 821 | /* | ||
| 822 | * If the signs are different, we are really subtracting. | ||
| 823 | */ | ||
| 824 | if (vdn->sign ^ vdm->sign) { | ||
| 825 | m_sig = vdn->significand - m_sig; | ||
| 826 | if ((s64)m_sig < 0) { | ||
| 827 | vdd->sign = vfp_sign_negate(vdd->sign); | ||
| 828 | m_sig = (~m_sig + 1); | ||
| 829 | } else if (m_sig == 0) { | ||
| 830 | vdd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 831 | } | ||
| 832 | } else { | ||
| 833 | m_sig += vdn->significand; | ||
| 834 | } | ||
| 835 | vdd->significand = m_sig; | ||
| 836 | |||
| 837 | return 0; | ||
| 838 | } | ||
| 839 | |||
| 840 | u32 vfp_double_multiply(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, | ||
| 841 | u32 fpscr) { | ||
| 842 | vfp_double_dump("VDN", vdn); | ||
| 843 | vfp_double_dump("VDM", vdm); | ||
| 844 | |||
| 845 | /* | ||
| 846 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 847 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 848 | * This ensures that NaN propagation works correctly. | ||
| 849 | */ | ||
| 850 | if (vdn->exponent < vdm->exponent) { | ||
| 851 | std::swap(vdm, vdn); | ||
| 852 | LOG_TRACE(Core_ARM, "VFP: swapping M <-> N"); | ||
| 853 | } | ||
| 854 | |||
| 855 | vdd->sign = vdn->sign ^ vdm->sign; | ||
| 856 | |||
| 857 | /* | ||
| 858 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 859 | */ | ||
| 860 | if (vdn->exponent == 2047) { | ||
| 861 | if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) | ||
| 862 | return vfp_propagate_nan(vdd, vdn, vdm, fpscr); | ||
| 863 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 864 | *vdd = vfp_double_default_qnan; | ||
| 865 | return FPSCR_IOC; | ||
| 866 | } | ||
| 867 | vdd->exponent = vdn->exponent; | ||
| 868 | vdd->significand = 0; | ||
| 869 | return 0; | ||
| 870 | } | ||
| 871 | |||
| 872 | /* | ||
| 873 | * If 'm' is zero, the result is always zero. In this case, | ||
| 874 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 875 | */ | ||
| 876 | if ((vdm->exponent | vdm->significand) == 0) { | ||
| 877 | vdd->exponent = 0; | ||
| 878 | vdd->significand = 0; | ||
| 879 | return 0; | ||
| 880 | } | ||
| 881 | |||
| 882 | /* | ||
| 883 | * We add 2 to the destination exponent for the same reason | ||
| 884 | * as the addition case - though this time we have +1 from | ||
| 885 | * each input operand. | ||
| 886 | */ | ||
| 887 | vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; | ||
| 888 | vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); | ||
| 889 | |||
| 890 | vfp_double_dump("VDD", vdd); | ||
| 891 | return 0; | ||
| 892 | } | ||
| 893 | |||
| 894 | #define NEG_MULTIPLY (1 << 0) | ||
| 895 | #define NEG_SUBTRACT (1 << 1) | ||
| 896 | |||
| 897 | static u32 vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, | ||
| 898 | u32 negate, const char* func) { | ||
| 899 | struct vfp_double vdd, vdp, vdn, vdm; | ||
| 900 | u32 exceptions = 0; | ||
| 901 | |||
| 902 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 903 | if (vdn.exponent == 0 && vdn.significand) | ||
| 904 | vfp_double_normalise_denormal(&vdn); | ||
| 905 | |||
| 906 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 907 | if (vdm.exponent == 0 && vdm.significand) | ||
| 908 | vfp_double_normalise_denormal(&vdm); | ||
| 909 | |||
| 910 | exceptions |= vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); | ||
| 911 | if (negate & NEG_MULTIPLY) | ||
| 912 | vdp.sign = vfp_sign_negate(vdp.sign); | ||
| 913 | |||
| 914 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dd), fpscr); | ||
| 915 | if (vdn.exponent == 0 && vdn.significand != 0) | ||
| 916 | vfp_double_normalise_denormal(&vdn); | ||
| 917 | |||
| 918 | if (negate & NEG_SUBTRACT) | ||
| 919 | vdn.sign = vfp_sign_negate(vdn.sign); | ||
| 920 | |||
| 921 | exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); | ||
| 922 | |||
| 923 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); | ||
| 924 | } | ||
| 925 | |||
| 926 | /* | ||
| 927 | * Standard operations | ||
| 928 | */ | ||
| 929 | |||
| 930 | /* | ||
| 931 | * sd = sd + (sn * sm) | ||
| 932 | */ | ||
| 933 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 934 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 935 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); | ||
| 936 | } | ||
| 937 | |||
| 938 | /* | ||
| 939 | * sd = sd - (sn * sm) | ||
| 940 | */ | ||
| 941 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 942 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 943 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 944 | } | ||
| 945 | |||
| 946 | /* | ||
| 947 | * sd = -sd + (sn * sm) | ||
| 948 | */ | ||
| 949 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 950 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 951 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 952 | } | ||
| 953 | |||
| 954 | /* | ||
| 955 | * sd = -sd - (sn * sm) | ||
| 956 | */ | ||
| 957 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 958 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 959 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, | ||
| 960 | "fnmsc"); | ||
| 961 | } | ||
| 962 | |||
| 963 | /* | ||
| 964 | * sd = sn * sm | ||
| 965 | */ | ||
| 966 | static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 967 | struct vfp_double vdd, vdn, vdm; | ||
| 968 | u32 exceptions = 0; | ||
| 969 | |||
| 970 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 971 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 972 | if (vdn.exponent == 0 && vdn.significand) | ||
| 973 | vfp_double_normalise_denormal(&vdn); | ||
| 974 | |||
| 975 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 976 | if (vdm.exponent == 0 && vdm.significand) | ||
| 977 | vfp_double_normalise_denormal(&vdm); | ||
| 978 | |||
| 979 | exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 980 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); | ||
| 981 | } | ||
| 982 | |||
| 983 | /* | ||
| 984 | * sd = -(sn * sm) | ||
| 985 | */ | ||
| 986 | static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 987 | struct vfp_double vdd, vdn, vdm; | ||
| 988 | u32 exceptions = 0; | ||
| 989 | |||
| 990 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 991 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 992 | if (vdn.exponent == 0 && vdn.significand) | ||
| 993 | vfp_double_normalise_denormal(&vdn); | ||
| 994 | |||
| 995 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 996 | if (vdm.exponent == 0 && vdm.significand) | ||
| 997 | vfp_double_normalise_denormal(&vdm); | ||
| 998 | |||
| 999 | exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); | ||
| 1000 | vdd.sign = vfp_sign_negate(vdd.sign); | ||
| 1001 | |||
| 1002 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | /* | ||
| 1006 | * sd = sn + sm | ||
| 1007 | */ | ||
| 1008 | static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 1009 | struct vfp_double vdd, vdn, vdm; | ||
| 1010 | u32 exceptions = 0; | ||
| 1011 | |||
| 1012 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 1013 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 1014 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1015 | vfp_double_normalise_denormal(&vdn); | ||
| 1016 | |||
| 1017 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 1018 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1019 | vfp_double_normalise_denormal(&vdm); | ||
| 1020 | |||
| 1021 | exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1022 | |||
| 1023 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | /* | ||
| 1027 | * sd = sn - sm | ||
| 1028 | */ | ||
| 1029 | static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 1030 | struct vfp_double vdd, vdn, vdm; | ||
| 1031 | u32 exceptions = 0; | ||
| 1032 | |||
| 1033 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 1034 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 1035 | if (vdn.exponent == 0 && vdn.significand) | ||
| 1036 | vfp_double_normalise_denormal(&vdn); | ||
| 1037 | |||
| 1038 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 1039 | if (vdm.exponent == 0 && vdm.significand) | ||
| 1040 | vfp_double_normalise_denormal(&vdm); | ||
| 1041 | |||
| 1042 | /* | ||
| 1043 | * Subtraction is like addition, but with a negated operand. | ||
| 1044 | */ | ||
| 1045 | vdm.sign = vfp_sign_negate(vdm.sign); | ||
| 1046 | |||
| 1047 | exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); | ||
| 1048 | |||
| 1049 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | /* | ||
| 1053 | * sd = sn / sm | ||
| 1054 | */ | ||
| 1055 | static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { | ||
| 1056 | struct vfp_double vdd, vdn, vdm; | ||
| 1057 | u32 exceptions = 0; | ||
| 1058 | int tm, tn; | ||
| 1059 | |||
| 1060 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 1061 | exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); | ||
| 1062 | exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); | ||
| 1063 | |||
| 1064 | vdd.sign = vdn.sign ^ vdm.sign; | ||
| 1065 | |||
| 1066 | tn = vfp_double_type(&vdn); | ||
| 1067 | tm = vfp_double_type(&vdm); | ||
| 1068 | |||
| 1069 | /* | ||
| 1070 | * Is n a NAN? | ||
| 1071 | */ | ||
| 1072 | if (tn & VFP_NAN) | ||
| 1073 | goto vdn_nan; | ||
| 1074 | |||
| 1075 | /* | ||
| 1076 | * Is m a NAN? | ||
| 1077 | */ | ||
| 1078 | if (tm & VFP_NAN) | ||
| 1079 | goto vdm_nan; | ||
| 1080 | |||
| 1081 | /* | ||
| 1082 | * If n and m are infinity, the result is invalid | ||
| 1083 | * If n and m are zero, the result is invalid | ||
| 1084 | */ | ||
| 1085 | if (tm & tn & (VFP_INFINITY | VFP_ZERO)) | ||
| 1086 | goto invalid; | ||
| 1087 | |||
| 1088 | /* | ||
| 1089 | * If n is infinity, the result is infinity | ||
| 1090 | */ | ||
| 1091 | if (tn & VFP_INFINITY) | ||
| 1092 | goto infinity; | ||
| 1093 | |||
| 1094 | /* | ||
| 1095 | * If m is zero, raise div0 exceptions | ||
| 1096 | */ | ||
| 1097 | if (tm & VFP_ZERO) | ||
| 1098 | goto divzero; | ||
| 1099 | |||
| 1100 | /* | ||
| 1101 | * If m is infinity, or n is zero, the result is zero | ||
| 1102 | */ | ||
| 1103 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1104 | goto zero; | ||
| 1105 | |||
| 1106 | if (tn & VFP_DENORMAL) | ||
| 1107 | vfp_double_normalise_denormal(&vdn); | ||
| 1108 | if (tm & VFP_DENORMAL) | ||
| 1109 | vfp_double_normalise_denormal(&vdm); | ||
| 1110 | |||
| 1111 | /* | ||
| 1112 | * Ok, we have two numbers, we can perform division. | ||
| 1113 | */ | ||
| 1114 | vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; | ||
| 1115 | vdm.significand <<= 1; | ||
| 1116 | if (vdm.significand <= (2 * vdn.significand)) { | ||
| 1117 | vdn.significand >>= 1; | ||
| 1118 | vdd.exponent++; | ||
| 1119 | } | ||
| 1120 | vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); | ||
| 1121 | if ((vdd.significand & 0x1ff) <= 2) { | ||
| 1122 | u64 termh, terml, remh, reml; | ||
| 1123 | mul64to128(&termh, &terml, vdm.significand, vdd.significand); | ||
| 1124 | sub128(&remh, &reml, vdn.significand, 0, termh, terml); | ||
| 1125 | while ((s64)remh < 0) { | ||
| 1126 | vdd.significand -= 1; | ||
| 1127 | add128(&remh, &reml, remh, reml, 0, vdm.significand); | ||
| 1128 | } | ||
| 1129 | vdd.significand |= (reml != 0); | ||
| 1130 | } | ||
| 1131 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); | ||
| 1132 | |||
| 1133 | vdn_nan: | ||
| 1134 | exceptions |= vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); | ||
| 1135 | pack: | ||
| 1136 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 1137 | return exceptions; | ||
| 1138 | |||
| 1139 | vdm_nan: | ||
| 1140 | exceptions |= vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); | ||
| 1141 | goto pack; | ||
| 1142 | |||
| 1143 | zero: | ||
| 1144 | vdd.exponent = 0; | ||
| 1145 | vdd.significand = 0; | ||
| 1146 | goto pack; | ||
| 1147 | |||
| 1148 | divzero: | ||
| 1149 | exceptions |= FPSCR_DZC; | ||
| 1150 | infinity: | ||
| 1151 | vdd.exponent = 2047; | ||
| 1152 | vdd.significand = 0; | ||
| 1153 | goto pack; | ||
| 1154 | |||
| 1155 | invalid: | ||
| 1156 | vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); | ||
| 1157 | return FPSCR_IOC; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static struct op fops[] = { | ||
| 1161 | {vfp_double_fmac, 0}, {vfp_double_fmsc, 0}, {vfp_double_fmul, 0}, | ||
| 1162 | {vfp_double_fadd, 0}, {vfp_double_fnmac, 0}, {vfp_double_fnmsc, 0}, | ||
| 1163 | {vfp_double_fnmul, 0}, {vfp_double_fsub, 0}, {vfp_double_fdiv, 0}, | ||
| 1164 | }; | ||
| 1165 | |||
| 1166 | #define FREG_BANK(x) ((x)&0x0c) | ||
| 1167 | #define FREG_IDX(x) ((x)&3) | ||
| 1168 | |||
| 1169 | u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { | ||
| 1170 | u32 op = inst & FOP_MASK; | ||
| 1171 | u32 exceptions = 0; | ||
| 1172 | unsigned int dest; | ||
| 1173 | unsigned int dn = vfp_get_dn(inst); | ||
| 1174 | unsigned int dm; | ||
| 1175 | unsigned int vecitr, veclen, vecstride; | ||
| 1176 | struct op* fop; | ||
| 1177 | |||
| 1178 | LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); | ||
| 1179 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); | ||
| 1180 | |||
| 1181 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1182 | |||
| 1183 | /* | ||
| 1184 | * fcvtds takes an sN register number as destination, not dN. | ||
| 1185 | * It also always operates on scalars. | ||
| 1186 | */ | ||
| 1187 | if (fop->flags & OP_SD) | ||
| 1188 | dest = vfp_get_sd(inst); | ||
| 1189 | else | ||
| 1190 | dest = vfp_get_dd(inst); | ||
| 1191 | |||
| 1192 | /* | ||
| 1193 | * f[us]ito takes a sN operand, not a dN operand. | ||
| 1194 | */ | ||
| 1195 | if (fop->flags & OP_SM) | ||
| 1196 | dm = vfp_get_sm(inst); | ||
| 1197 | else | ||
| 1198 | dm = vfp_get_dm(inst); | ||
| 1199 | |||
| 1200 | /* | ||
| 1201 | * If destination bank is zero, vector length is always '1'. | ||
| 1202 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1203 | */ | ||
| 1204 | if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) | ||
| 1205 | veclen = 0; | ||
| 1206 | else | ||
| 1207 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1208 | |||
| 1209 | LOG_TRACE(Core_ARM, "VFP: vecstride=%u veclen=%u", vecstride, | ||
| 1210 | (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1211 | |||
| 1212 | if (!fop->fn) { | ||
| 1213 | printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); | ||
| 1214 | goto invalid; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1218 | u32 except; | ||
| 1219 | char type; | ||
| 1220 | |||
| 1221 | type = (fop->flags & OP_SD) ? 's' : 'd'; | ||
| 1222 | if (op == FOP_EXT) | ||
| 1223 | LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = op[%u] (d%u)", vecitr >> FPSCR_LENGTH_BIT, | ||
| 1224 | type, dest, dn, dm); | ||
| 1225 | else | ||
| 1226 | LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)", | ||
| 1227 | vecitr >> FPSCR_LENGTH_BIT, type, dest, dn, FOP_TO_IDX(op), dm); | ||
| 1228 | |||
| 1229 | except = fop->fn(state, dest, dn, dm, fpscr); | ||
| 1230 | LOG_TRACE(Core_ARM, "VFP: itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1231 | |||
| 1232 | exceptions |= except & ~VFP_NAN_FLAG; | ||
| 1233 | |||
| 1234 | /* | ||
| 1235 | * CHECK: It appears to be undefined whether we stop when | ||
| 1236 | * we encounter an exception. We continue. | ||
| 1237 | */ | ||
| 1238 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); | ||
| 1239 | dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); | ||
| 1240 | if (FREG_BANK(dm) != 0) | ||
| 1241 | dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); | ||
| 1242 | } | ||
| 1243 | return exceptions; | ||
| 1244 | |||
| 1245 | invalid: | ||
| 1246 | return ~0; | ||
| 1247 | } | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp deleted file mode 100644 index a66dc1016..000000000 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ /dev/null | |||
| @@ -1,1703 +0,0 @@ | |||
| 1 | // Copyright 2012 Michael Kang, 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | /* Notice: this file should not be compiled as is, and is meant to be | ||
| 6 | included in other files only. */ | ||
| 7 | |||
| 8 | /* ----------------------------------------------------------------------- */ | ||
| 9 | /* CDP instructions */ | ||
| 10 | /* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ | ||
| 11 | |||
| 12 | /* ----------------------------------------------------------------------- */ | ||
| 13 | /* VMLA */ | ||
| 14 | /* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 15 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 16 | struct vmla_inst { | ||
| 17 | unsigned int instr; | ||
| 18 | unsigned int dp_operation; | ||
| 19 | }; | ||
| 20 | #endif | ||
| 21 | #ifdef VFP_INTERPRETER_TRANS | ||
| 22 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index) { | ||
| 23 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmla_inst)); | ||
| 24 | vmla_inst* inst_cream = (vmla_inst*)inst_base->component; | ||
| 25 | |||
| 26 | inst_base->cond = BITS(inst, 28, 31); | ||
| 27 | inst_base->idx = index; | ||
| 28 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 29 | |||
| 30 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 31 | inst_cream->instr = inst; | ||
| 32 | |||
| 33 | return inst_base; | ||
| 34 | } | ||
| 35 | #endif | ||
| 36 | #ifdef VFP_INTERPRETER_IMPL | ||
| 37 | VMLA_INST : { | ||
| 38 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 39 | CHECK_VFP_ENABLED; | ||
| 40 | |||
| 41 | vmla_inst* inst_cream = (vmla_inst*)inst_base->component; | ||
| 42 | |||
| 43 | int ret; | ||
| 44 | |||
| 45 | if (inst_cream->dp_operation) | ||
| 46 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 47 | else | ||
| 48 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 49 | |||
| 50 | CHECK_VFP_CDP_RET; | ||
| 51 | } | ||
| 52 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 53 | INC_PC(sizeof(vmla_inst)); | ||
| 54 | FETCH_INST; | ||
| 55 | GOTO_NEXT_INST; | ||
| 56 | } | ||
| 57 | #endif | ||
| 58 | |||
| 59 | /* ----------------------------------------------------------------------- */ | ||
| 60 | /* VNMLS */ | ||
| 61 | /* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */ | ||
| 62 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 63 | struct vmls_inst { | ||
| 64 | unsigned int instr; | ||
| 65 | unsigned int dp_operation; | ||
| 66 | }; | ||
| 67 | #endif | ||
| 68 | #ifdef VFP_INTERPRETER_TRANS | ||
| 69 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index) { | ||
| 70 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmls_inst)); | ||
| 71 | vmls_inst* inst_cream = (vmls_inst*)inst_base->component; | ||
| 72 | |||
| 73 | inst_base->cond = BITS(inst, 28, 31); | ||
| 74 | inst_base->idx = index; | ||
| 75 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 76 | |||
| 77 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 78 | inst_cream->instr = inst; | ||
| 79 | |||
| 80 | return inst_base; | ||
| 81 | } | ||
| 82 | #endif | ||
| 83 | #ifdef VFP_INTERPRETER_IMPL | ||
| 84 | VMLS_INST : { | ||
| 85 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 86 | CHECK_VFP_ENABLED; | ||
| 87 | |||
| 88 | vmls_inst* inst_cream = (vmls_inst*)inst_base->component; | ||
| 89 | |||
| 90 | int ret; | ||
| 91 | |||
| 92 | if (inst_cream->dp_operation) | ||
| 93 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 94 | else | ||
| 95 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 96 | |||
| 97 | CHECK_VFP_CDP_RET; | ||
| 98 | } | ||
| 99 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 100 | INC_PC(sizeof(vmls_inst)); | ||
| 101 | FETCH_INST; | ||
| 102 | GOTO_NEXT_INST; | ||
| 103 | } | ||
| 104 | #endif | ||
| 105 | |||
| 106 | /* ----------------------------------------------------------------------- */ | ||
| 107 | /* VNMLA */ | ||
| 108 | /* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */ | ||
| 109 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 110 | struct vnmla_inst { | ||
| 111 | unsigned int instr; | ||
| 112 | unsigned int dp_operation; | ||
| 113 | }; | ||
| 114 | #endif | ||
| 115 | #ifdef VFP_INTERPRETER_TRANS | ||
| 116 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index) { | ||
| 117 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmla_inst)); | ||
| 118 | vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component; | ||
| 119 | |||
| 120 | inst_base->cond = BITS(inst, 28, 31); | ||
| 121 | inst_base->idx = index; | ||
| 122 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 123 | |||
| 124 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 125 | inst_cream->instr = inst; | ||
| 126 | |||
| 127 | return inst_base; | ||
| 128 | } | ||
| 129 | #endif | ||
| 130 | #ifdef VFP_INTERPRETER_IMPL | ||
| 131 | VNMLA_INST : { | ||
| 132 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 133 | CHECK_VFP_ENABLED; | ||
| 134 | |||
| 135 | vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component; | ||
| 136 | |||
| 137 | int ret; | ||
| 138 | |||
| 139 | if (inst_cream->dp_operation) | ||
| 140 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 141 | else | ||
| 142 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 143 | |||
| 144 | CHECK_VFP_CDP_RET; | ||
| 145 | } | ||
| 146 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 147 | INC_PC(sizeof(vnmla_inst)); | ||
| 148 | FETCH_INST; | ||
| 149 | GOTO_NEXT_INST; | ||
| 150 | } | ||
| 151 | #endif | ||
| 152 | |||
| 153 | /* ----------------------------------------------------------------------- */ | ||
| 154 | /* VNMLS */ | ||
| 155 | /* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 156 | |||
| 157 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 158 | struct vnmls_inst { | ||
| 159 | unsigned int instr; | ||
| 160 | unsigned int dp_operation; | ||
| 161 | }; | ||
| 162 | #endif | ||
| 163 | #ifdef VFP_INTERPRETER_TRANS | ||
| 164 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index) { | ||
| 165 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmls_inst)); | ||
| 166 | vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component; | ||
| 167 | |||
| 168 | inst_base->cond = BITS(inst, 28, 31); | ||
| 169 | inst_base->idx = index; | ||
| 170 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 171 | |||
| 172 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 173 | inst_cream->instr = inst; | ||
| 174 | |||
| 175 | return inst_base; | ||
| 176 | } | ||
| 177 | #endif | ||
| 178 | #ifdef VFP_INTERPRETER_IMPL | ||
| 179 | VNMLS_INST : { | ||
| 180 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 181 | CHECK_VFP_ENABLED; | ||
| 182 | |||
| 183 | vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component; | ||
| 184 | |||
| 185 | int ret; | ||
| 186 | |||
| 187 | if (inst_cream->dp_operation) | ||
| 188 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 189 | else | ||
| 190 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 191 | |||
| 192 | CHECK_VFP_CDP_RET; | ||
| 193 | } | ||
| 194 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 195 | INC_PC(sizeof(vnmls_inst)); | ||
| 196 | FETCH_INST; | ||
| 197 | GOTO_NEXT_INST; | ||
| 198 | } | ||
| 199 | #endif | ||
| 200 | |||
| 201 | /* ----------------------------------------------------------------------- */ | ||
| 202 | /* VNMUL */ | ||
| 203 | /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 204 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 205 | struct vnmul_inst { | ||
| 206 | unsigned int instr; | ||
| 207 | unsigned int dp_operation; | ||
| 208 | }; | ||
| 209 | #endif | ||
| 210 | #ifdef VFP_INTERPRETER_TRANS | ||
| 211 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index) { | ||
| 212 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmul_inst)); | ||
| 213 | vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component; | ||
| 214 | |||
| 215 | inst_base->cond = BITS(inst, 28, 31); | ||
| 216 | inst_base->idx = index; | ||
| 217 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 218 | |||
| 219 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 220 | inst_cream->instr = inst; | ||
| 221 | |||
| 222 | return inst_base; | ||
| 223 | } | ||
| 224 | #endif | ||
| 225 | #ifdef VFP_INTERPRETER_IMPL | ||
| 226 | VNMUL_INST : { | ||
| 227 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 228 | CHECK_VFP_ENABLED; | ||
| 229 | |||
| 230 | vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component; | ||
| 231 | |||
| 232 | int ret; | ||
| 233 | |||
| 234 | if (inst_cream->dp_operation) | ||
| 235 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 236 | else | ||
| 237 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 238 | |||
| 239 | CHECK_VFP_CDP_RET; | ||
| 240 | } | ||
| 241 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 242 | INC_PC(sizeof(vnmul_inst)); | ||
| 243 | FETCH_INST; | ||
| 244 | GOTO_NEXT_INST; | ||
| 245 | } | ||
| 246 | #endif | ||
| 247 | |||
| 248 | /* ----------------------------------------------------------------------- */ | ||
| 249 | /* VMUL */ | ||
| 250 | /* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 251 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 252 | struct vmul_inst { | ||
| 253 | unsigned int instr; | ||
| 254 | unsigned int dp_operation; | ||
| 255 | }; | ||
| 256 | #endif | ||
| 257 | #ifdef VFP_INTERPRETER_TRANS | ||
| 258 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index) { | ||
| 259 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmul_inst)); | ||
| 260 | vmul_inst* inst_cream = (vmul_inst*)inst_base->component; | ||
| 261 | |||
| 262 | inst_base->cond = BITS(inst, 28, 31); | ||
| 263 | inst_base->idx = index; | ||
| 264 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 265 | |||
| 266 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 267 | inst_cream->instr = inst; | ||
| 268 | |||
| 269 | return inst_base; | ||
| 270 | } | ||
| 271 | #endif | ||
| 272 | #ifdef VFP_INTERPRETER_IMPL | ||
| 273 | VMUL_INST : { | ||
| 274 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 275 | CHECK_VFP_ENABLED; | ||
| 276 | |||
| 277 | vmul_inst* inst_cream = (vmul_inst*)inst_base->component; | ||
| 278 | |||
| 279 | int ret; | ||
| 280 | |||
| 281 | if (inst_cream->dp_operation) | ||
| 282 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 283 | else | ||
| 284 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 285 | |||
| 286 | CHECK_VFP_CDP_RET; | ||
| 287 | } | ||
| 288 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 289 | INC_PC(sizeof(vmul_inst)); | ||
| 290 | FETCH_INST; | ||
| 291 | GOTO_NEXT_INST; | ||
| 292 | } | ||
| 293 | #endif | ||
| 294 | |||
| 295 | /* ----------------------------------------------------------------------- */ | ||
| 296 | /* VADD */ | ||
| 297 | /* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 298 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 299 | struct vadd_inst { | ||
| 300 | unsigned int instr; | ||
| 301 | unsigned int dp_operation; | ||
| 302 | }; | ||
| 303 | #endif | ||
| 304 | #ifdef VFP_INTERPRETER_TRANS | ||
| 305 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index) { | ||
| 306 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vadd_inst)); | ||
| 307 | vadd_inst* inst_cream = (vadd_inst*)inst_base->component; | ||
| 308 | |||
| 309 | inst_base->cond = BITS(inst, 28, 31); | ||
| 310 | inst_base->idx = index; | ||
| 311 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 312 | |||
| 313 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 314 | inst_cream->instr = inst; | ||
| 315 | |||
| 316 | return inst_base; | ||
| 317 | } | ||
| 318 | #endif | ||
| 319 | #ifdef VFP_INTERPRETER_IMPL | ||
| 320 | VADD_INST : { | ||
| 321 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 322 | CHECK_VFP_ENABLED; | ||
| 323 | |||
| 324 | vadd_inst* inst_cream = (vadd_inst*)inst_base->component; | ||
| 325 | |||
| 326 | int ret; | ||
| 327 | |||
| 328 | if (inst_cream->dp_operation) | ||
| 329 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 330 | else | ||
| 331 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 332 | |||
| 333 | CHECK_VFP_CDP_RET; | ||
| 334 | } | ||
| 335 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 336 | INC_PC(sizeof(vadd_inst)); | ||
| 337 | FETCH_INST; | ||
| 338 | GOTO_NEXT_INST; | ||
| 339 | } | ||
| 340 | #endif | ||
| 341 | |||
| 342 | /* ----------------------------------------------------------------------- */ | ||
| 343 | /* VSUB */ | ||
| 344 | /* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */ | ||
| 345 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 346 | struct vsub_inst { | ||
| 347 | unsigned int instr; | ||
| 348 | unsigned int dp_operation; | ||
| 349 | }; | ||
| 350 | #endif | ||
| 351 | #ifdef VFP_INTERPRETER_TRANS | ||
| 352 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index) { | ||
| 353 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsub_inst)); | ||
| 354 | vsub_inst* inst_cream = (vsub_inst*)inst_base->component; | ||
| 355 | |||
| 356 | inst_base->cond = BITS(inst, 28, 31); | ||
| 357 | inst_base->idx = index; | ||
| 358 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 359 | |||
| 360 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 361 | inst_cream->instr = inst; | ||
| 362 | |||
| 363 | return inst_base; | ||
| 364 | } | ||
| 365 | #endif | ||
| 366 | #ifdef VFP_INTERPRETER_IMPL | ||
| 367 | VSUB_INST : { | ||
| 368 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 369 | CHECK_VFP_ENABLED; | ||
| 370 | |||
| 371 | vsub_inst* inst_cream = (vsub_inst*)inst_base->component; | ||
| 372 | |||
| 373 | int ret; | ||
| 374 | |||
| 375 | if (inst_cream->dp_operation) | ||
| 376 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 377 | else | ||
| 378 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 379 | |||
| 380 | CHECK_VFP_CDP_RET; | ||
| 381 | } | ||
| 382 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 383 | INC_PC(sizeof(vsub_inst)); | ||
| 384 | FETCH_INST; | ||
| 385 | GOTO_NEXT_INST; | ||
| 386 | } | ||
| 387 | #endif | ||
| 388 | |||
| 389 | /* ----------------------------------------------------------------------- */ | ||
| 390 | /* VDIV */ | ||
| 391 | /* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */ | ||
| 392 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 393 | struct vdiv_inst { | ||
| 394 | unsigned int instr; | ||
| 395 | unsigned int dp_operation; | ||
| 396 | }; | ||
| 397 | #endif | ||
| 398 | #ifdef VFP_INTERPRETER_TRANS | ||
| 399 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index) { | ||
| 400 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vdiv_inst)); | ||
| 401 | vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component; | ||
| 402 | |||
| 403 | inst_base->cond = BITS(inst, 28, 31); | ||
| 404 | inst_base->idx = index; | ||
| 405 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 406 | |||
| 407 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 408 | inst_cream->instr = inst; | ||
| 409 | |||
| 410 | return inst_base; | ||
| 411 | } | ||
| 412 | #endif | ||
| 413 | #ifdef VFP_INTERPRETER_IMPL | ||
| 414 | VDIV_INST : { | ||
| 415 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 416 | CHECK_VFP_ENABLED; | ||
| 417 | |||
| 418 | vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component; | ||
| 419 | |||
| 420 | int ret; | ||
| 421 | |||
| 422 | if (inst_cream->dp_operation) | ||
| 423 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 424 | else | ||
| 425 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 426 | |||
| 427 | CHECK_VFP_CDP_RET; | ||
| 428 | } | ||
| 429 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 430 | INC_PC(sizeof(vdiv_inst)); | ||
| 431 | FETCH_INST; | ||
| 432 | GOTO_NEXT_INST; | ||
| 433 | } | ||
| 434 | #endif | ||
| 435 | |||
| 436 | /* ----------------------------------------------------------------------- */ | ||
| 437 | /* VMOVI move immediate */ | ||
| 438 | /* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */ | ||
| 439 | /* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ | ||
| 440 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 441 | struct vmovi_inst { | ||
| 442 | unsigned int single; | ||
| 443 | unsigned int d; | ||
| 444 | unsigned int imm; | ||
| 445 | }; | ||
| 446 | #endif | ||
| 447 | #ifdef VFP_INTERPRETER_TRANS | ||
| 448 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index) { | ||
| 449 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovi_inst)); | ||
| 450 | vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component; | ||
| 451 | |||
| 452 | inst_base->cond = BITS(inst, 28, 31); | ||
| 453 | inst_base->idx = index; | ||
| 454 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 455 | |||
| 456 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 457 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 458 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 459 | unsigned int imm8 = BITS(inst, 16, 19) << 4 | BITS(inst, 0, 3); | ||
| 460 | if (inst_cream->single) | ||
| 461 | inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 | | ||
| 462 | (BIT(imm8, 6) ? 0x1f : 0) << 25 | BITS(imm8, 0, 5) << 19; | ||
| 463 | else | ||
| 464 | inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 | | ||
| 465 | (BIT(imm8, 6) ? 0xff : 0) << 22 | BITS(imm8, 0, 5) << 16; | ||
| 466 | return inst_base; | ||
| 467 | } | ||
| 468 | #endif | ||
| 469 | #ifdef VFP_INTERPRETER_IMPL | ||
| 470 | VMOVI_INST : { | ||
| 471 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 472 | CHECK_VFP_ENABLED; | ||
| 473 | |||
| 474 | vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component; | ||
| 475 | |||
| 476 | VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); | ||
| 477 | } | ||
| 478 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 479 | INC_PC(sizeof(vmovi_inst)); | ||
| 480 | FETCH_INST; | ||
| 481 | GOTO_NEXT_INST; | ||
| 482 | } | ||
| 483 | #endif | ||
| 484 | |||
| 485 | /* ----------------------------------------------------------------------- */ | ||
| 486 | /* VMOVR move register */ | ||
| 487 | /* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */ | ||
| 488 | /* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ | ||
| 489 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 490 | struct vmovr_inst { | ||
| 491 | unsigned int single; | ||
| 492 | unsigned int d; | ||
| 493 | unsigned int m; | ||
| 494 | }; | ||
| 495 | #endif | ||
| 496 | #ifdef VFP_INTERPRETER_TRANS | ||
| 497 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index) { | ||
| 498 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovr_inst)); | ||
| 499 | vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component; | ||
| 500 | |||
| 501 | inst_base->cond = BITS(inst, 28, 31); | ||
| 502 | inst_base->idx = index; | ||
| 503 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 504 | |||
| 505 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 506 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 507 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 508 | inst_cream->m = (inst_cream->single ? BITS(inst, 0, 3) << 1 | BIT(inst, 5) | ||
| 509 | : BITS(inst, 0, 3) | BIT(inst, 5) << 4); | ||
| 510 | return inst_base; | ||
| 511 | } | ||
| 512 | #endif | ||
| 513 | #ifdef VFP_INTERPRETER_IMPL | ||
| 514 | VMOVR_INST : { | ||
| 515 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 516 | CHECK_VFP_ENABLED; | ||
| 517 | |||
| 518 | vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component; | ||
| 519 | |||
| 520 | VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); | ||
| 521 | } | ||
| 522 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 523 | INC_PC(sizeof(vmovr_inst)); | ||
| 524 | FETCH_INST; | ||
| 525 | GOTO_NEXT_INST; | ||
| 526 | } | ||
| 527 | #endif | ||
| 528 | |||
| 529 | /* ----------------------------------------------------------------------- */ | ||
| 530 | /* VABS */ | ||
| 531 | /* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */ | ||
| 532 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 533 | typedef struct _vabs_inst { | ||
| 534 | unsigned int instr; | ||
| 535 | unsigned int dp_operation; | ||
| 536 | } vabs_inst; | ||
| 537 | #endif | ||
| 538 | #ifdef VFP_INTERPRETER_TRANS | ||
| 539 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index) { | ||
| 540 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vabs_inst)); | ||
| 541 | vabs_inst* inst_cream = (vabs_inst*)inst_base->component; | ||
| 542 | |||
| 543 | inst_base->cond = BITS(inst, 28, 31); | ||
| 544 | inst_base->idx = index; | ||
| 545 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 546 | |||
| 547 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 548 | inst_cream->instr = inst; | ||
| 549 | |||
| 550 | return inst_base; | ||
| 551 | } | ||
| 552 | #endif | ||
| 553 | #ifdef VFP_INTERPRETER_IMPL | ||
| 554 | VABS_INST : { | ||
| 555 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 556 | CHECK_VFP_ENABLED; | ||
| 557 | |||
| 558 | vabs_inst* inst_cream = (vabs_inst*)inst_base->component; | ||
| 559 | |||
| 560 | int ret; | ||
| 561 | |||
| 562 | if (inst_cream->dp_operation) | ||
| 563 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 564 | else | ||
| 565 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 566 | |||
| 567 | CHECK_VFP_CDP_RET; | ||
| 568 | } | ||
| 569 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 570 | INC_PC(sizeof(vabs_inst)); | ||
| 571 | FETCH_INST; | ||
| 572 | GOTO_NEXT_INST; | ||
| 573 | } | ||
| 574 | #endif | ||
| 575 | |||
| 576 | /* ----------------------------------------------------------------------- */ | ||
| 577 | /* VNEG */ | ||
| 578 | /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ | ||
| 579 | |||
| 580 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 581 | struct vneg_inst { | ||
| 582 | unsigned int instr; | ||
| 583 | unsigned int dp_operation; | ||
| 584 | }; | ||
| 585 | #endif | ||
| 586 | #ifdef VFP_INTERPRETER_TRANS | ||
| 587 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index) { | ||
| 588 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vneg_inst)); | ||
| 589 | vneg_inst* inst_cream = (vneg_inst*)inst_base->component; | ||
| 590 | |||
| 591 | inst_base->cond = BITS(inst, 28, 31); | ||
| 592 | inst_base->idx = index; | ||
| 593 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 594 | |||
| 595 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 596 | inst_cream->instr = inst; | ||
| 597 | |||
| 598 | return inst_base; | ||
| 599 | } | ||
| 600 | #endif | ||
| 601 | #ifdef VFP_INTERPRETER_IMPL | ||
| 602 | VNEG_INST : { | ||
| 603 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 604 | CHECK_VFP_ENABLED; | ||
| 605 | |||
| 606 | vneg_inst* inst_cream = (vneg_inst*)inst_base->component; | ||
| 607 | |||
| 608 | int ret; | ||
| 609 | |||
| 610 | if (inst_cream->dp_operation) | ||
| 611 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 612 | else | ||
| 613 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 614 | |||
| 615 | CHECK_VFP_CDP_RET; | ||
| 616 | } | ||
| 617 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 618 | INC_PC(sizeof(vneg_inst)); | ||
| 619 | FETCH_INST; | ||
| 620 | GOTO_NEXT_INST; | ||
| 621 | } | ||
| 622 | #endif | ||
| 623 | |||
| 624 | /* ----------------------------------------------------------------------- */ | ||
| 625 | /* VSQRT */ | ||
| 626 | /* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ | ||
| 627 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 628 | struct vsqrt_inst { | ||
| 629 | unsigned int instr; | ||
| 630 | unsigned int dp_operation; | ||
| 631 | }; | ||
| 632 | #endif | ||
| 633 | #ifdef VFP_INTERPRETER_TRANS | ||
| 634 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index) { | ||
| 635 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsqrt_inst)); | ||
| 636 | vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component; | ||
| 637 | |||
| 638 | inst_base->cond = BITS(inst, 28, 31); | ||
| 639 | inst_base->idx = index; | ||
| 640 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 641 | |||
| 642 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 643 | inst_cream->instr = inst; | ||
| 644 | |||
| 645 | return inst_base; | ||
| 646 | } | ||
| 647 | #endif | ||
| 648 | #ifdef VFP_INTERPRETER_IMPL | ||
| 649 | VSQRT_INST : { | ||
| 650 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 651 | CHECK_VFP_ENABLED; | ||
| 652 | |||
| 653 | vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component; | ||
| 654 | |||
| 655 | int ret; | ||
| 656 | |||
| 657 | if (inst_cream->dp_operation) | ||
| 658 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 659 | else | ||
| 660 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 661 | |||
| 662 | CHECK_VFP_CDP_RET; | ||
| 663 | } | ||
| 664 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 665 | INC_PC(sizeof(vsqrt_inst)); | ||
| 666 | FETCH_INST; | ||
| 667 | GOTO_NEXT_INST; | ||
| 668 | } | ||
| 669 | #endif | ||
| 670 | |||
| 671 | /* ----------------------------------------------------------------------- */ | ||
| 672 | /* VCMP VCMPE */ | ||
| 673 | /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */ | ||
| 674 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 675 | struct vcmp_inst { | ||
| 676 | unsigned int instr; | ||
| 677 | unsigned int dp_operation; | ||
| 678 | }; | ||
| 679 | #endif | ||
| 680 | #ifdef VFP_INTERPRETER_TRANS | ||
| 681 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index) { | ||
| 682 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp_inst)); | ||
| 683 | vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component; | ||
| 684 | |||
| 685 | inst_base->cond = BITS(inst, 28, 31); | ||
| 686 | inst_base->idx = index; | ||
| 687 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 688 | |||
| 689 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 690 | inst_cream->instr = inst; | ||
| 691 | |||
| 692 | return inst_base; | ||
| 693 | } | ||
| 694 | #endif | ||
| 695 | #ifdef VFP_INTERPRETER_IMPL | ||
| 696 | VCMP_INST : { | ||
| 697 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 698 | CHECK_VFP_ENABLED; | ||
| 699 | |||
| 700 | vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component; | ||
| 701 | |||
| 702 | int ret; | ||
| 703 | |||
| 704 | if (inst_cream->dp_operation) | ||
| 705 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 706 | else | ||
| 707 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 708 | |||
| 709 | CHECK_VFP_CDP_RET; | ||
| 710 | } | ||
| 711 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 712 | INC_PC(sizeof(vcmp_inst)); | ||
| 713 | FETCH_INST; | ||
| 714 | GOTO_NEXT_INST; | ||
| 715 | } | ||
| 716 | #endif | ||
| 717 | |||
| 718 | /* ----------------------------------------------------------------------- */ | ||
| 719 | /* VCMP VCMPE */ | ||
| 720 | /* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */ | ||
| 721 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 722 | struct vcmp2_inst { | ||
| 723 | unsigned int instr; | ||
| 724 | unsigned int dp_operation; | ||
| 725 | }; | ||
| 726 | #endif | ||
| 727 | #ifdef VFP_INTERPRETER_TRANS | ||
| 728 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index) { | ||
| 729 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp2_inst)); | ||
| 730 | vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component; | ||
| 731 | |||
| 732 | inst_base->cond = BITS(inst, 28, 31); | ||
| 733 | inst_base->idx = index; | ||
| 734 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 735 | |||
| 736 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 737 | inst_cream->instr = inst; | ||
| 738 | |||
| 739 | return inst_base; | ||
| 740 | } | ||
| 741 | #endif | ||
| 742 | #ifdef VFP_INTERPRETER_IMPL | ||
| 743 | VCMP2_INST : { | ||
| 744 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 745 | CHECK_VFP_ENABLED; | ||
| 746 | |||
| 747 | vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component; | ||
| 748 | |||
| 749 | int ret; | ||
| 750 | |||
| 751 | if (inst_cream->dp_operation) | ||
| 752 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 753 | else | ||
| 754 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 755 | |||
| 756 | CHECK_VFP_CDP_RET; | ||
| 757 | } | ||
| 758 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 759 | INC_PC(sizeof(vcmp2_inst)); | ||
| 760 | FETCH_INST; | ||
| 761 | GOTO_NEXT_INST; | ||
| 762 | } | ||
| 763 | #endif | ||
| 764 | |||
| 765 | /* ----------------------------------------------------------------------- */ | ||
| 766 | /* VCVTBDS between double and single */ | ||
| 767 | /* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */ | ||
| 768 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 769 | struct vcvtbds_inst { | ||
| 770 | unsigned int instr; | ||
| 771 | unsigned int dp_operation; | ||
| 772 | }; | ||
| 773 | #endif | ||
| 774 | #ifdef VFP_INTERPRETER_TRANS | ||
| 775 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index) { | ||
| 776 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbds_inst)); | ||
| 777 | vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component; | ||
| 778 | |||
| 779 | inst_base->cond = BITS(inst, 28, 31); | ||
| 780 | inst_base->idx = index; | ||
| 781 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 782 | |||
| 783 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 784 | inst_cream->instr = inst; | ||
| 785 | |||
| 786 | return inst_base; | ||
| 787 | } | ||
| 788 | #endif | ||
| 789 | #ifdef VFP_INTERPRETER_IMPL | ||
| 790 | VCVTBDS_INST : { | ||
| 791 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 792 | CHECK_VFP_ENABLED; | ||
| 793 | |||
| 794 | vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component; | ||
| 795 | |||
| 796 | int ret; | ||
| 797 | |||
| 798 | if (inst_cream->dp_operation) | ||
| 799 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 800 | else | ||
| 801 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 802 | |||
| 803 | CHECK_VFP_CDP_RET; | ||
| 804 | } | ||
| 805 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 806 | INC_PC(sizeof(vcvtbds_inst)); | ||
| 807 | FETCH_INST; | ||
| 808 | GOTO_NEXT_INST; | ||
| 809 | } | ||
| 810 | #endif | ||
| 811 | |||
| 812 | /* ----------------------------------------------------------------------- */ | ||
| 813 | /* VCVTBFF between floating point and fixed point */ | ||
| 814 | /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ | ||
| 815 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 816 | struct vcvtbff_inst { | ||
| 817 | unsigned int instr; | ||
| 818 | unsigned int dp_operation; | ||
| 819 | }; | ||
| 820 | #endif | ||
| 821 | #ifdef VFP_INTERPRETER_TRANS | ||
| 822 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index) { | ||
| 823 | VFP_DEBUG_UNTESTED(VCVTBFF); | ||
| 824 | |||
| 825 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbff_inst)); | ||
| 826 | vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component; | ||
| 827 | |||
| 828 | inst_base->cond = BITS(inst, 28, 31); | ||
| 829 | inst_base->idx = index; | ||
| 830 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 831 | |||
| 832 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 833 | inst_cream->instr = inst; | ||
| 834 | |||
| 835 | return inst_base; | ||
| 836 | } | ||
| 837 | #endif | ||
| 838 | #ifdef VFP_INTERPRETER_IMPL | ||
| 839 | VCVTBFF_INST : { | ||
| 840 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 841 | CHECK_VFP_ENABLED; | ||
| 842 | |||
| 843 | vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component; | ||
| 844 | |||
| 845 | int ret; | ||
| 846 | |||
| 847 | if (inst_cream->dp_operation) | ||
| 848 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 849 | else | ||
| 850 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 851 | |||
| 852 | CHECK_VFP_CDP_RET; | ||
| 853 | } | ||
| 854 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 855 | INC_PC(sizeof(vcvtbff_inst)); | ||
| 856 | FETCH_INST; | ||
| 857 | GOTO_NEXT_INST; | ||
| 858 | } | ||
| 859 | #endif | ||
| 860 | |||
| 861 | /* ----------------------------------------------------------------------- */ | ||
| 862 | /* VCVTBFI between floating point and integer */ | ||
| 863 | /* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ | ||
| 864 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 865 | struct vcvtbfi_inst { | ||
| 866 | unsigned int instr; | ||
| 867 | unsigned int dp_operation; | ||
| 868 | }; | ||
| 869 | #endif | ||
| 870 | #ifdef VFP_INTERPRETER_TRANS | ||
| 871 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index) { | ||
| 872 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbfi_inst)); | ||
| 873 | vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component; | ||
| 874 | |||
| 875 | inst_base->cond = BITS(inst, 28, 31); | ||
| 876 | inst_base->idx = index; | ||
| 877 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 878 | |||
| 879 | inst_cream->dp_operation = BIT(inst, 8); | ||
| 880 | inst_cream->instr = inst; | ||
| 881 | |||
| 882 | return inst_base; | ||
| 883 | } | ||
| 884 | #endif | ||
| 885 | #ifdef VFP_INTERPRETER_IMPL | ||
| 886 | VCVTBFI_INST : { | ||
| 887 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 888 | CHECK_VFP_ENABLED; | ||
| 889 | |||
| 890 | vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component; | ||
| 891 | |||
| 892 | int ret; | ||
| 893 | |||
| 894 | if (inst_cream->dp_operation) | ||
| 895 | ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 896 | else | ||
| 897 | ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | ||
| 898 | |||
| 899 | CHECK_VFP_CDP_RET; | ||
| 900 | } | ||
| 901 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 902 | INC_PC(sizeof(vcvtbfi_inst)); | ||
| 903 | FETCH_INST; | ||
| 904 | GOTO_NEXT_INST; | ||
| 905 | } | ||
| 906 | #endif | ||
| 907 | |||
| 908 | /* ----------------------------------------------------------------------- */ | ||
| 909 | /* MRC / MCR instructions */ | ||
| 910 | /* cond 1110 AAAL XXXX XXXX 101C XBB1 XXXX */ | ||
| 911 | /* cond 1110 op11 CRn- Rt-- copr op21 CRm- */ | ||
| 912 | |||
| 913 | /* ----------------------------------------------------------------------- */ | ||
| 914 | /* VMOVBRS between register and single precision */ | ||
| 915 | /* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */ | ||
| 916 | /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ | ||
| 917 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 918 | struct vmovbrs_inst { | ||
| 919 | unsigned int to_arm; | ||
| 920 | unsigned int t; | ||
| 921 | unsigned int n; | ||
| 922 | }; | ||
| 923 | #endif | ||
| 924 | #ifdef VFP_INTERPRETER_TRANS | ||
| 925 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index) { | ||
| 926 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrs_inst)); | ||
| 927 | vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component; | ||
| 928 | |||
| 929 | inst_base->cond = BITS(inst, 28, 31); | ||
| 930 | inst_base->idx = index; | ||
| 931 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 932 | |||
| 933 | inst_cream->to_arm = BIT(inst, 20) == 1; | ||
| 934 | inst_cream->t = BITS(inst, 12, 15); | ||
| 935 | inst_cream->n = BIT(inst, 7) | BITS(inst, 16, 19) << 1; | ||
| 936 | |||
| 937 | return inst_base; | ||
| 938 | } | ||
| 939 | #endif | ||
| 940 | #ifdef VFP_INTERPRETER_IMPL | ||
| 941 | VMOVBRS_INST : { | ||
| 942 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 943 | CHECK_VFP_ENABLED; | ||
| 944 | |||
| 945 | vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component; | ||
| 946 | |||
| 947 | VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); | ||
| 948 | } | ||
| 949 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 950 | INC_PC(sizeof(vmovbrs_inst)); | ||
| 951 | FETCH_INST; | ||
| 952 | GOTO_NEXT_INST; | ||
| 953 | } | ||
| 954 | #endif | ||
| 955 | |||
| 956 | /* ----------------------------------------------------------------------- */ | ||
| 957 | /* VMSR */ | ||
| 958 | /* cond 1110 1110 reg- Rt-- 1010 0001 0000 */ | ||
| 959 | /* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ | ||
| 960 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 961 | struct vmsr_inst { | ||
| 962 | unsigned int reg; | ||
| 963 | unsigned int Rt; | ||
| 964 | }; | ||
| 965 | #endif | ||
| 966 | #ifdef VFP_INTERPRETER_TRANS | ||
| 967 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) { | ||
| 968 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmsr_inst)); | ||
| 969 | vmsr_inst* inst_cream = (vmsr_inst*)inst_base->component; | ||
| 970 | |||
| 971 | inst_base->cond = BITS(inst, 28, 31); | ||
| 972 | inst_base->idx = index; | ||
| 973 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 974 | |||
| 975 | inst_cream->reg = BITS(inst, 16, 19); | ||
| 976 | inst_cream->Rt = BITS(inst, 12, 15); | ||
| 977 | |||
| 978 | return inst_base; | ||
| 979 | } | ||
| 980 | #endif | ||
| 981 | #ifdef VFP_INTERPRETER_IMPL | ||
| 982 | VMSR_INST : { | ||
| 983 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 984 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , | ||
| 985 | and in privileged mode */ | ||
| 986 | /* Exceptions must be checked, according to v7 ref manual */ | ||
| 987 | CHECK_VFP_ENABLED; | ||
| 988 | |||
| 989 | vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component; | ||
| 990 | |||
| 991 | unsigned int reg = inst_cream->reg; | ||
| 992 | unsigned int rt = inst_cream->Rt; | ||
| 993 | |||
| 994 | if (reg == 1) { | ||
| 995 | cpu->VFP[VFP_FPSCR] = cpu->Reg[rt]; | ||
| 996 | } else if (cpu->InAPrivilegedMode()) { | ||
| 997 | if (reg == 8) | ||
| 998 | cpu->VFP[VFP_FPEXC] = cpu->Reg[rt]; | ||
| 999 | else if (reg == 9) | ||
| 1000 | cpu->VFP[VFP_FPINST] = cpu->Reg[rt]; | ||
| 1001 | else if (reg == 10) | ||
| 1002 | cpu->VFP[VFP_FPINST2] = cpu->Reg[rt]; | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1006 | INC_PC(sizeof(vmsr_inst)); | ||
| 1007 | FETCH_INST; | ||
| 1008 | GOTO_NEXT_INST; | ||
| 1009 | } | ||
| 1010 | #endif | ||
| 1011 | |||
| 1012 | /* ----------------------------------------------------------------------- */ | ||
| 1013 | /* VMOVBRC register to scalar */ | ||
| 1014 | /* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */ | ||
| 1015 | /* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ | ||
| 1016 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1017 | struct vmovbrc_inst { | ||
| 1018 | unsigned int esize; | ||
| 1019 | unsigned int index; | ||
| 1020 | unsigned int d; | ||
| 1021 | unsigned int t; | ||
| 1022 | }; | ||
| 1023 | #endif | ||
| 1024 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1025 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) { | ||
| 1026 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrc_inst)); | ||
| 1027 | vmovbrc_inst* inst_cream = (vmovbrc_inst*)inst_base->component; | ||
| 1028 | |||
| 1029 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1030 | inst_base->idx = index; | ||
| 1031 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1032 | |||
| 1033 | inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4; | ||
| 1034 | inst_cream->t = BITS(inst, 12, 15); | ||
| 1035 | /* VFP variant of instruction */ | ||
| 1036 | inst_cream->esize = 32; | ||
| 1037 | inst_cream->index = BIT(inst, 21); | ||
| 1038 | |||
| 1039 | return inst_base; | ||
| 1040 | } | ||
| 1041 | #endif | ||
| 1042 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1043 | VMOVBRC_INST : { | ||
| 1044 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1045 | CHECK_VFP_ENABLED; | ||
| 1046 | |||
| 1047 | vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component; | ||
| 1048 | |||
| 1049 | cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; | ||
| 1050 | } | ||
| 1051 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1052 | INC_PC(sizeof(vmovbrc_inst)); | ||
| 1053 | FETCH_INST; | ||
| 1054 | GOTO_NEXT_INST; | ||
| 1055 | } | ||
| 1056 | #endif | ||
| 1057 | |||
| 1058 | /* ----------------------------------------------------------------------- */ | ||
| 1059 | /* VMRS */ | ||
| 1060 | /* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */ | ||
| 1061 | /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ | ||
| 1062 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1063 | struct vmrs_inst { | ||
| 1064 | unsigned int reg; | ||
| 1065 | unsigned int Rt; | ||
| 1066 | }; | ||
| 1067 | #endif | ||
| 1068 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1069 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) { | ||
| 1070 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmrs_inst)); | ||
| 1071 | vmrs_inst* inst_cream = (vmrs_inst*)inst_base->component; | ||
| 1072 | |||
| 1073 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1074 | inst_base->idx = index; | ||
| 1075 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1076 | |||
| 1077 | inst_cream->reg = BITS(inst, 16, 19); | ||
| 1078 | inst_cream->Rt = BITS(inst, 12, 15); | ||
| 1079 | |||
| 1080 | return inst_base; | ||
| 1081 | } | ||
| 1082 | #endif | ||
| 1083 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1084 | VMRS_INST : { | ||
| 1085 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1086 | /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, | ||
| 1087 | and in privileged mode */ | ||
| 1088 | /* Exceptions must be checked, according to v7 ref manual */ | ||
| 1089 | CHECK_VFP_ENABLED; | ||
| 1090 | |||
| 1091 | vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component; | ||
| 1092 | |||
| 1093 | unsigned int reg = inst_cream->reg; | ||
| 1094 | unsigned int rt = inst_cream->Rt; | ||
| 1095 | |||
| 1096 | if (reg == 1) // FPSCR | ||
| 1097 | { | ||
| 1098 | if (rt != 15) { | ||
| 1099 | cpu->Reg[rt] = cpu->VFP[VFP_FPSCR]; | ||
| 1100 | } else { | ||
| 1101 | cpu->NFlag = (cpu->VFP[VFP_FPSCR] >> 31) & 1; | ||
| 1102 | cpu->ZFlag = (cpu->VFP[VFP_FPSCR] >> 30) & 1; | ||
| 1103 | cpu->CFlag = (cpu->VFP[VFP_FPSCR] >> 29) & 1; | ||
| 1104 | cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; | ||
| 1105 | } | ||
| 1106 | } else if (reg == 0) { | ||
| 1107 | cpu->Reg[rt] = cpu->VFP[VFP_FPSID]; | ||
| 1108 | } else if (reg == 6) { | ||
| 1109 | cpu->Reg[rt] = cpu->VFP[VFP_MVFR1]; | ||
| 1110 | } else if (reg == 7) { | ||
| 1111 | cpu->Reg[rt] = cpu->VFP[VFP_MVFR0]; | ||
| 1112 | } else if (cpu->InAPrivilegedMode()) { | ||
| 1113 | if (reg == 8) | ||
| 1114 | cpu->Reg[rt] = cpu->VFP[VFP_FPEXC]; | ||
| 1115 | else if (reg == 9) | ||
| 1116 | cpu->Reg[rt] = cpu->VFP[VFP_FPINST]; | ||
| 1117 | else if (reg == 10) | ||
| 1118 | cpu->Reg[rt] = cpu->VFP[VFP_FPINST2]; | ||
| 1119 | } | ||
| 1120 | } | ||
| 1121 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1122 | INC_PC(sizeof(vmrs_inst)); | ||
| 1123 | FETCH_INST; | ||
| 1124 | GOTO_NEXT_INST; | ||
| 1125 | } | ||
| 1126 | #endif | ||
| 1127 | |||
| 1128 | /* ----------------------------------------------------------------------- */ | ||
| 1129 | /* VMOVBCR scalar to register */ | ||
| 1130 | /* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */ | ||
| 1131 | /* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */ | ||
| 1132 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1133 | struct vmovbcr_inst { | ||
| 1134 | unsigned int esize; | ||
| 1135 | unsigned int index; | ||
| 1136 | unsigned int d; | ||
| 1137 | unsigned int t; | ||
| 1138 | }; | ||
| 1139 | #endif | ||
| 1140 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1141 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) { | ||
| 1142 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbcr_inst)); | ||
| 1143 | vmovbcr_inst* inst_cream = (vmovbcr_inst*)inst_base->component; | ||
| 1144 | |||
| 1145 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1146 | inst_base->idx = index; | ||
| 1147 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1148 | |||
| 1149 | inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4; | ||
| 1150 | inst_cream->t = BITS(inst, 12, 15); | ||
| 1151 | /* VFP variant of instruction */ | ||
| 1152 | inst_cream->esize = 32; | ||
| 1153 | inst_cream->index = BIT(inst, 21); | ||
| 1154 | |||
| 1155 | return inst_base; | ||
| 1156 | } | ||
| 1157 | #endif | ||
| 1158 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1159 | VMOVBCR_INST : { | ||
| 1160 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1161 | CHECK_VFP_ENABLED; | ||
| 1162 | |||
| 1163 | vmovbcr_inst* const inst_cream = (vmovbcr_inst*)inst_base->component; | ||
| 1164 | |||
| 1165 | cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; | ||
| 1166 | } | ||
| 1167 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1168 | INC_PC(sizeof(vmovbcr_inst)); | ||
| 1169 | FETCH_INST; | ||
| 1170 | GOTO_NEXT_INST; | ||
| 1171 | } | ||
| 1172 | #endif | ||
| 1173 | |||
| 1174 | /* ----------------------------------------------------------------------- */ | ||
| 1175 | /* MRRC / MCRR instructions */ | ||
| 1176 | /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ | ||
| 1177 | /* cond 1100 0100 Rt2- Rt-- copr opc1 CRm- MCRR */ | ||
| 1178 | |||
| 1179 | /* ----------------------------------------------------------------------- */ | ||
| 1180 | /* VMOVBRRSS between 2 registers to 2 singles */ | ||
| 1181 | /* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */ | ||
| 1182 | /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ | ||
| 1183 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1184 | struct vmovbrrss_inst { | ||
| 1185 | unsigned int to_arm; | ||
| 1186 | unsigned int t; | ||
| 1187 | unsigned int t2; | ||
| 1188 | unsigned int m; | ||
| 1189 | }; | ||
| 1190 | #endif | ||
| 1191 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1192 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index) { | ||
| 1193 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrss_inst)); | ||
| 1194 | vmovbrrss_inst* inst_cream = (vmovbrrss_inst*)inst_base->component; | ||
| 1195 | |||
| 1196 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1197 | inst_base->idx = index; | ||
| 1198 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1199 | |||
| 1200 | inst_cream->to_arm = BIT(inst, 20) == 1; | ||
| 1201 | inst_cream->t = BITS(inst, 12, 15); | ||
| 1202 | inst_cream->t2 = BITS(inst, 16, 19); | ||
| 1203 | inst_cream->m = BITS(inst, 0, 3) << 1 | BIT(inst, 5); | ||
| 1204 | |||
| 1205 | return inst_base; | ||
| 1206 | } | ||
| 1207 | #endif | ||
| 1208 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1209 | VMOVBRRSS_INST : { | ||
| 1210 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1211 | CHECK_VFP_ENABLED; | ||
| 1212 | |||
| 1213 | vmovbrrss_inst* const inst_cream = (vmovbrrss_inst*)inst_base->component; | ||
| 1214 | |||
| 1215 | VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | ||
| 1216 | &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); | ||
| 1217 | } | ||
| 1218 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1219 | INC_PC(sizeof(vmovbrrss_inst)); | ||
| 1220 | FETCH_INST; | ||
| 1221 | GOTO_NEXT_INST; | ||
| 1222 | } | ||
| 1223 | #endif | ||
| 1224 | |||
| 1225 | /* ----------------------------------------------------------------------- */ | ||
| 1226 | /* VMOVBRRD between 2 registers and 1 double */ | ||
| 1227 | /* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */ | ||
| 1228 | /* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ | ||
| 1229 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1230 | struct vmovbrrd_inst { | ||
| 1231 | unsigned int to_arm; | ||
| 1232 | unsigned int t; | ||
| 1233 | unsigned int t2; | ||
| 1234 | unsigned int m; | ||
| 1235 | }; | ||
| 1236 | #endif | ||
| 1237 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1238 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index) { | ||
| 1239 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrd_inst)); | ||
| 1240 | vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component; | ||
| 1241 | |||
| 1242 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1243 | inst_base->idx = index; | ||
| 1244 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1245 | |||
| 1246 | inst_cream->to_arm = BIT(inst, 20) == 1; | ||
| 1247 | inst_cream->t = BITS(inst, 12, 15); | ||
| 1248 | inst_cream->t2 = BITS(inst, 16, 19); | ||
| 1249 | inst_cream->m = BIT(inst, 5) << 4 | BITS(inst, 0, 3); | ||
| 1250 | |||
| 1251 | return inst_base; | ||
| 1252 | } | ||
| 1253 | #endif | ||
| 1254 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1255 | VMOVBRRD_INST : { | ||
| 1256 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1257 | CHECK_VFP_ENABLED; | ||
| 1258 | |||
| 1259 | vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component; | ||
| 1260 | |||
| 1261 | VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, | ||
| 1262 | &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); | ||
| 1263 | } | ||
| 1264 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1265 | INC_PC(sizeof(vmovbrrd_inst)); | ||
| 1266 | FETCH_INST; | ||
| 1267 | GOTO_NEXT_INST; | ||
| 1268 | } | ||
| 1269 | #endif | ||
| 1270 | |||
| 1271 | /* ----------------------------------------------------------------------- */ | ||
| 1272 | /* LDC/STC between 2 registers and 1 double */ | ||
| 1273 | /* cond 110X XXX1 Rn-- CRd- copr imm- imm- LDC */ | ||
| 1274 | /* cond 110X XXX0 Rn-- CRd- copr imm8 imm8 STC */ | ||
| 1275 | |||
| 1276 | /* ----------------------------------------------------------------------- */ | ||
| 1277 | /* VSTR */ | ||
| 1278 | /* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */ | ||
| 1279 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1280 | struct vstr_inst { | ||
| 1281 | unsigned int single; | ||
| 1282 | unsigned int n; | ||
| 1283 | unsigned int d; | ||
| 1284 | unsigned int imm32; | ||
| 1285 | unsigned int add; | ||
| 1286 | }; | ||
| 1287 | #endif | ||
| 1288 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1289 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index) { | ||
| 1290 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstr_inst)); | ||
| 1291 | vstr_inst* inst_cream = (vstr_inst*)inst_base->component; | ||
| 1292 | |||
| 1293 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1294 | inst_base->idx = index; | ||
| 1295 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1296 | |||
| 1297 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1298 | inst_cream->add = BIT(inst, 23); | ||
| 1299 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1300 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 1301 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 1302 | inst_cream->n = BITS(inst, 16, 19); | ||
| 1303 | |||
| 1304 | return inst_base; | ||
| 1305 | } | ||
| 1306 | #endif | ||
| 1307 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1308 | VSTR_INST : { | ||
| 1309 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1310 | CHECK_VFP_ENABLED; | ||
| 1311 | |||
| 1312 | vstr_inst* inst_cream = (vstr_inst*)inst_base->component; | ||
| 1313 | |||
| 1314 | unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 | ||
| 1315 | : cpu->Reg[inst_cream->n]); | ||
| 1316 | addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); | ||
| 1317 | |||
| 1318 | if (inst_cream->single) { | ||
| 1319 | cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]); | ||
| 1320 | } else { | ||
| 1321 | const u32 word1 = cpu->ExtReg[inst_cream->d * 2 + 0]; | ||
| 1322 | const u32 word2 = cpu->ExtReg[inst_cream->d * 2 + 1]; | ||
| 1323 | |||
| 1324 | if (cpu->InBigEndianMode()) { | ||
| 1325 | cpu->WriteMemory32(addr + 0, word2); | ||
| 1326 | cpu->WriteMemory32(addr + 4, word1); | ||
| 1327 | } else { | ||
| 1328 | cpu->WriteMemory32(addr + 0, word1); | ||
| 1329 | cpu->WriteMemory32(addr + 4, word2); | ||
| 1330 | } | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1334 | INC_PC(sizeof(vstr_inst)); | ||
| 1335 | FETCH_INST; | ||
| 1336 | GOTO_NEXT_INST; | ||
| 1337 | } | ||
| 1338 | #endif | ||
| 1339 | |||
| 1340 | /* ----------------------------------------------------------------------- */ | ||
| 1341 | /* VPUSH */ | ||
| 1342 | /* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */ | ||
| 1343 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1344 | struct vpush_inst { | ||
| 1345 | unsigned int single; | ||
| 1346 | unsigned int d; | ||
| 1347 | unsigned int imm32; | ||
| 1348 | unsigned int regs; | ||
| 1349 | }; | ||
| 1350 | #endif | ||
| 1351 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1352 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index) { | ||
| 1353 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpush_inst)); | ||
| 1354 | vpush_inst* inst_cream = (vpush_inst*)inst_base->component; | ||
| 1355 | |||
| 1356 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1357 | inst_base->idx = index; | ||
| 1358 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1359 | |||
| 1360 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1361 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 1362 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 1363 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1364 | inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); | ||
| 1365 | |||
| 1366 | return inst_base; | ||
| 1367 | } | ||
| 1368 | #endif | ||
| 1369 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1370 | VPUSH_INST : { | ||
| 1371 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1372 | CHECK_VFP_ENABLED; | ||
| 1373 | |||
| 1374 | vpush_inst* inst_cream = (vpush_inst*)inst_base->component; | ||
| 1375 | |||
| 1376 | addr = cpu->Reg[R13] - inst_cream->imm32; | ||
| 1377 | |||
| 1378 | for (unsigned int i = 0; i < inst_cream->regs; i++) { | ||
| 1379 | if (inst_cream->single) { | ||
| 1380 | cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d + i]); | ||
| 1381 | addr += 4; | ||
| 1382 | } else { | ||
| 1383 | const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0]; | ||
| 1384 | const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1]; | ||
| 1385 | |||
| 1386 | if (cpu->InBigEndianMode()) { | ||
| 1387 | cpu->WriteMemory32(addr + 0, word2); | ||
| 1388 | cpu->WriteMemory32(addr + 4, word1); | ||
| 1389 | } else { | ||
| 1390 | cpu->WriteMemory32(addr + 0, word1); | ||
| 1391 | cpu->WriteMemory32(addr + 4, word2); | ||
| 1392 | } | ||
| 1393 | |||
| 1394 | addr += 8; | ||
| 1395 | } | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | cpu->Reg[R13] -= inst_cream->imm32; | ||
| 1399 | } | ||
| 1400 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1401 | INC_PC(sizeof(vpush_inst)); | ||
| 1402 | FETCH_INST; | ||
| 1403 | GOTO_NEXT_INST; | ||
| 1404 | } | ||
| 1405 | #endif | ||
| 1406 | |||
| 1407 | /* ----------------------------------------------------------------------- */ | ||
| 1408 | /* VSTM */ | ||
| 1409 | /* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */ | ||
| 1410 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1411 | struct vstm_inst { | ||
| 1412 | unsigned int single; | ||
| 1413 | unsigned int add; | ||
| 1414 | unsigned int wback; | ||
| 1415 | unsigned int d; | ||
| 1416 | unsigned int n; | ||
| 1417 | unsigned int imm32; | ||
| 1418 | unsigned int regs; | ||
| 1419 | }; | ||
| 1420 | #endif | ||
| 1421 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1422 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) { | ||
| 1423 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstm_inst)); | ||
| 1424 | vstm_inst* inst_cream = (vstm_inst*)inst_base->component; | ||
| 1425 | |||
| 1426 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1427 | inst_base->idx = index; | ||
| 1428 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1429 | |||
| 1430 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1431 | inst_cream->add = BIT(inst, 23); | ||
| 1432 | inst_cream->wback = BIT(inst, 21); | ||
| 1433 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 1434 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 1435 | inst_cream->n = BITS(inst, 16, 19); | ||
| 1436 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1437 | inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); | ||
| 1438 | |||
| 1439 | return inst_base; | ||
| 1440 | } | ||
| 1441 | #endif | ||
| 1442 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1443 | VSTM_INST : /* encoding 1 */ | ||
| 1444 | { | ||
| 1445 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1446 | CHECK_VFP_ENABLED; | ||
| 1447 | |||
| 1448 | vstm_inst* inst_cream = (vstm_inst*)inst_base->component; | ||
| 1449 | |||
| 1450 | u32 address = cpu->Reg[inst_cream->n]; | ||
| 1451 | |||
| 1452 | // Only possible in ARM mode, where PC accesses have an 8 byte offset. | ||
| 1453 | if (inst_cream->n == 15) | ||
| 1454 | address += 8; | ||
| 1455 | |||
| 1456 | if (inst_cream->add == 0) | ||
| 1457 | address -= inst_cream->imm32; | ||
| 1458 | |||
| 1459 | for (unsigned int i = 0; i < inst_cream->regs; i++) { | ||
| 1460 | if (inst_cream->single) { | ||
| 1461 | cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d + i]); | ||
| 1462 | address += 4; | ||
| 1463 | } else { | ||
| 1464 | const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0]; | ||
| 1465 | const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1]; | ||
| 1466 | |||
| 1467 | if (cpu->InBigEndianMode()) { | ||
| 1468 | cpu->WriteMemory32(address + 0, word2); | ||
| 1469 | cpu->WriteMemory32(address + 4, word1); | ||
| 1470 | } else { | ||
| 1471 | cpu->WriteMemory32(address + 0, word1); | ||
| 1472 | cpu->WriteMemory32(address + 4, word2); | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | address += 8; | ||
| 1476 | } | ||
| 1477 | } | ||
| 1478 | if (inst_cream->wback) { | ||
| 1479 | cpu->Reg[inst_cream->n] = | ||
| 1480 | (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 | ||
| 1481 | : cpu->Reg[inst_cream->n] - inst_cream->imm32); | ||
| 1482 | } | ||
| 1483 | } | ||
| 1484 | cpu->Reg[15] += 4; | ||
| 1485 | INC_PC(sizeof(vstm_inst)); | ||
| 1486 | |||
| 1487 | FETCH_INST; | ||
| 1488 | GOTO_NEXT_INST; | ||
| 1489 | } | ||
| 1490 | #endif | ||
| 1491 | |||
| 1492 | /* ----------------------------------------------------------------------- */ | ||
| 1493 | /* VPOP */ | ||
| 1494 | /* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */ | ||
| 1495 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1496 | struct vpop_inst { | ||
| 1497 | unsigned int single; | ||
| 1498 | unsigned int d; | ||
| 1499 | unsigned int imm32; | ||
| 1500 | unsigned int regs; | ||
| 1501 | }; | ||
| 1502 | #endif | ||
| 1503 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1504 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index) { | ||
| 1505 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpop_inst)); | ||
| 1506 | vpop_inst* inst_cream = (vpop_inst*)inst_base->component; | ||
| 1507 | |||
| 1508 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1509 | inst_base->idx = index; | ||
| 1510 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1511 | |||
| 1512 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1513 | inst_cream->d = (inst_cream->single ? (BITS(inst, 12, 15) << 1) | BIT(inst, 22) | ||
| 1514 | : BITS(inst, 12, 15) | (BIT(inst, 22) << 4)); | ||
| 1515 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1516 | inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); | ||
| 1517 | |||
| 1518 | return inst_base; | ||
| 1519 | } | ||
| 1520 | #endif | ||
| 1521 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1522 | VPOP_INST : { | ||
| 1523 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1524 | CHECK_VFP_ENABLED; | ||
| 1525 | |||
| 1526 | vpop_inst* inst_cream = (vpop_inst*)inst_base->component; | ||
| 1527 | |||
| 1528 | addr = cpu->Reg[R13]; | ||
| 1529 | |||
| 1530 | for (unsigned int i = 0; i < inst_cream->regs; i++) { | ||
| 1531 | if (inst_cream->single) { | ||
| 1532 | cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(addr); | ||
| 1533 | addr += 4; | ||
| 1534 | } else { | ||
| 1535 | const u32 word1 = cpu->ReadMemory32(addr + 0); | ||
| 1536 | const u32 word2 = cpu->ReadMemory32(addr + 4); | ||
| 1537 | |||
| 1538 | if (cpu->InBigEndianMode()) { | ||
| 1539 | cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2; | ||
| 1540 | cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1; | ||
| 1541 | } else { | ||
| 1542 | cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1; | ||
| 1543 | cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | addr += 8; | ||
| 1547 | } | ||
| 1548 | } | ||
| 1549 | cpu->Reg[R13] += inst_cream->imm32; | ||
| 1550 | } | ||
| 1551 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1552 | INC_PC(sizeof(vpop_inst)); | ||
| 1553 | FETCH_INST; | ||
| 1554 | GOTO_NEXT_INST; | ||
| 1555 | } | ||
| 1556 | #endif | ||
| 1557 | |||
| 1558 | /* ----------------------------------------------------------------------- */ | ||
| 1559 | /* VLDR */ | ||
| 1560 | /* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */ | ||
| 1561 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1562 | struct vldr_inst { | ||
| 1563 | unsigned int single; | ||
| 1564 | unsigned int n; | ||
| 1565 | unsigned int d; | ||
| 1566 | unsigned int imm32; | ||
| 1567 | unsigned int add; | ||
| 1568 | }; | ||
| 1569 | #endif | ||
| 1570 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1571 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index) { | ||
| 1572 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldr_inst)); | ||
| 1573 | vldr_inst* inst_cream = (vldr_inst*)inst_base->component; | ||
| 1574 | |||
| 1575 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1576 | inst_base->idx = index; | ||
| 1577 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1578 | |||
| 1579 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1580 | inst_cream->add = BIT(inst, 23); | ||
| 1581 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1582 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 1583 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 1584 | inst_cream->n = BITS(inst, 16, 19); | ||
| 1585 | |||
| 1586 | return inst_base; | ||
| 1587 | } | ||
| 1588 | #endif | ||
| 1589 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1590 | VLDR_INST : { | ||
| 1591 | if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { | ||
| 1592 | CHECK_VFP_ENABLED; | ||
| 1593 | |||
| 1594 | vldr_inst* inst_cream = (vldr_inst*)inst_base->component; | ||
| 1595 | |||
| 1596 | unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 | ||
| 1597 | : cpu->Reg[inst_cream->n]); | ||
| 1598 | addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); | ||
| 1599 | |||
| 1600 | if (inst_cream->single) { | ||
| 1601 | cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr); | ||
| 1602 | } else { | ||
| 1603 | const u32 word1 = cpu->ReadMemory32(addr + 0); | ||
| 1604 | const u32 word2 = cpu->ReadMemory32(addr + 4); | ||
| 1605 | |||
| 1606 | if (cpu->InBigEndianMode()) { | ||
| 1607 | cpu->ExtReg[inst_cream->d * 2 + 0] = word2; | ||
| 1608 | cpu->ExtReg[inst_cream->d * 2 + 1] = word1; | ||
| 1609 | } else { | ||
| 1610 | cpu->ExtReg[inst_cream->d * 2 + 0] = word1; | ||
| 1611 | cpu->ExtReg[inst_cream->d * 2 + 1] = word2; | ||
| 1612 | } | ||
| 1613 | } | ||
| 1614 | } | ||
| 1615 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1616 | INC_PC(sizeof(vldr_inst)); | ||
| 1617 | FETCH_INST; | ||
| 1618 | GOTO_NEXT_INST; | ||
| 1619 | } | ||
| 1620 | #endif | ||
| 1621 | |||
| 1622 | /* ----------------------------------------------------------------------- */ | ||
| 1623 | /* VLDM */ | ||
| 1624 | /* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */ | ||
| 1625 | #ifdef VFP_INTERPRETER_STRUCT | ||
| 1626 | struct vldm_inst { | ||
| 1627 | unsigned int single; | ||
| 1628 | unsigned int add; | ||
| 1629 | unsigned int wback; | ||
| 1630 | unsigned int d; | ||
| 1631 | unsigned int n; | ||
| 1632 | unsigned int imm32; | ||
| 1633 | unsigned int regs; | ||
| 1634 | }; | ||
| 1635 | #endif | ||
| 1636 | #ifdef VFP_INTERPRETER_TRANS | ||
| 1637 | static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) { | ||
| 1638 | arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldm_inst)); | ||
| 1639 | vldm_inst* inst_cream = (vldm_inst*)inst_base->component; | ||
| 1640 | |||
| 1641 | inst_base->cond = BITS(inst, 28, 31); | ||
| 1642 | inst_base->idx = index; | ||
| 1643 | inst_base->br = TransExtData::NON_BRANCH; | ||
| 1644 | |||
| 1645 | inst_cream->single = BIT(inst, 8) == 0; | ||
| 1646 | inst_cream->add = BIT(inst, 23); | ||
| 1647 | inst_cream->wback = BIT(inst, 21); | ||
| 1648 | inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) | ||
| 1649 | : BITS(inst, 12, 15) | BIT(inst, 22) << 4); | ||
| 1650 | inst_cream->n = BITS(inst, 16, 19); | ||
| 1651 | inst_cream->imm32 = BITS(inst, 0, 7) << 2; | ||
| 1652 | inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); | ||
| 1653 | |||
| 1654 | return inst_base; | ||
| 1655 | } | ||
| 1656 | #endif | ||
| 1657 | #ifdef VFP_INTERPRETER_IMPL | ||
| 1658 | VLDM_INST : { | ||
| 1659 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | ||
| 1660 | CHECK_VFP_ENABLED; | ||
| 1661 | |||
| 1662 | vldm_inst* inst_cream = (vldm_inst*)inst_base->component; | ||
| 1663 | |||
| 1664 | u32 address = cpu->Reg[inst_cream->n]; | ||
| 1665 | |||
| 1666 | // Only possible in ARM mode, where PC accesses have an 8 byte offset. | ||
| 1667 | if (inst_cream->n == 15) | ||
| 1668 | address += 8; | ||
| 1669 | |||
| 1670 | if (inst_cream->add == 0) | ||
| 1671 | address -= inst_cream->imm32; | ||
| 1672 | |||
| 1673 | for (unsigned int i = 0; i < inst_cream->regs; i++) { | ||
| 1674 | if (inst_cream->single) { | ||
| 1675 | cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(address); | ||
| 1676 | address += 4; | ||
| 1677 | } else { | ||
| 1678 | const u32 word1 = cpu->ReadMemory32(address + 0); | ||
| 1679 | const u32 word2 = cpu->ReadMemory32(address + 4); | ||
| 1680 | |||
| 1681 | if (cpu->InBigEndianMode()) { | ||
| 1682 | cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2; | ||
| 1683 | cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1; | ||
| 1684 | } else { | ||
| 1685 | cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1; | ||
| 1686 | cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2; | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | address += 8; | ||
| 1690 | } | ||
| 1691 | } | ||
| 1692 | if (inst_cream->wback) { | ||
| 1693 | cpu->Reg[inst_cream->n] = | ||
| 1694 | (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 | ||
| 1695 | : cpu->Reg[inst_cream->n] - inst_cream->imm32); | ||
| 1696 | } | ||
| 1697 | } | ||
| 1698 | cpu->Reg[15] += cpu->GetInstructionSize(); | ||
| 1699 | INC_PC(sizeof(vldm_inst)); | ||
| 1700 | FETCH_INST; | ||
| 1701 | GOTO_NEXT_INST; | ||
| 1702 | } | ||
| 1703 | #endif | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp deleted file mode 100644 index 108f03aa9..000000000 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ /dev/null | |||
| @@ -1,1272 +0,0 @@ | |||
| 1 | /* | ||
| 2 | vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction | ||
| 3 | Copyright (C) 2003 Skyeye Develop Group | ||
| 4 | for help please send mail to <skyeye-developer@lists.gro.clinux.org> | ||
| 5 | |||
| 6 | This program is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 2 of the License, or | ||
| 9 | (at your option) any later version. | ||
| 10 | |||
| 11 | This program is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with this program; if not, write to the Free Software | ||
| 18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This code is derived in part from : | ||
| 23 | * - Android kernel | ||
| 24 | * - John R. Housers softfloat library, which | ||
| 25 | * carries the following notice: | ||
| 26 | * | ||
| 27 | * =========================================================================== | ||
| 28 | * This C source file is part of the SoftFloat IEC/IEEE Floating-point | ||
| 29 | * Arithmetic Package, Release 2. | ||
| 30 | * | ||
| 31 | * Written by John R. Hauser. This work was made possible in part by the | ||
| 32 | * International Computer Science Institute, located at Suite 600, 1947 Center | ||
| 33 | * Street, Berkeley, California 94704. Funding was partially provided by the | ||
| 34 | * National Science Foundation under grant MIP-9311980. The original version | ||
| 35 | * of this code was written as part of a project to build a fixed-point vector | ||
| 36 | * processor in collaboration with the University of California at Berkeley, | ||
| 37 | * overseen by Profs. Nelson Morgan and John Wawrzynek. More information | ||
| 38 | * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ | ||
| 39 | * arithmetic/softfloat.html'. | ||
| 40 | * | ||
| 41 | * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort | ||
| 42 | * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT | ||
| 43 | * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO | ||
| 44 | * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY | ||
| 45 | * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. | ||
| 46 | * | ||
| 47 | * Derivative works are acceptable, even for commercial purposes, so long as | ||
| 48 | * (1) they include prominent notice that the work is derivative, and (2) they | ||
| 49 | * include prominent notice akin to these three paragraphs for those parts of | ||
| 50 | * this code that are retained. | ||
| 51 | * =========================================================================== | ||
| 52 | */ | ||
| 53 | |||
| 54 | #include <algorithm> | ||
| 55 | #include <cinttypes> | ||
| 56 | #include "common/common_funcs.h" | ||
| 57 | #include "common/common_types.h" | ||
| 58 | #include "common/logging/log.h" | ||
| 59 | #include "core/arm/skyeye_common/vfp/asm_vfp.h" | ||
| 60 | #include "core/arm/skyeye_common/vfp/vfp.h" | ||
| 61 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" | ||
| 62 | |||
| 63 | static struct vfp_single vfp_single_default_qnan = { | ||
| 64 | 255, 0, VFP_SINGLE_SIGNIFICAND_QNAN, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static void vfp_single_dump(const char* str, struct vfp_single* s) { | ||
| 68 | LOG_TRACE(Core_ARM, "%s: sign=%d exponent=%d significand=%08x", str, s->sign != 0, | ||
| 69 | s->exponent, s->significand); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void vfp_single_normalise_denormal(struct vfp_single* vs) { | ||
| 73 | int bits = 31 - fls(vs->significand); | ||
| 74 | |||
| 75 | vfp_single_dump("normalise_denormal: in", vs); | ||
| 76 | |||
| 77 | if (bits) { | ||
| 78 | vs->exponent -= bits - 1; | ||
| 79 | vs->significand <<= bits; | ||
| 80 | } | ||
| 81 | |||
| 82 | vfp_single_dump("normalise_denormal: out", vs); | ||
| 83 | } | ||
| 84 | |||
| 85 | u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single* vs, u32 fpscr, | ||
| 86 | u32 exceptions, const char* func) { | ||
| 87 | u32 significand, incr, rmode; | ||
| 88 | int exponent, shift, underflow; | ||
| 89 | |||
| 90 | vfp_single_dump("pack: in", vs); | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Infinities and NaNs are a special case. | ||
| 94 | */ | ||
| 95 | if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) | ||
| 96 | goto pack; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * Special-case zero. | ||
| 100 | */ | ||
| 101 | if (vs->significand == 0) { | ||
| 102 | vs->exponent = 0; | ||
| 103 | goto pack; | ||
| 104 | } | ||
| 105 | |||
| 106 | exponent = vs->exponent; | ||
| 107 | significand = vs->significand; | ||
| 108 | |||
| 109 | /* | ||
| 110 | * Normalise first. Note that we shift the significand up to | ||
| 111 | * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least | ||
| 112 | * significant bit. | ||
| 113 | */ | ||
| 114 | shift = 32 - fls(significand); | ||
| 115 | if (shift < 32 && shift) { | ||
| 116 | exponent -= shift; | ||
| 117 | significand <<= shift; | ||
| 118 | } | ||
| 119 | |||
| 120 | #if 1 | ||
| 121 | vs->exponent = exponent; | ||
| 122 | vs->significand = significand; | ||
| 123 | vfp_single_dump("pack: normalised", vs); | ||
| 124 | #endif | ||
| 125 | |||
| 126 | /* | ||
| 127 | * Tiny number? | ||
| 128 | */ | ||
| 129 | underflow = exponent < 0; | ||
| 130 | if (underflow) { | ||
| 131 | significand = vfp_shiftright32jamming(significand, -exponent); | ||
| 132 | exponent = 0; | ||
| 133 | #if 1 | ||
| 134 | vs->exponent = exponent; | ||
| 135 | vs->significand = significand; | ||
| 136 | vfp_single_dump("pack: tiny number", vs); | ||
| 137 | #endif | ||
| 138 | if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) | ||
| 139 | underflow = 0; | ||
| 140 | |||
| 141 | int type = vfp_single_type(vs); | ||
| 142 | |||
| 143 | if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) { | ||
| 144 | // Flush denormal to positive 0 | ||
| 145 | significand = 0; | ||
| 146 | |||
| 147 | vs->sign = 0; | ||
| 148 | vs->significand = significand; | ||
| 149 | |||
| 150 | underflow = 0; | ||
| 151 | exceptions |= FPSCR_UFC; | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | /* | ||
| 156 | * Select rounding increment. | ||
| 157 | */ | ||
| 158 | incr = 0; | ||
| 159 | rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 160 | |||
| 161 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 162 | incr = 1 << VFP_SINGLE_LOW_BITS; | ||
| 163 | if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) | ||
| 164 | incr -= 1; | ||
| 165 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 166 | incr = 0; | ||
| 167 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) | ||
| 168 | incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; | ||
| 169 | |||
| 170 | LOG_TRACE(Core_ARM, "rounding increment = 0x%08x", incr); | ||
| 171 | |||
| 172 | /* | ||
| 173 | * Is our rounding going to overflow? | ||
| 174 | */ | ||
| 175 | if ((significand + incr) < significand) { | ||
| 176 | exponent += 1; | ||
| 177 | significand = (significand >> 1) | (significand & 1); | ||
| 178 | incr >>= 1; | ||
| 179 | #if 1 | ||
| 180 | vs->exponent = exponent; | ||
| 181 | vs->significand = significand; | ||
| 182 | vfp_single_dump("pack: overflow", vs); | ||
| 183 | #endif | ||
| 184 | } | ||
| 185 | |||
| 186 | /* | ||
| 187 | * If any of the low bits (which will be shifted out of the | ||
| 188 | * number) are non-zero, the result is inexact. | ||
| 189 | */ | ||
| 190 | if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) | ||
| 191 | exceptions |= FPSCR_IXC; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Do our rounding. | ||
| 195 | */ | ||
| 196 | significand += incr; | ||
| 197 | |||
| 198 | /* | ||
| 199 | * Infinity? | ||
| 200 | */ | ||
| 201 | if (exponent >= 254) { | ||
| 202 | exceptions |= FPSCR_OFC | FPSCR_IXC; | ||
| 203 | if (incr == 0) { | ||
| 204 | vs->exponent = 253; | ||
| 205 | vs->significand = 0x7fffffff; | ||
| 206 | } else { | ||
| 207 | vs->exponent = 255; /* infinity */ | ||
| 208 | vs->significand = 0; | ||
| 209 | } | ||
| 210 | } else { | ||
| 211 | if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) | ||
| 212 | exponent = 0; | ||
| 213 | if (exponent || significand > 0x80000000) | ||
| 214 | underflow = 0; | ||
| 215 | if (underflow) | ||
| 216 | exceptions |= FPSCR_UFC; | ||
| 217 | vs->exponent = exponent; | ||
| 218 | vs->significand = significand >> 1; | ||
| 219 | } | ||
| 220 | |||
| 221 | pack: | ||
| 222 | vfp_single_dump("pack: final", vs); | ||
| 223 | { | ||
| 224 | s32 d = vfp_single_pack(vs); | ||
| 225 | LOG_TRACE(Core_ARM, "%s: d(s%d)=%08x exceptions=%08x", func, sd, d, exceptions); | ||
| 226 | vfp_put_float(state, d, sd); | ||
| 227 | } | ||
| 228 | |||
| 229 | return exceptions; | ||
| 230 | } | ||
| 231 | |||
| 232 | /* | ||
| 233 | * Propagate the NaN, setting exceptions if it is signalling. | ||
| 234 | * 'n' is always a NaN. 'm' may be a number, NaN or infinity. | ||
| 235 | */ | ||
| 236 | static u32 vfp_propagate_nan(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm, | ||
| 237 | u32 fpscr) { | ||
| 238 | struct vfp_single* nan; | ||
| 239 | int tn, tm = 0; | ||
| 240 | |||
| 241 | tn = vfp_single_type(vsn); | ||
| 242 | |||
| 243 | if (vsm) | ||
| 244 | tm = vfp_single_type(vsm); | ||
| 245 | |||
| 246 | if (fpscr & FPSCR_DEFAULT_NAN) | ||
| 247 | /* | ||
| 248 | * Default NaN mode - always returns a quiet NaN | ||
| 249 | */ | ||
| 250 | nan = &vfp_single_default_qnan; | ||
| 251 | else { | ||
| 252 | /* | ||
| 253 | * Contemporary mode - select the first signalling | ||
| 254 | * NAN, or if neither are signalling, the first | ||
| 255 | * quiet NAN. | ||
| 256 | */ | ||
| 257 | if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) | ||
| 258 | nan = vsn; | ||
| 259 | else | ||
| 260 | nan = vsm; | ||
| 261 | /* | ||
| 262 | * Make the NaN quiet. | ||
| 263 | */ | ||
| 264 | nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; | ||
| 265 | } | ||
| 266 | |||
| 267 | *vsd = *nan; | ||
| 268 | |||
| 269 | /* | ||
| 270 | * If one was a signalling NAN, raise invalid operation. | ||
| 271 | */ | ||
| 272 | return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; | ||
| 273 | } | ||
| 274 | |||
| 275 | /* | ||
| 276 | * Extended operations | ||
| 277 | */ | ||
| 278 | static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 279 | vfp_put_float(state, vfp_single_packed_abs(m), sd); | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 284 | vfp_put_float(state, m, sd); | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 289 | vfp_put_float(state, vfp_single_packed_negate(m), sd); | ||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static const u16 sqrt_oddadjust[] = { | ||
| 294 | 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, | ||
| 295 | 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67, | ||
| 296 | }; | ||
| 297 | |||
| 298 | static const u16 sqrt_evenadjust[] = { | ||
| 299 | 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, | ||
| 300 | 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002, | ||
| 301 | }; | ||
| 302 | |||
| 303 | u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) { | ||
| 304 | int index; | ||
| 305 | u32 z, a; | ||
| 306 | |||
| 307 | if ((significand & 0xc0000000) != 0x40000000) { | ||
| 308 | LOG_TRACE(Core_ARM, "invalid significand"); | ||
| 309 | } | ||
| 310 | |||
| 311 | a = significand << 1; | ||
| 312 | index = (a >> 27) & 15; | ||
| 313 | if (exponent & 1) { | ||
| 314 | z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; | ||
| 315 | z = ((a / z) << 14) + (z << 15); | ||
| 316 | a >>= 1; | ||
| 317 | } else { | ||
| 318 | z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; | ||
| 319 | z = a / z + z; | ||
| 320 | z = (z >= 0x20000) ? 0xffff8000 : (z << 15); | ||
| 321 | if (z <= a) | ||
| 322 | return (s32)a >> 1; | ||
| 323 | } | ||
| 324 | { | ||
| 325 | u64 v = (u64)a << 31; | ||
| 326 | do_div(v, z); | ||
| 327 | return (u32)(v + (z >> 1)); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 332 | struct vfp_single vsm, vsd, *vsp; | ||
| 333 | int ret, tm; | ||
| 334 | u32 exceptions = 0; | ||
| 335 | |||
| 336 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 337 | tm = vfp_single_type(&vsm); | ||
| 338 | if (tm & (VFP_NAN | VFP_INFINITY)) { | ||
| 339 | vsp = &vsd; | ||
| 340 | |||
| 341 | if (tm & VFP_NAN) | ||
| 342 | ret = vfp_propagate_nan(vsp, &vsm, nullptr, fpscr); | ||
| 343 | else if (vsm.sign == 0) { | ||
| 344 | sqrt_copy: | ||
| 345 | vsp = &vsm; | ||
| 346 | ret = 0; | ||
| 347 | } else { | ||
| 348 | sqrt_invalid: | ||
| 349 | vsp = &vfp_single_default_qnan; | ||
| 350 | ret = FPSCR_IOC; | ||
| 351 | } | ||
| 352 | vfp_put_float(state, vfp_single_pack(vsp), sd); | ||
| 353 | return ret; | ||
| 354 | } | ||
| 355 | |||
| 356 | /* | ||
| 357 | * sqrt(+/- 0) == +/- 0 | ||
| 358 | */ | ||
| 359 | if (tm & VFP_ZERO) | ||
| 360 | goto sqrt_copy; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * Normalise a denormalised number | ||
| 364 | */ | ||
| 365 | if (tm & VFP_DENORMAL) | ||
| 366 | vfp_single_normalise_denormal(&vsm); | ||
| 367 | |||
| 368 | /* | ||
| 369 | * sqrt(<0) = invalid | ||
| 370 | */ | ||
| 371 | if (vsm.sign) | ||
| 372 | goto sqrt_invalid; | ||
| 373 | |||
| 374 | vfp_single_dump("sqrt", &vsm); | ||
| 375 | |||
| 376 | /* | ||
| 377 | * Estimate the square root. | ||
| 378 | */ | ||
| 379 | vsd.sign = 0; | ||
| 380 | vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; | ||
| 381 | vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; | ||
| 382 | |||
| 383 | vfp_single_dump("sqrt estimate", &vsd); | ||
| 384 | |||
| 385 | /* | ||
| 386 | * And now adjust. | ||
| 387 | */ | ||
| 388 | if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { | ||
| 389 | if (vsd.significand < 2) { | ||
| 390 | vsd.significand = 0xffffffff; | ||
| 391 | } else { | ||
| 392 | u64 term; | ||
| 393 | s64 rem; | ||
| 394 | vsm.significand <<= static_cast<u32>((vsm.exponent & 1) == 0); | ||
| 395 | term = (u64)vsd.significand * vsd.significand; | ||
| 396 | rem = ((u64)vsm.significand << 32) - term; | ||
| 397 | |||
| 398 | LOG_TRACE(Core_ARM, "term=%016" PRIx64 "rem=%016" PRIx64, term, rem); | ||
| 399 | |||
| 400 | while (rem < 0) { | ||
| 401 | vsd.significand -= 1; | ||
| 402 | rem += ((u64)vsd.significand << 1) | 1; | ||
| 403 | } | ||
| 404 | vsd.significand |= rem != 0; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); | ||
| 408 | |||
| 409 | exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); | ||
| 410 | |||
| 411 | return exceptions; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* | ||
| 415 | * Equal := ZC | ||
| 416 | * Less than := N | ||
| 417 | * Greater than := C | ||
| 418 | * Unordered := CV | ||
| 419 | */ | ||
| 420 | static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) { | ||
| 421 | s32 d; | ||
| 422 | u32 ret = 0; | ||
| 423 | |||
| 424 | d = vfp_get_float(state, sd); | ||
| 425 | if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { | ||
| 426 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | ||
| 427 | if (signal_on_qnan || | ||
| 428 | !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 429 | /* | ||
| 430 | * Signalling NaN, or signalling on quiet NaN | ||
| 431 | */ | ||
| 432 | ret |= FPSCR_IOC; | ||
| 433 | } | ||
| 434 | |||
| 435 | if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { | ||
| 436 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | ||
| 437 | if (signal_on_qnan || | ||
| 438 | !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) | ||
| 439 | /* | ||
| 440 | * Signalling NaN, or signalling on quiet NaN | ||
| 441 | */ | ||
| 442 | ret |= FPSCR_IOC; | ||
| 443 | } | ||
| 444 | |||
| 445 | if (ret == 0) { | ||
| 446 | if (d == m || vfp_single_packed_abs(d | m) == 0) { | ||
| 447 | /* | ||
| 448 | * equal | ||
| 449 | */ | ||
| 450 | ret |= FPSCR_ZFLAG | FPSCR_CFLAG; | ||
| 451 | } else if (vfp_single_packed_sign(d ^ m)) { | ||
| 452 | /* | ||
| 453 | * different signs | ||
| 454 | */ | ||
| 455 | if (vfp_single_packed_sign(d)) | ||
| 456 | /* | ||
| 457 | * d is negative, so d < m | ||
| 458 | */ | ||
| 459 | ret |= FPSCR_NFLAG; | ||
| 460 | else | ||
| 461 | /* | ||
| 462 | * d is positive, so d > m | ||
| 463 | */ | ||
| 464 | ret |= FPSCR_CFLAG; | ||
| 465 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { | ||
| 466 | /* | ||
| 467 | * d < m | ||
| 468 | */ | ||
| 469 | ret |= FPSCR_NFLAG; | ||
| 470 | } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { | ||
| 471 | /* | ||
| 472 | * d > m | ||
| 473 | */ | ||
| 474 | ret |= FPSCR_CFLAG; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | return ret; | ||
| 478 | } | ||
| 479 | |||
| 480 | static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 481 | return vfp_compare(state, sd, 0, m, fpscr); | ||
| 482 | } | ||
| 483 | |||
| 484 | static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 485 | return vfp_compare(state, sd, 1, m, fpscr); | ||
| 486 | } | ||
| 487 | |||
| 488 | static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 489 | return vfp_compare(state, sd, 0, 0, fpscr); | ||
| 490 | } | ||
| 491 | |||
| 492 | static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 493 | return vfp_compare(state, sd, 1, 0, fpscr); | ||
| 494 | } | ||
| 495 | |||
| 496 | static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) { | ||
| 497 | struct vfp_single vsm; | ||
| 498 | struct vfp_double vdd; | ||
| 499 | int tm; | ||
| 500 | u32 exceptions = 0; | ||
| 501 | |||
| 502 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 503 | |||
| 504 | tm = vfp_single_type(&vsm); | ||
| 505 | |||
| 506 | /* | ||
| 507 | * If we have a signalling NaN, signal invalid operation. | ||
| 508 | */ | ||
| 509 | if (tm == VFP_SNAN) | ||
| 510 | exceptions |= FPSCR_IOC; | ||
| 511 | |||
| 512 | if (tm & VFP_DENORMAL) | ||
| 513 | vfp_single_normalise_denormal(&vsm); | ||
| 514 | |||
| 515 | vdd.sign = vsm.sign; | ||
| 516 | vdd.significand = (u64)vsm.significand << 32; | ||
| 517 | |||
| 518 | /* | ||
| 519 | * If we have an infinity or NaN, the exponent must be 2047. | ||
| 520 | */ | ||
| 521 | if (tm & (VFP_INFINITY | VFP_NAN)) { | ||
| 522 | vdd.exponent = 2047; | ||
| 523 | if (tm == VFP_QNAN) | ||
| 524 | vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; | ||
| 525 | goto pack_nan; | ||
| 526 | } else if (tm & VFP_ZERO) | ||
| 527 | vdd.exponent = 0; | ||
| 528 | else | ||
| 529 | vdd.exponent = vsm.exponent + (1023 - 127); | ||
| 530 | |||
| 531 | return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); | ||
| 532 | |||
| 533 | pack_nan: | ||
| 534 | vfp_put_double(state, vfp_double_pack(&vdd), dd); | ||
| 535 | return exceptions; | ||
| 536 | } | ||
| 537 | |||
| 538 | static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 539 | struct vfp_single vs; | ||
| 540 | |||
| 541 | vs.sign = 0; | ||
| 542 | vs.exponent = 127 + 31 - 1; | ||
| 543 | vs.significand = (u32)m; | ||
| 544 | |||
| 545 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); | ||
| 546 | } | ||
| 547 | |||
| 548 | static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 549 | struct vfp_single vs; | ||
| 550 | |||
| 551 | vs.sign = (m & 0x80000000) >> 16; | ||
| 552 | vs.exponent = 127 + 31 - 1; | ||
| 553 | vs.significand = vs.sign ? -m : m; | ||
| 554 | |||
| 555 | return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); | ||
| 556 | } | ||
| 557 | |||
| 558 | static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 559 | struct vfp_single vsm; | ||
| 560 | u32 d, exceptions = 0; | ||
| 561 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 562 | int tm; | ||
| 563 | |||
| 564 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 565 | vfp_single_dump("VSM", &vsm); | ||
| 566 | |||
| 567 | /* | ||
| 568 | * Do we have a denormalised number? | ||
| 569 | */ | ||
| 570 | tm = vfp_single_type(&vsm); | ||
| 571 | if (tm & VFP_DENORMAL) | ||
| 572 | exceptions |= FPSCR_IDC; | ||
| 573 | |||
| 574 | if (tm & VFP_NAN) | ||
| 575 | vsm.sign = 1; | ||
| 576 | |||
| 577 | if (vsm.exponent >= 127 + 32) { | ||
| 578 | d = vsm.sign ? 0 : 0xffffffff; | ||
| 579 | exceptions |= FPSCR_IOC; | ||
| 580 | } else if (vsm.exponent >= 127) { | ||
| 581 | int shift = 127 + 31 - vsm.exponent; | ||
| 582 | u32 rem, incr = 0; | ||
| 583 | |||
| 584 | /* | ||
| 585 | * 2^0 <= m < 2^32-2^8 | ||
| 586 | */ | ||
| 587 | d = (vsm.significand << 1) >> shift; | ||
| 588 | if (shift > 0) { | ||
| 589 | rem = (vsm.significand << 1) << (32 - shift); | ||
| 590 | } else { | ||
| 591 | rem = 0; | ||
| 592 | } | ||
| 593 | |||
| 594 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 595 | incr = 0x80000000; | ||
| 596 | if ((d & 1) == 0) | ||
| 597 | incr -= 1; | ||
| 598 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 599 | incr = 0; | ||
| 600 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 601 | incr = ~0; | ||
| 602 | } | ||
| 603 | |||
| 604 | if ((rem + incr) < rem) { | ||
| 605 | if (d < 0xffffffff) | ||
| 606 | d += 1; | ||
| 607 | else | ||
| 608 | exceptions |= FPSCR_IOC; | ||
| 609 | } | ||
| 610 | |||
| 611 | if (d && vsm.sign) { | ||
| 612 | d = 0; | ||
| 613 | exceptions |= FPSCR_IOC; | ||
| 614 | } else if (rem) | ||
| 615 | exceptions |= FPSCR_IXC; | ||
| 616 | } else { | ||
| 617 | d = 0; | ||
| 618 | if (vsm.exponent | vsm.significand) { | ||
| 619 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 620 | if (vsm.exponent >= 126) { | ||
| 621 | d = vsm.sign ? 0 : 1; | ||
| 622 | exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC; | ||
| 623 | } else { | ||
| 624 | exceptions |= FPSCR_IXC; | ||
| 625 | } | ||
| 626 | } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) { | ||
| 627 | d = 1; | ||
| 628 | exceptions |= FPSCR_IXC; | ||
| 629 | } else if (rmode == FPSCR_ROUND_MINUSINF) { | ||
| 630 | exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC; | ||
| 631 | } else { | ||
| 632 | exceptions |= FPSCR_IXC; | ||
| 633 | } | ||
| 634 | } | ||
| 635 | } | ||
| 636 | |||
| 637 | LOG_TRACE(Core_ARM, "ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); | ||
| 638 | |||
| 639 | vfp_put_float(state, d, sd); | ||
| 640 | |||
| 641 | return exceptions; | ||
| 642 | } | ||
| 643 | |||
| 644 | static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 645 | return vfp_single_ftoui(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); | ||
| 646 | } | ||
| 647 | |||
| 648 | static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 649 | struct vfp_single vsm; | ||
| 650 | u32 d, exceptions = 0; | ||
| 651 | int rmode = fpscr & FPSCR_RMODE_MASK; | ||
| 652 | int tm; | ||
| 653 | |||
| 654 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 655 | vfp_single_dump("VSM", &vsm); | ||
| 656 | |||
| 657 | /* | ||
| 658 | * Do we have a denormalised number? | ||
| 659 | */ | ||
| 660 | tm = vfp_single_type(&vsm); | ||
| 661 | if (vfp_single_type(&vsm) & VFP_DENORMAL) | ||
| 662 | exceptions |= FPSCR_IDC; | ||
| 663 | |||
| 664 | if (tm & VFP_NAN) { | ||
| 665 | d = 0; | ||
| 666 | exceptions |= FPSCR_IOC; | ||
| 667 | } else if (vsm.exponent >= 127 + 31) { | ||
| 668 | /* | ||
| 669 | * m >= 2^31-2^7: invalid | ||
| 670 | */ | ||
| 671 | d = 0x7fffffff; | ||
| 672 | if (vsm.sign) | ||
| 673 | d = ~d; | ||
| 674 | exceptions |= FPSCR_IOC; | ||
| 675 | } else if (vsm.exponent >= 127) { | ||
| 676 | int shift = 127 + 31 - vsm.exponent; | ||
| 677 | u32 rem, incr = 0; | ||
| 678 | |||
| 679 | /* 2^0 <= m <= 2^31-2^7 */ | ||
| 680 | d = (vsm.significand << 1) >> shift; | ||
| 681 | rem = (vsm.significand << 1) << (32 - shift); | ||
| 682 | |||
| 683 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 684 | incr = 0x80000000; | ||
| 685 | if ((d & 1) == 0) | ||
| 686 | incr -= 1; | ||
| 687 | } else if (rmode == FPSCR_ROUND_TOZERO) { | ||
| 688 | incr = 0; | ||
| 689 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { | ||
| 690 | incr = ~0; | ||
| 691 | } | ||
| 692 | |||
| 693 | if ((rem + incr) < rem && d < 0xffffffff) | ||
| 694 | d += 1; | ||
| 695 | if (d > (0x7fffffffu + (vsm.sign != 0))) { | ||
| 696 | d = (0x7fffffffu + (vsm.sign != 0)); | ||
| 697 | exceptions |= FPSCR_IOC; | ||
| 698 | } else if (rem) | ||
| 699 | exceptions |= FPSCR_IXC; | ||
| 700 | |||
| 701 | if (vsm.sign) | ||
| 702 | d = (~d + 1); | ||
| 703 | } else { | ||
| 704 | d = 0; | ||
| 705 | if (vsm.exponent | vsm.significand) { | ||
| 706 | exceptions |= FPSCR_IXC; | ||
| 707 | if (rmode == FPSCR_ROUND_NEAREST) { | ||
| 708 | if (vsm.exponent >= 126) | ||
| 709 | d = vsm.sign ? 0xffffffff : 1; | ||
| 710 | } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) { | ||
| 711 | d = 1; | ||
| 712 | } else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { | ||
| 713 | d = 0xffffffff; | ||
| 714 | } | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 718 | LOG_TRACE(Core_ARM, "ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); | ||
| 719 | |||
| 720 | vfp_put_float(state, (s32)d, sd); | ||
| 721 | |||
| 722 | return exceptions; | ||
| 723 | } | ||
| 724 | |||
| 725 | static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { | ||
| 726 | return vfp_single_ftosi(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); | ||
| 727 | } | ||
| 728 | |||
| 729 | static struct op fops_ext[] = { | ||
| 730 | {vfp_single_fcpy, 0}, // 0x00000000 - FEXT_FCPY | ||
| 731 | {vfp_single_fabs, 0}, // 0x00000001 - FEXT_FABS | ||
| 732 | {vfp_single_fneg, 0}, // 0x00000002 - FEXT_FNEG | ||
| 733 | {vfp_single_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT | ||
| 734 | {nullptr, 0}, | ||
| 735 | {nullptr, 0}, | ||
| 736 | {nullptr, 0}, | ||
| 737 | {nullptr, 0}, | ||
| 738 | {vfp_single_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP | ||
| 739 | {vfp_single_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE | ||
| 740 | {vfp_single_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ | ||
| 741 | {vfp_single_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ | ||
| 742 | {nullptr, 0}, | ||
| 743 | {nullptr, 0}, | ||
| 744 | {nullptr, 0}, | ||
| 745 | {vfp_single_fcvtd, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT | ||
| 746 | {vfp_single_fuito, OP_SCALAR}, // 0x00000010 - FEXT_FUITO | ||
| 747 | {vfp_single_fsito, OP_SCALAR}, // 0x00000011 - FEXT_FSITO | ||
| 748 | {nullptr, 0}, | ||
| 749 | {nullptr, 0}, | ||
| 750 | {nullptr, 0}, | ||
| 751 | {nullptr, 0}, | ||
| 752 | {nullptr, 0}, | ||
| 753 | {nullptr, 0}, | ||
| 754 | {vfp_single_ftoui, OP_SCALAR}, // 0x00000018 - FEXT_FTOUI | ||
| 755 | {vfp_single_ftouiz, OP_SCALAR}, // 0x00000019 - FEXT_FTOUIZ | ||
| 756 | {vfp_single_ftosi, OP_SCALAR}, // 0x0000001A - FEXT_FTOSI | ||
| 757 | {vfp_single_ftosiz, OP_SCALAR}, // 0x0000001B - FEXT_FTOSIZ | ||
| 758 | }; | ||
| 759 | |||
| 760 | static u32 vfp_single_fadd_nonnumber(struct vfp_single* vsd, struct vfp_single* vsn, | ||
| 761 | struct vfp_single* vsm, u32 fpscr) { | ||
| 762 | struct vfp_single* vsp; | ||
| 763 | u32 exceptions = 0; | ||
| 764 | int tn, tm; | ||
| 765 | |||
| 766 | tn = vfp_single_type(vsn); | ||
| 767 | tm = vfp_single_type(vsm); | ||
| 768 | |||
| 769 | if (tn & tm & VFP_INFINITY) { | ||
| 770 | /* | ||
| 771 | * Two infinities. Are they different signs? | ||
| 772 | */ | ||
| 773 | if (vsn->sign ^ vsm->sign) { | ||
| 774 | /* | ||
| 775 | * different signs -> invalid | ||
| 776 | */ | ||
| 777 | exceptions |= FPSCR_IOC; | ||
| 778 | vsp = &vfp_single_default_qnan; | ||
| 779 | } else { | ||
| 780 | /* | ||
| 781 | * same signs -> valid | ||
| 782 | */ | ||
| 783 | vsp = vsn; | ||
| 784 | } | ||
| 785 | } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { | ||
| 786 | /* | ||
| 787 | * One infinity and one number -> infinity | ||
| 788 | */ | ||
| 789 | vsp = vsn; | ||
| 790 | } else { | ||
| 791 | /* | ||
| 792 | * 'n' is a NaN of some type | ||
| 793 | */ | ||
| 794 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 795 | } | ||
| 796 | *vsd = *vsp; | ||
| 797 | return exceptions; | ||
| 798 | } | ||
| 799 | |||
| 800 | static u32 vfp_single_add(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm, | ||
| 801 | u32 fpscr) { | ||
| 802 | u32 exp_diff, m_sig; | ||
| 803 | |||
| 804 | if (vsn->significand & 0x80000000 || vsm->significand & 0x80000000) { | ||
| 805 | LOG_WARNING(Core_ARM, "bad FP values"); | ||
| 806 | vfp_single_dump("VSN", vsn); | ||
| 807 | vfp_single_dump("VSM", vsm); | ||
| 808 | } | ||
| 809 | |||
| 810 | /* | ||
| 811 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 812 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 813 | * This ensures that NaN propagation works correctly. | ||
| 814 | */ | ||
| 815 | if (vsn->exponent < vsm->exponent) { | ||
| 816 | std::swap(vsm, vsn); | ||
| 817 | } | ||
| 818 | |||
| 819 | /* | ||
| 820 | * Is 'n' an infinity or a NaN? Note that 'm' may be a number, | ||
| 821 | * infinity or a NaN here. | ||
| 822 | */ | ||
| 823 | if (vsn->exponent == 255) | ||
| 824 | return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); | ||
| 825 | |||
| 826 | /* | ||
| 827 | * We have two proper numbers, where 'vsn' is the larger magnitude. | ||
| 828 | * | ||
| 829 | * Copy 'n' to 'd' before doing the arithmetic. | ||
| 830 | */ | ||
| 831 | *vsd = *vsn; | ||
| 832 | |||
| 833 | /* | ||
| 834 | * Align both numbers. | ||
| 835 | */ | ||
| 836 | exp_diff = vsn->exponent - vsm->exponent; | ||
| 837 | m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); | ||
| 838 | |||
| 839 | /* | ||
| 840 | * If the signs are different, we are really subtracting. | ||
| 841 | */ | ||
| 842 | if (vsn->sign ^ vsm->sign) { | ||
| 843 | m_sig = vsn->significand - m_sig; | ||
| 844 | if ((s32)m_sig < 0) { | ||
| 845 | vsd->sign = vfp_sign_negate(vsd->sign); | ||
| 846 | m_sig = (~m_sig + 1); | ||
| 847 | } else if (m_sig == 0) { | ||
| 848 | vsd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; | ||
| 849 | } | ||
| 850 | } else { | ||
| 851 | m_sig = vsn->significand + m_sig; | ||
| 852 | } | ||
| 853 | vsd->significand = m_sig; | ||
| 854 | |||
| 855 | return 0; | ||
| 856 | } | ||
| 857 | |||
| 858 | static u32 vfp_single_multiply(struct vfp_single* vsd, struct vfp_single* vsn, | ||
| 859 | struct vfp_single* vsm, u32 fpscr) { | ||
| 860 | vfp_single_dump("VSN", vsn); | ||
| 861 | vfp_single_dump("VSM", vsm); | ||
| 862 | |||
| 863 | /* | ||
| 864 | * Ensure that 'n' is the largest magnitude number. Note that | ||
| 865 | * if 'n' and 'm' have equal exponents, we do not swap them. | ||
| 866 | * This ensures that NaN propagation works correctly. | ||
| 867 | */ | ||
| 868 | if (vsn->exponent < vsm->exponent) { | ||
| 869 | std::swap(vsm, vsn); | ||
| 870 | LOG_TRACE(Core_ARM, "swapping M <-> N"); | ||
| 871 | } | ||
| 872 | |||
| 873 | vsd->sign = vsn->sign ^ vsm->sign; | ||
| 874 | |||
| 875 | /* | ||
| 876 | * If 'n' is an infinity or NaN, handle it. 'm' may be anything. | ||
| 877 | */ | ||
| 878 | if (vsn->exponent == 255) { | ||
| 879 | if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) | ||
| 880 | return vfp_propagate_nan(vsd, vsn, vsm, fpscr); | ||
| 881 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 882 | *vsd = vfp_single_default_qnan; | ||
| 883 | return FPSCR_IOC; | ||
| 884 | } | ||
| 885 | vsd->exponent = vsn->exponent; | ||
| 886 | vsd->significand = 0; | ||
| 887 | return 0; | ||
| 888 | } | ||
| 889 | |||
| 890 | /* | ||
| 891 | * If 'm' is zero, the result is always zero. In this case, | ||
| 892 | * 'n' may be zero or a number, but it doesn't matter which. | ||
| 893 | */ | ||
| 894 | if ((vsm->exponent | vsm->significand) == 0) { | ||
| 895 | vsd->exponent = 0; | ||
| 896 | vsd->significand = 0; | ||
| 897 | return 0; | ||
| 898 | } | ||
| 899 | |||
| 900 | /* | ||
| 901 | * We add 2 to the destination exponent for the same reason as | ||
| 902 | * the addition case - though this time we have +1 from each | ||
| 903 | * input operand. | ||
| 904 | */ | ||
| 905 | vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; | ||
| 906 | vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); | ||
| 907 | |||
| 908 | vfp_single_dump("VSD", vsd); | ||
| 909 | return 0; | ||
| 910 | } | ||
| 911 | |||
| 912 | #define NEG_MULTIPLY (1 << 0) | ||
| 913 | #define NEG_SUBTRACT (1 << 1) | ||
| 914 | |||
| 915 | static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, | ||
| 916 | u32 negate, const char* func) { | ||
| 917 | vfp_single vsd, vsp, vsn, vsm; | ||
| 918 | u32 exceptions = 0; | ||
| 919 | s32 v; | ||
| 920 | |||
| 921 | v = vfp_get_float(state, sn); | ||
| 922 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, v); | ||
| 923 | exceptions |= vfp_single_unpack(&vsn, v, fpscr); | ||
| 924 | if (vsn.exponent == 0 && vsn.significand) | ||
| 925 | vfp_single_normalise_denormal(&vsn); | ||
| 926 | |||
| 927 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 928 | if (vsm.exponent == 0 && vsm.significand) | ||
| 929 | vfp_single_normalise_denormal(&vsm); | ||
| 930 | |||
| 931 | exceptions |= vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); | ||
| 932 | |||
| 933 | if (negate & NEG_MULTIPLY) | ||
| 934 | vsp.sign = vfp_sign_negate(vsp.sign); | ||
| 935 | |||
| 936 | v = vfp_get_float(state, sd); | ||
| 937 | LOG_TRACE(Core_ARM, "s%u = %08x", sd, v); | ||
| 938 | exceptions |= vfp_single_unpack(&vsn, v, fpscr); | ||
| 939 | if (vsn.exponent == 0 && vsn.significand != 0) | ||
| 940 | vfp_single_normalise_denormal(&vsn); | ||
| 941 | |||
| 942 | if (negate & NEG_SUBTRACT) | ||
| 943 | vsn.sign = vfp_sign_negate(vsn.sign); | ||
| 944 | |||
| 945 | exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); | ||
| 946 | |||
| 947 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); | ||
| 948 | } | ||
| 949 | |||
| 950 | /* | ||
| 951 | * Standard operations | ||
| 952 | */ | ||
| 953 | |||
| 954 | /* | ||
| 955 | * sd = sd + (sn * sm) | ||
| 956 | */ | ||
| 957 | static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 958 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); | ||
| 959 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); | ||
| 960 | } | ||
| 961 | |||
| 962 | /* | ||
| 963 | * sd = sd - (sn * sm) | ||
| 964 | */ | ||
| 965 | static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 966 | // TODO: this one has its arguments inverted, investigate. | ||
| 967 | LOG_TRACE(Core_ARM, "s%u = %08x", sd, sn); | ||
| 968 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); | ||
| 969 | } | ||
| 970 | |||
| 971 | /* | ||
| 972 | * sd = -sd + (sn * sm) | ||
| 973 | */ | ||
| 974 | static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 975 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); | ||
| 976 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); | ||
| 977 | } | ||
| 978 | |||
| 979 | /* | ||
| 980 | * sd = -sd - (sn * sm) | ||
| 981 | */ | ||
| 982 | static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 983 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); | ||
| 984 | return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, | ||
| 985 | "fnmsc"); | ||
| 986 | } | ||
| 987 | |||
| 988 | /* | ||
| 989 | * sd = sn * sm | ||
| 990 | */ | ||
| 991 | static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 992 | struct vfp_single vsd, vsn, vsm; | ||
| 993 | u32 exceptions = 0; | ||
| 994 | s32 n = vfp_get_float(state, sn); | ||
| 995 | |||
| 996 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); | ||
| 997 | |||
| 998 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); | ||
| 999 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1000 | vfp_single_normalise_denormal(&vsn); | ||
| 1001 | |||
| 1002 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 1003 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1004 | vfp_single_normalise_denormal(&vsm); | ||
| 1005 | |||
| 1006 | exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1007 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | /* | ||
| 1011 | * sd = -(sn * sm) | ||
| 1012 | */ | ||
| 1013 | static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 1014 | struct vfp_single vsd, vsn, vsm; | ||
| 1015 | u32 exceptions = 0; | ||
| 1016 | s32 n = vfp_get_float(state, sn); | ||
| 1017 | |||
| 1018 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); | ||
| 1019 | |||
| 1020 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); | ||
| 1021 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1022 | vfp_single_normalise_denormal(&vsn); | ||
| 1023 | |||
| 1024 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 1025 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1026 | vfp_single_normalise_denormal(&vsm); | ||
| 1027 | |||
| 1028 | exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); | ||
| 1029 | vsd.sign = vfp_sign_negate(vsd.sign); | ||
| 1030 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | /* | ||
| 1034 | * sd = sn + sm | ||
| 1035 | */ | ||
| 1036 | static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 1037 | struct vfp_single vsd, vsn, vsm; | ||
| 1038 | u32 exceptions = 0; | ||
| 1039 | s32 n = vfp_get_float(state, sn); | ||
| 1040 | |||
| 1041 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); | ||
| 1042 | |||
| 1043 | /* | ||
| 1044 | * Unpack and normalise denormals. | ||
| 1045 | */ | ||
| 1046 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); | ||
| 1047 | if (vsn.exponent == 0 && vsn.significand) | ||
| 1048 | vfp_single_normalise_denormal(&vsn); | ||
| 1049 | |||
| 1050 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 1051 | if (vsm.exponent == 0 && vsm.significand) | ||
| 1052 | vfp_single_normalise_denormal(&vsm); | ||
| 1053 | |||
| 1054 | exceptions |= vfp_single_add(&vsd, &vsn, &vsm, fpscr); | ||
| 1055 | |||
| 1056 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | /* | ||
| 1060 | * sd = sn - sm | ||
| 1061 | */ | ||
| 1062 | static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 1063 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); | ||
| 1064 | /* | ||
| 1065 | * Subtraction is addition with one sign inverted. Unpack the second operand to perform FTZ if | ||
| 1066 | * necessary, we can't let fadd do this because a denormal in m might get flushed to +0 in FTZ | ||
| 1067 | * mode, and the resulting sign of 0 OP +0 differs between fadd and fsub. We do not need to do | ||
| 1068 | * this for n because +0 OP 0 is always +0 for both fadd and fsub. | ||
| 1069 | */ | ||
| 1070 | struct vfp_single vsm; | ||
| 1071 | u32 exceptions = vfp_single_unpack(&vsm, m, fpscr); | ||
| 1072 | if (exceptions & FPSCR_IDC) { | ||
| 1073 | // The value was flushed to zero, re-pack it. | ||
| 1074 | m = vfp_single_pack(&vsm); | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | if (m != 0x7FC00000) // Only negate if m isn't NaN. | ||
| 1078 | m = vfp_single_packed_negate(m); | ||
| 1079 | |||
| 1080 | return vfp_single_fadd(state, sd, sn, m, fpscr) | exceptions; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | /* | ||
| 1084 | * sd = sn / sm | ||
| 1085 | */ | ||
| 1086 | static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { | ||
| 1087 | struct vfp_single vsd, vsn, vsm; | ||
| 1088 | u32 exceptions = 0; | ||
| 1089 | s32 n = vfp_get_float(state, sn); | ||
| 1090 | int tm, tn; | ||
| 1091 | |||
| 1092 | LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); | ||
| 1093 | |||
| 1094 | exceptions |= vfp_single_unpack(&vsn, n, fpscr); | ||
| 1095 | exceptions |= vfp_single_unpack(&vsm, m, fpscr); | ||
| 1096 | |||
| 1097 | vsd.sign = vsn.sign ^ vsm.sign; | ||
| 1098 | |||
| 1099 | tn = vfp_single_type(&vsn); | ||
| 1100 | tm = vfp_single_type(&vsm); | ||
| 1101 | |||
| 1102 | /* | ||
| 1103 | * Is n a NAN? | ||
| 1104 | */ | ||
| 1105 | if (tn & VFP_NAN) | ||
| 1106 | goto vsn_nan; | ||
| 1107 | |||
| 1108 | /* | ||
| 1109 | * Is m a NAN? | ||
| 1110 | */ | ||
| 1111 | if (tm & VFP_NAN) | ||
| 1112 | goto vsm_nan; | ||
| 1113 | |||
| 1114 | /* | ||
| 1115 | * If n and m are infinity, the result is invalid | ||
| 1116 | * If n and m are zero, the result is invalid | ||
| 1117 | */ | ||
| 1118 | if (tm & tn & (VFP_INFINITY | VFP_ZERO)) | ||
| 1119 | goto invalid; | ||
| 1120 | |||
| 1121 | /* | ||
| 1122 | * If n is infinity, the result is infinity | ||
| 1123 | */ | ||
| 1124 | if (tn & VFP_INFINITY) | ||
| 1125 | goto infinity; | ||
| 1126 | |||
| 1127 | /* | ||
| 1128 | * If m is zero, raise div0 exception | ||
| 1129 | */ | ||
| 1130 | if (tm & VFP_ZERO) | ||
| 1131 | goto divzero; | ||
| 1132 | |||
| 1133 | /* | ||
| 1134 | * If m is infinity, or n is zero, the result is zero | ||
| 1135 | */ | ||
| 1136 | if (tm & VFP_INFINITY || tn & VFP_ZERO) | ||
| 1137 | goto zero; | ||
| 1138 | |||
| 1139 | if (tn & VFP_DENORMAL) | ||
| 1140 | vfp_single_normalise_denormal(&vsn); | ||
| 1141 | if (tm & VFP_DENORMAL) | ||
| 1142 | vfp_single_normalise_denormal(&vsm); | ||
| 1143 | |||
| 1144 | /* | ||
| 1145 | * Ok, we have two numbers, we can perform division. | ||
| 1146 | */ | ||
| 1147 | vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; | ||
| 1148 | vsm.significand <<= 1; | ||
| 1149 | if (vsm.significand <= (2 * vsn.significand)) { | ||
| 1150 | vsn.significand >>= 1; | ||
| 1151 | vsd.exponent++; | ||
| 1152 | } | ||
| 1153 | { | ||
| 1154 | u64 significand = (u64)vsn.significand << 32; | ||
| 1155 | do_div(significand, vsm.significand); | ||
| 1156 | vsd.significand = (u32)significand; | ||
| 1157 | } | ||
| 1158 | if ((vsd.significand & 0x3f) == 0) | ||
| 1159 | vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); | ||
| 1160 | |||
| 1161 | return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); | ||
| 1162 | |||
| 1163 | vsn_nan: | ||
| 1164 | exceptions |= vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); | ||
| 1165 | pack: | ||
| 1166 | vfp_put_float(state, vfp_single_pack(&vsd), sd); | ||
| 1167 | return exceptions; | ||
| 1168 | |||
| 1169 | vsm_nan: | ||
| 1170 | exceptions |= vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); | ||
| 1171 | goto pack; | ||
| 1172 | |||
| 1173 | zero: | ||
| 1174 | vsd.exponent = 0; | ||
| 1175 | vsd.significand = 0; | ||
| 1176 | goto pack; | ||
| 1177 | |||
| 1178 | divzero: | ||
| 1179 | exceptions |= FPSCR_DZC; | ||
| 1180 | infinity: | ||
| 1181 | vsd.exponent = 255; | ||
| 1182 | vsd.significand = 0; | ||
| 1183 | goto pack; | ||
| 1184 | |||
| 1185 | invalid: | ||
| 1186 | vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); | ||
| 1187 | return FPSCR_IOC; | ||
| 1188 | } | ||
| 1189 | |||
| 1190 | static struct op fops[] = { | ||
| 1191 | {vfp_single_fmac, 0}, {vfp_single_fmsc, 0}, {vfp_single_fmul, 0}, | ||
| 1192 | {vfp_single_fadd, 0}, {vfp_single_fnmac, 0}, {vfp_single_fnmsc, 0}, | ||
| 1193 | {vfp_single_fnmul, 0}, {vfp_single_fsub, 0}, {vfp_single_fdiv, 0}, | ||
| 1194 | }; | ||
| 1195 | |||
| 1196 | #define FREG_BANK(x) ((x)&0x18) | ||
| 1197 | #define FREG_IDX(x) ((x)&7) | ||
| 1198 | |||
| 1199 | u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { | ||
| 1200 | u32 op = inst & FOP_MASK; | ||
| 1201 | u32 exceptions = 0; | ||
| 1202 | unsigned int dest; | ||
| 1203 | unsigned int sn = vfp_get_sn(inst); | ||
| 1204 | unsigned int sm = vfp_get_sm(inst); | ||
| 1205 | unsigned int vecitr, veclen, vecstride; | ||
| 1206 | struct op* fop; | ||
| 1207 | |||
| 1208 | vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); | ||
| 1209 | |||
| 1210 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | ||
| 1211 | |||
| 1212 | /* | ||
| 1213 | * fcvtsd takes a dN register number as destination, not sN. | ||
| 1214 | * Technically, if bit 0 of dd is set, this is an invalid | ||
| 1215 | * instruction. However, we ignore this for efficiency. | ||
| 1216 | * It also only operates on scalars. | ||
| 1217 | */ | ||
| 1218 | if (fop->flags & OP_DD) | ||
| 1219 | dest = vfp_get_dd(inst); | ||
| 1220 | else | ||
| 1221 | dest = vfp_get_sd(inst); | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * If destination bank is zero, vector length is always '1'. | ||
| 1225 | * ARM DDI0100F C5.1.3, C5.3.2. | ||
| 1226 | */ | ||
| 1227 | if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) | ||
| 1228 | veclen = 0; | ||
| 1229 | else | ||
| 1230 | veclen = fpscr & FPSCR_LENGTH_MASK; | ||
| 1231 | |||
| 1232 | LOG_TRACE(Core_ARM, "vecstride=%u veclen=%u", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1); | ||
| 1233 | |||
| 1234 | if (!fop->fn) { | ||
| 1235 | LOG_CRITICAL(Core_ARM, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), | ||
| 1236 | inst, state->Reg[15]); | ||
| 1237 | Crash(); | ||
| 1238 | goto invalid; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { | ||
| 1242 | s32 m = vfp_get_float(state, sm); | ||
| 1243 | u32 except; | ||
| 1244 | char type; | ||
| 1245 | |||
| 1246 | type = (fop->flags & OP_DD) ? 'd' : 's'; | ||
| 1247 | if (op == FOP_EXT) | ||
| 1248 | LOG_TRACE(Core_ARM, "itr%d (%c%u) = op[%u] (s%u=%08x)", vecitr >> FPSCR_LENGTH_BIT, | ||
| 1249 | type, dest, sn, sm, m); | ||
| 1250 | else | ||
| 1251 | LOG_TRACE(Core_ARM, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)", | ||
| 1252 | vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, FOP_TO_IDX(op), sm, m); | ||
| 1253 | |||
| 1254 | except = fop->fn(state, dest, sn, m, fpscr); | ||
| 1255 | LOG_TRACE(Core_ARM, "itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); | ||
| 1256 | |||
| 1257 | exceptions |= except & ~VFP_NAN_FLAG; | ||
| 1258 | |||
| 1259 | /* | ||
| 1260 | * CHECK: It appears to be undefined whether we stop when | ||
| 1261 | * we encounter an exception. We continue. | ||
| 1262 | */ | ||
| 1263 | dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); | ||
| 1264 | sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); | ||
| 1265 | if (FREG_BANK(sm) != 0) | ||
| 1266 | sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); | ||
| 1267 | } | ||
| 1268 | return exceptions; | ||
| 1269 | |||
| 1270 | invalid: | ||
| 1271 | return (u32)-1; | ||
| 1272 | } | ||
diff --git a/src/core/core.cpp b/src/core/core.cpp index 6358e827b..886cb0972 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/arm/arm_interface.h" | 9 | #include "core/arm/arm_interface.h" |
| 10 | #include "core/arm/dynarmic/arm_dynarmic.h" | 10 | #include "core/arm/dynarmic/arm_dynarmic.h" |
| 11 | #include "core/arm/dyncom/arm_dyncom.h" | ||
| 12 | #include "core/arm/unicorn/arm_unicorn.h" | 11 | #include "core/arm/unicorn/arm_unicorn.h" |
| 13 | #include "core/core.h" | 12 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 13 | #include "core/core_timing.h" |
| @@ -142,9 +141,9 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
| 142 | LOG_DEBUG(HW_Memory, "initialized OK"); | 141 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 143 | 142 | ||
| 144 | if (Settings::values.use_cpu_jit) { | 143 | if (Settings::values.use_cpu_jit) { |
| 145 | cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE); | 144 | cpu_core = std::make_unique<ARM_Dynarmic>(); |
| 146 | } else { | 145 | } else { |
| 147 | cpu_core = std::make_unique<ARM_DynCom>(USER32MODE); | 146 | cpu_core = std::make_unique<ARM_Unicorn>(); |
| 148 | } | 147 | } |
| 149 | 148 | ||
| 150 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 149 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index d6be16ef6..dedbd4bdf 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -547,8 +547,7 @@ static void ReadRegister() { | |||
| 547 | id - CPSR_REGISTER - | 547 | id - CPSR_REGISTER - |
| 548 | 1)); // VFP registers should start at 26, so one after CSPR_REGISTER | 548 | 1)); // VFP registers should start at 26, so one after CSPR_REGISTER |
| 549 | } else if (id == FPSCR_REGISTER) { | 549 | } else if (id == FPSCR_REGISTER) { |
| 550 | IntToGdbHex(reply, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR | 550 | UNIMPLEMENTED(); |
| 551 | IntToGdbHex(reply + 8, 0); | ||
| 552 | } else { | 551 | } else { |
| 553 | return SendReply("E01"); | 552 | return SendReply("E01"); |
| 554 | } | 553 | } |
| @@ -579,8 +578,6 @@ static void ReadRegisters() { | |||
| 579 | 578 | ||
| 580 | bufptr += (32 * CHAR_BIT); | 579 | bufptr += (32 * CHAR_BIT); |
| 581 | 580 | ||
| 582 | IntToGdbHex(bufptr, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); | ||
| 583 | |||
| 584 | SendReply(reinterpret_cast<char*>(buffer)); | 581 | SendReply(reinterpret_cast<char*>(buffer)); |
| 585 | } | 582 | } |
| 586 | 583 | ||
| @@ -602,7 +599,7 @@ static void WriteRegister() { | |||
| 602 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | 599 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { |
| 603 | Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); | 600 | Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); |
| 604 | } else if (id == FPSCR_REGISTER) { | 601 | } else if (id == FPSCR_REGISTER) { |
| 605 | Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr)); | 602 | UNIMPLEMENTED(); |
| 606 | } else { | 603 | } else { |
| 607 | return SendReply("E01"); | 604 | return SendReply("E01"); |
| 608 | } | 605 | } |
| @@ -631,7 +628,7 @@ static void WriteRegisters() { | |||
| 631 | Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | 628 | Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); |
| 632 | i++; // Skip padding | 629 | i++; // Skip padding |
| 633 | } else if (reg == FPSCR_REGISTER) { | 630 | } else if (reg == FPSCR_REGISTER) { |
| 634 | Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | 631 | UNIMPLEMENTED(); |
| 635 | } | 632 | } |
| 636 | } | 633 | } |
| 637 | 634 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 1e5218000..debaa82e5 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -26,8 +26,8 @@ namespace Kernel { | |||
| 26 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 26 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 27 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); | 27 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x%llx", heap_size); |
| 28 | auto& process = *g_current_process; | 28 | auto& process = *g_current_process; |
| 29 | CASCADE_RESULT(*heap_addr, process.HeapAllocate(Memory::HEAP_VADDR, heap_size, | 29 | CASCADE_RESULT(*heap_addr, |
| 30 | VMAPermission::ReadWrite)); | 30 | process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); |
| 31 | return RESULT_SUCCESS; | 31 | return RESULT_SUCCESS; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| @@ -95,8 +95,7 @@ static ResultCode SendSyncRequest(Handle handle) { | |||
| 95 | static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | 95 | static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { |
| 96 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); | 96 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); |
| 97 | 97 | ||
| 98 | const SharedPtr<Thread> thread = | 98 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 99 | g_handle_table.Get<Thread>(thread_handle); | ||
| 100 | if (!thread) { | 99 | if (!thread) { |
| 101 | return ERR_INVALID_HANDLE; | 100 | return ERR_INVALID_HANDLE; |
| 102 | } | 101 | } |
| @@ -109,8 +108,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | |||
| 109 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | 108 | static ResultCode GetProcessId(u32* process_id, Handle process_handle) { |
| 110 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); | 109 | LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle); |
| 111 | 110 | ||
| 112 | const SharedPtr<Process> process = | 111 | const SharedPtr<Process> process = g_handle_table.Get<Process>(process_handle); |
| 113 | g_handle_table.Get<Process>(process_handle); | ||
| 114 | if (!process) { | 112 | if (!process) { |
| 115 | return ERR_INVALID_HANDLE; | 113 | return ERR_INVALID_HANDLE; |
| 116 | } | 114 | } |
| @@ -135,10 +133,8 @@ static ResultCode LockMutex(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 135 | "requesting_current_thread_handle=0x%08X", | 133 | "requesting_current_thread_handle=0x%08X", |
| 136 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 134 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 137 | 135 | ||
| 138 | SharedPtr<Thread> holding_thread = | 136 | SharedPtr<Thread> holding_thread = g_handle_table.Get<Thread>(holding_thread_handle); |
| 139 | g_handle_table.Get<Thread>(holding_thread_handle); | 137 | SharedPtr<Thread> requesting_thread = g_handle_table.Get<Thread>(requesting_thread_handle); |
| 140 | SharedPtr<Thread> requesting_thread = | ||
| 141 | g_handle_table.Get<Thread>(requesting_thread_handle); | ||
| 142 | 138 | ||
| 143 | ASSERT(holding_thread); | 139 | ASSERT(holding_thread); |
| 144 | ASSERT(requesting_thread); | 140 | ASSERT(requesting_thread); |
| @@ -302,8 +298,7 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd | |||
| 302 | static void ExitProcess() { | 298 | static void ExitProcess() { |
| 303 | LOG_INFO(Kernel_SVC, "Process %u exiting", g_current_process->process_id); | 299 | LOG_INFO(Kernel_SVC, "Process %u exiting", g_current_process->process_id); |
| 304 | 300 | ||
| 305 | ASSERT_MSG(g_current_process->status == ProcessStatus::Running, | 301 | ASSERT_MSG(g_current_process->status == ProcessStatus::Running, "Process has already exited"); |
| 306 | "Process has already exited"); | ||
| 307 | 302 | ||
| 308 | g_current_process->status = ProcessStatus::Exited; | 303 | g_current_process->status = ProcessStatus::Exited; |
| 309 | 304 | ||
| @@ -369,11 +364,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 369 | 364 | ||
| 370 | CASCADE_RESULT(SharedPtr<Thread> thread, | 365 | CASCADE_RESULT(SharedPtr<Thread> thread, |
| 371 | Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, | 366 | Thread::Create(name, entry_point, priority, arg, processor_id, stack_top, |
| 372 | g_current_process)); | 367 | g_current_process)); |
| 373 | |||
| 374 | thread->context.fpscr = | ||
| 375 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 | ||
| 376 | |||
| 377 | CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); | 368 | CASCADE_RESULT(thread->guest_handle, g_handle_table.Create(thread)); |
| 378 | *out_handle = thread->guest_handle; | 369 | *out_handle = thread->guest_handle; |
| 379 | 370 | ||
| @@ -391,8 +382,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 391 | static ResultCode StartThread(Handle thread_handle) { | 382 | static ResultCode StartThread(Handle thread_handle) { |
| 392 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); | 383 | LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle); |
| 393 | 384 | ||
| 394 | const SharedPtr<Thread> thread = | 385 | const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle); |
| 395 | g_handle_table.Get<Thread>(thread_handle); | ||
| 396 | if (!thread) { | 386 | if (!thread) { |
| 397 | return ERR_INVALID_HANDLE; | 387 | return ERR_INVALID_HANDLE; |
| 398 | } | 388 | } |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1588cfc7e..9132d1d77 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | #include "common/math_util.h" | 11 | #include "common/math_util.h" |
| 12 | #include "common/thread_queue_list.h" | 12 | #include "common/thread_queue_list.h" |
| 13 | #include "core/arm/arm_interface.h" | 13 | #include "core/arm/arm_interface.h" |
| 14 | #include "core/arm/skyeye_common/armstate.h" | ||
| 15 | #include "core/core.h" | 14 | #include "core/core.h" |
| 16 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 17 | #include "core/hle/kernel/errors.h" | 16 | #include "core/hle/kernel/errors.h" |
| @@ -365,7 +364,8 @@ static void ResetThreadContext(ARM_Interface::ThreadContext& context, VAddr stac | |||
| 365 | context.cpu_registers[0] = arg; | 364 | context.cpu_registers[0] = arg; |
| 366 | context.pc = entry_point; | 365 | context.pc = entry_point; |
| 367 | context.sp = stack_top; | 366 | context.sp = stack_top; |
| 368 | context.cpsr = USER32MODE; | 367 | context.cpsr = 0; |
| 368 | context.fpscr = 0; | ||
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, | 371 | ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, |
| @@ -504,8 +504,6 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority, | |||
| 504 | // Register 1 must be a handle to the main thread | 504 | // Register 1 must be a handle to the main thread |
| 505 | thread->guest_handle = Kernel::g_handle_table.Create(thread).Unwrap();; | 505 | thread->guest_handle = Kernel::g_handle_table.Create(thread).Unwrap();; |
| 506 | thread->context.cpu_registers[1] = thread->guest_handle; | 506 | thread->context.cpu_registers[1] = thread->guest_handle; |
| 507 | thread->context.fpscr = | ||
| 508 | FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010 | ||
| 509 | 507 | ||
| 510 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires | 508 | // Threads by default are dormant, wake up the main thread so it runs when the scheduler fires |
| 511 | thread->ResumeFromWait(); | 509 | thread->ResumeFromWait(); |