From b172f0d770486d4367fbea22906a5e908ef621e8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 2 Jan 2018 22:24:12 -0500 Subject: arm: Remove SkyEye/Dyncom code that is ARMv6-only. --- src/core/arm/skyeye_common/arm_regformat.h | 187 --- src/core/arm/skyeye_common/armstate.cpp | 597 --------- src/core/arm/skyeye_common/armstate.h | 245 ---- src/core/arm/skyeye_common/armsupp.cpp | 189 --- src/core/arm/skyeye_common/armsupp.h | 32 - src/core/arm/skyeye_common/vfp/asm_vfp.h | 83 -- src/core/arm/skyeye_common/vfp/vfp.cpp | 137 --- src/core/arm/skyeye_common/vfp/vfp.h | 43 - src/core/arm/skyeye_common/vfp/vfp_helper.h | 433 ------- src/core/arm/skyeye_common/vfp/vfpdouble.cpp | 1247 ------------------- src/core/arm/skyeye_common/vfp/vfpinstr.cpp | 1703 -------------------------- src/core/arm/skyeye_common/vfp/vfpsingle.cpp | 1272 ------------------- 12 files changed, 6168 deletions(-) delete mode 100644 src/core/arm/skyeye_common/arm_regformat.h delete mode 100644 src/core/arm/skyeye_common/armstate.cpp delete mode 100644 src/core/arm/skyeye_common/armstate.h delete mode 100644 src/core/arm/skyeye_common/armsupp.cpp delete mode 100644 src/core/arm/skyeye_common/armsupp.h delete mode 100644 src/core/arm/skyeye_common/vfp/asm_vfp.h delete mode 100644 src/core/arm/skyeye_common/vfp/vfp.cpp delete mode 100644 src/core/arm/skyeye_common/vfp/vfp.h delete mode 100644 src/core/arm/skyeye_common/vfp/vfp_helper.h delete mode 100644 src/core/arm/skyeye_common/vfp/vfpdouble.cpp delete mode 100644 src/core/arm/skyeye_common/vfp/vfpinstr.cpp delete mode 100644 src/core/arm/skyeye_common/vfp/vfpsingle.cpp (limited to 'src/core/arm/skyeye_common') 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 @@ -#pragma once - -enum { - R0 = 0, - R1, - R2, - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R10, - R11, - R12, - R13, - LR, - R15, // PC, - CPSR_REG, - SPSR_REG, - - PHYS_PC, - R13_USR, - R14_USR, - R13_SVC, - R14_SVC, - R13_ABORT, - R14_ABORT, - R13_UNDEF, - R14_UNDEF, - R13_IRQ, - R14_IRQ, - R8_FIRQ, - R9_FIRQ, - R10_FIRQ, - R11_FIRQ, - R12_FIRQ, - R13_FIRQ, - R14_FIRQ, - SPSR_INVALID1, - SPSR_INVALID2, - SPSR_SVC, - SPSR_ABORT, - SPSR_UNDEF, - SPSR_IRQ, - SPSR_FIRQ, - MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */ - BANK_REG, - EXCLUSIVE_TAG, - EXCLUSIVE_STATE, - EXCLUSIVE_RESULT, - - MAX_REG_NUM, -}; - -// VFP system registers -enum VFPSystemRegister { - VFP_FPSID, - VFP_FPSCR, - VFP_FPEXC, - VFP_FPINST, - VFP_FPINST2, - VFP_MVFR0, - VFP_MVFR1, - - // Not an actual register. - // All VFP system registers should be defined above this. - VFP_SYSTEM_REGISTER_COUNT -}; - -enum CP15Register { - // c0 - Information registers - CP15_MAIN_ID, - CP15_CACHE_TYPE, - CP15_TCM_STATUS, - CP15_TLB_TYPE, - CP15_CPU_ID, - CP15_PROCESSOR_FEATURE_0, - CP15_PROCESSOR_FEATURE_1, - CP15_DEBUG_FEATURE_0, - CP15_AUXILIARY_FEATURE_0, - CP15_MEMORY_MODEL_FEATURE_0, - CP15_MEMORY_MODEL_FEATURE_1, - CP15_MEMORY_MODEL_FEATURE_2, - CP15_MEMORY_MODEL_FEATURE_3, - CP15_ISA_FEATURE_0, - CP15_ISA_FEATURE_1, - CP15_ISA_FEATURE_2, - CP15_ISA_FEATURE_3, - CP15_ISA_FEATURE_4, - - // c1 - Control registers - CP15_CONTROL, - CP15_AUXILIARY_CONTROL, - CP15_COPROCESSOR_ACCESS_CONTROL, - - // c2 - Translation table registers - CP15_TRANSLATION_BASE_TABLE_0, - CP15_TRANSLATION_BASE_TABLE_1, - CP15_TRANSLATION_BASE_CONTROL, - CP15_DOMAIN_ACCESS_CONTROL, - CP15_RESERVED, - - // c5 - Fault status registers - CP15_FAULT_STATUS, - CP15_INSTR_FAULT_STATUS, - CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS, - CP15_INST_FSR, - - // c6 - Fault Address registers - CP15_FAULT_ADDRESS, - CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS, - CP15_WFAR, - CP15_IFAR, - - // c7 - Cache operation registers - CP15_WAIT_FOR_INTERRUPT, - CP15_PHYS_ADDRESS, - CP15_INVALIDATE_INSTR_CACHE, - CP15_INVALIDATE_INSTR_CACHE_USING_MVA, - CP15_INVALIDATE_INSTR_CACHE_USING_INDEX, - CP15_FLUSH_PREFETCH_BUFFER, - CP15_FLUSH_BRANCH_TARGET_CACHE, - CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY, - CP15_INVALIDATE_DATA_CACHE, - CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA, - CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, - CP15_INVALIDATE_DATA_AND_INSTR_CACHE, - CP15_CLEAN_DATA_CACHE, - CP15_CLEAN_DATA_CACHE_LINE_USING_MVA, - CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX, - CP15_DATA_SYNC_BARRIER, - CP15_DATA_MEMORY_BARRIER, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA, - CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX, - - // c8 - TLB operations - CP15_INVALIDATE_ITLB, - CP15_INVALIDATE_ITLB_SINGLE_ENTRY, - CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_ITLB_ENTRY_ON_MVA, - CP15_INVALIDATE_DTLB, - CP15_INVALIDATE_DTLB_SINGLE_ENTRY, - CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_DTLB_ENTRY_ON_MVA, - CP15_INVALIDATE_UTLB, - CP15_INVALIDATE_UTLB_SINGLE_ENTRY, - CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH, - CP15_INVALIDATE_UTLB_ENTRY_ON_MVA, - - // c9 - Data cache lockdown register - CP15_DATA_CACHE_LOCKDOWN, - - // c10 - TLB/Memory map registers - CP15_TLB_LOCKDOWN, - CP15_PRIMARY_REGION_REMAP, - CP15_NORMAL_REGION_REMAP, - - // c13 - Thread related registers - CP15_PID, - CP15_CONTEXT_ID, - CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write - CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W) - CP15_THREAD_PRW, // Thread ID register - Privileged R/W only. - - // c15 - Performance and TLB lockdown registers - CP15_PERFORMANCE_MONITOR_CONTROL, - CP15_CYCLE_COUNTER, - CP15_COUNT_0, - CP15_COUNT_1, - CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY, - CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY, - CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS, - CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS, - CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE, - CP15_TLB_DEBUG_CONTROL, - - // Skyeye defined - CP15_TLB_FAULT_ADDR, - CP15_TLB_FAULT_STATUS, - - // Not an actual register. - // All registers should be defined above this. - CP15_REGISTER_COUNT, -}; 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 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/logging/log.h" -#include "common/swap.h" -#include "core/arm/skyeye_common/armstate.h" -#include "core/arm/skyeye_common/vfp/vfp.h" -#include "core/gdbstub/gdbstub.h" -#include "core/memory.h" - -ARMul_State::ARMul_State(PrivilegeMode initial_mode) { - Reset(); - ChangePrivilegeMode(initial_mode); -} - -void ARMul_State::ChangePrivilegeMode(u32 new_mode) { - if (Mode == new_mode) - return; - - if (new_mode != USERBANK) { - switch (Mode) { - case SYSTEM32MODE: // Shares registers with user mode - case USER32MODE: - Reg_usr[0] = Reg[13]; - Reg_usr[1] = Reg[14]; - break; - case IRQ32MODE: - Reg_irq[0] = Reg[13]; - Reg_irq[1] = Reg[14]; - Spsr[IRQBANK] = Spsr_copy; - break; - case SVC32MODE: - Reg_svc[0] = Reg[13]; - Reg_svc[1] = Reg[14]; - Spsr[SVCBANK] = Spsr_copy; - break; - case ABORT32MODE: - Reg_abort[0] = Reg[13]; - Reg_abort[1] = Reg[14]; - Spsr[ABORTBANK] = Spsr_copy; - break; - case UNDEF32MODE: - Reg_undef[0] = Reg[13]; - Reg_undef[1] = Reg[14]; - Spsr[UNDEFBANK] = Spsr_copy; - break; - case FIQ32MODE: - std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin()); - Spsr[FIQBANK] = Spsr_copy; - break; - } - - switch (new_mode) { - case USER32MODE: - Reg[13] = Reg_usr[0]; - Reg[14] = Reg_usr[1]; - Bank = USERBANK; - break; - case IRQ32MODE: - Reg[13] = Reg_irq[0]; - Reg[14] = Reg_irq[1]; - Spsr_copy = Spsr[IRQBANK]; - Bank = IRQBANK; - break; - case SVC32MODE: - Reg[13] = Reg_svc[0]; - Reg[14] = Reg_svc[1]; - Spsr_copy = Spsr[SVCBANK]; - Bank = SVCBANK; - break; - case ABORT32MODE: - Reg[13] = Reg_abort[0]; - Reg[14] = Reg_abort[1]; - Spsr_copy = Spsr[ABORTBANK]; - Bank = ABORTBANK; - break; - case UNDEF32MODE: - Reg[13] = Reg_undef[0]; - Reg[14] = Reg_undef[1]; - Spsr_copy = Spsr[UNDEFBANK]; - Bank = UNDEFBANK; - break; - case FIQ32MODE: - std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8); - Spsr_copy = Spsr[FIQBANK]; - Bank = FIQBANK; - break; - case SYSTEM32MODE: // Shares registers with user mode. - Reg[13] = Reg_usr[0]; - Reg[14] = Reg_usr[1]; - Bank = SYSTEMBANK; - break; - } - - // Set the mode bits in the APSR - Cpsr = (Cpsr & ~Mode) | new_mode; - Mode = new_mode; - } -} - -// Performs a reset -void ARMul_State::Reset() { - VFPInit(this); - - // Set stack pointer to the top of the stack - Reg[13] = 0x10000000; - Reg[15] = 0; - - Cpsr = INTBITS | SVC32MODE; - Mode = SVC32MODE; - Bank = SVCBANK; - - ResetMPCoreCP15Registers(); - - NresetSig = HIGH; - NfiqSig = HIGH; - NirqSig = HIGH; - NtransSig = (Mode & 3) ? HIGH : LOW; - abortSig = LOW; - - NumInstrs = 0; - Emulate = RUN; -} - -// Resets certain MPCore CP15 values to their ARM-defined reset values. -void ARMul_State::ResetMPCoreCP15Registers() { - // c0 - CP15[CP15_MAIN_ID] = 0x410FB024; - CP15[CP15_TLB_TYPE] = 0x00000800; - CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111; - CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001; - CP15[CP15_DEBUG_FEATURE_0] = 0x00000002; - CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103; - CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302; - CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000; - CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000; - CP15[CP15_ISA_FEATURE_0] = 0x00100011; - CP15[CP15_ISA_FEATURE_1] = 0x12002111; - CP15[CP15_ISA_FEATURE_2] = 0x11221011; - CP15[CP15_ISA_FEATURE_3] = 0x01102131; - CP15[CP15_ISA_FEATURE_4] = 0x00000141; - - // c1 - CP15[CP15_CONTROL] = 0x00054078; - CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F; - CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000; - - // c2 - CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000; - CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000; - CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000; - - // c3 - CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000; - - // c7 - CP15[CP15_PHYS_ADDRESS] = 0x00000000; - - // c9 - CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0; - - // c10 - CP15[CP15_TLB_LOCKDOWN] = 0x00000000; - CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4; - CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0; - - // c13 - CP15[CP15_PID] = 0x00000000; - CP15[CP15_CONTEXT_ID] = 0x00000000; - CP15[CP15_THREAD_UPRW] = 0x00000000; - CP15[CP15_THREAD_URO] = 0x00000000; - CP15[CP15_THREAD_PRW] = 0x00000000; - - // c15 - CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000; - CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000; - CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000; - CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000; - CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; -} - -static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) { - if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) { - LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address); - GDBStub::Break(true); - } -} - -u8 ARMul_State::ReadMemory8(u32 address) const { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); - - return Memory::Read8(address); -} - -u16 ARMul_State::ReadMemory16(u32 address) const { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); - - u16 data = Memory::Read16(address); - - if (InBigEndianMode()) - data = Common::swap16(data); - - return data; -} - -u32 ARMul_State::ReadMemory32(u32 address) const { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); - - u32 data = Memory::Read32(address); - - if (InBigEndianMode()) - data = Common::swap32(data); - - return data; -} - -u64 ARMul_State::ReadMemory64(u32 address) const { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); - - u64 data = Memory::Read64(address); - - if (InBigEndianMode()) - data = Common::swap64(data); - - return data; -} - -void ARMul_State::WriteMemory8(u32 address, u8 data) { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); - - Memory::Write8(address, data); -} - -void ARMul_State::WriteMemory16(u32 address, u16 data) { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); - - if (InBigEndianMode()) - data = Common::swap16(data); - - Memory::Write16(address, data); -} - -void ARMul_State::WriteMemory32(u32 address, u32 data) { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); - - if (InBigEndianMode()) - data = Common::swap32(data); - - Memory::Write32(address, data); -} - -void ARMul_State::WriteMemory64(u32 address, u64 data) { - CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); - - if (InBigEndianMode()) - data = Common::swap64(data); - - Memory::Write64(address, data); -} - -// Reads from the CP15 registers. Used with implementation of the MRC instruction. -// Note that since the 3DS does not have the hypervisor extensions, these registers -// are not implemented. -u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const { - // Unprivileged registers - if (crn == 13 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 2) - return CP15[CP15_THREAD_UPRW]; - - if (opcode_2 == 3) - return CP15[CP15_THREAD_URO]; - } - - if (InAPrivilegedMode()) { - if (crn == 0 && opcode_1 == 0) { - if (crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_MAIN_ID]; - - if (opcode_2 == 1) - return CP15[CP15_CACHE_TYPE]; - - if (opcode_2 == 3) - return CP15[CP15_TLB_TYPE]; - - if (opcode_2 == 5) - return CP15[CP15_CPU_ID]; - } else if (crm == 1) { - if (opcode_2 == 0) - return CP15[CP15_PROCESSOR_FEATURE_0]; - - if (opcode_2 == 1) - return CP15[CP15_PROCESSOR_FEATURE_1]; - - if (opcode_2 == 2) - return CP15[CP15_DEBUG_FEATURE_0]; - - if (opcode_2 == 4) - return CP15[CP15_MEMORY_MODEL_FEATURE_0]; - - if (opcode_2 == 5) - return CP15[CP15_MEMORY_MODEL_FEATURE_1]; - - if (opcode_2 == 6) - return CP15[CP15_MEMORY_MODEL_FEATURE_2]; - - if (opcode_2 == 7) - return CP15[CP15_MEMORY_MODEL_FEATURE_3]; - } else if (crm == 2) { - if (opcode_2 == 0) - return CP15[CP15_ISA_FEATURE_0]; - - if (opcode_2 == 1) - return CP15[CP15_ISA_FEATURE_1]; - - if (opcode_2 == 2) - return CP15[CP15_ISA_FEATURE_2]; - - if (opcode_2 == 3) - return CP15[CP15_ISA_FEATURE_3]; - - if (opcode_2 == 4) - return CP15[CP15_ISA_FEATURE_4]; - } - } - - if (crn == 1 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_CONTROL]; - - if (opcode_2 == 1) - return CP15[CP15_AUXILIARY_CONTROL]; - - if (opcode_2 == 2) - return CP15[CP15_COPROCESSOR_ACCESS_CONTROL]; - } - - if (crn == 2 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_TRANSLATION_BASE_TABLE_0]; - - if (opcode_2 == 1) - return CP15[CP15_TRANSLATION_BASE_TABLE_1]; - - if (opcode_2 == 2) - return CP15[CP15_TRANSLATION_BASE_CONTROL]; - } - - if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) - return CP15[CP15_DOMAIN_ACCESS_CONTROL]; - - if (crn == 5 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_FAULT_STATUS]; - - if (opcode_2 == 1) - return CP15[CP15_INSTR_FAULT_STATUS]; - } - - if (crn == 6 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_FAULT_ADDRESS]; - - if (opcode_2 == 1) - return CP15[CP15_WFAR]; - } - - if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0) - return CP15[CP15_PHYS_ADDRESS]; - - if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) - return CP15[CP15_DATA_CACHE_LOCKDOWN]; - - if (crn == 10 && opcode_1 == 0) { - if (crm == 0 && opcode_2 == 0) - return CP15[CP15_TLB_LOCKDOWN]; - - if (crm == 2) { - if (opcode_2 == 0) - return CP15[CP15_PRIMARY_REGION_REMAP]; - - if (opcode_2 == 1) - return CP15[CP15_NORMAL_REGION_REMAP]; - } - } - - if (crn == 13 && crm == 0) { - if (opcode_2 == 0) - return CP15[CP15_PID]; - - if (opcode_2 == 1) - return CP15[CP15_CONTEXT_ID]; - - if (opcode_2 == 4) - return CP15[CP15_THREAD_PRW]; - } - - if (crn == 15) { - if (opcode_1 == 0 && crm == 12) { - if (opcode_2 == 0) - return CP15[CP15_PERFORMANCE_MONITOR_CONTROL]; - - if (opcode_2 == 1) - return CP15[CP15_CYCLE_COUNTER]; - - if (opcode_2 == 2) - return CP15[CP15_COUNT_0]; - - if (opcode_2 == 3) - return CP15[CP15_COUNT_1]; - } - - if (opcode_1 == 5 && opcode_2 == 2) { - if (crm == 5) - return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS]; - - if (crm == 6) - return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS]; - - if (crm == 7) - return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE]; - } - - if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) - return CP15[CP15_TLB_DEBUG_CONTROL]; - } - } - - LOG_ERROR(Core_ARM, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", - crn, crm, opcode_1, opcode_2); - return 0; -} - -// Write to the CP15 registers. Used with implementation of the MCR instruction. -// Note that since the 3DS does not have the hypervisor extensions, these registers -// are not implemented. -void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) { - if (InAPrivilegedMode()) { - if (crn == 1 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - CP15[CP15_CONTROL] = value; - else if (opcode_2 == 1) - CP15[CP15_AUXILIARY_CONTROL] = value; - else if (opcode_2 == 2) - CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value; - } else if (crn == 2 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - CP15[CP15_TRANSLATION_BASE_TABLE_0] = value; - else if (opcode_2 == 1) - CP15[CP15_TRANSLATION_BASE_TABLE_1] = value; - else if (opcode_2 == 2) - CP15[CP15_TRANSLATION_BASE_CONTROL] = value; - } else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { - CP15[CP15_DOMAIN_ACCESS_CONTROL] = value; - } else if (crn == 5 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - CP15[CP15_FAULT_STATUS] = value; - else if (opcode_2 == 1) - CP15[CP15_INSTR_FAULT_STATUS] = value; - } else if (crn == 6 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - CP15[CP15_FAULT_ADDRESS] = value; - else if (opcode_2 == 1) - CP15[CP15_WFAR] = value; - } else if (crn == 7 && opcode_1 == 0) { - if (crm == 0 && opcode_2 == 4) { - CP15[CP15_WAIT_FOR_INTERRUPT] = value; - } else if (crm == 4 && opcode_2 == 0) { - // NOTE: Not entirely accurate. This should do permission checks. - CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value); - } else if (crm == 5) { - if (opcode_2 == 0) - CP15[CP15_INVALIDATE_INSTR_CACHE] = value; - else if (opcode_2 == 1) - CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value; - else if (opcode_2 == 2) - CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value; - else if (opcode_2 == 6) - CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value; - else if (opcode_2 == 7) - CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value; - } else if (crm == 6) { - if (opcode_2 == 0) - CP15[CP15_INVALIDATE_DATA_CACHE] = value; - else if (opcode_2 == 1) - CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; - else if (opcode_2 == 2) - CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; - } else if (crm == 7 && opcode_2 == 0) { - CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value; - } else if (crm == 10) { - if (opcode_2 == 0) - CP15[CP15_CLEAN_DATA_CACHE] = value; - else if (opcode_2 == 1) - CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value; - else if (opcode_2 == 2) - CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value; - } else if (crm == 14) { - if (opcode_2 == 0) - CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value; - else if (opcode_2 == 1) - CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value; - else if (opcode_2 == 2) - CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value; - } - } else if (crn == 8 && opcode_1 == 0) { - if (crm == 5) { - if (opcode_2 == 0) - CP15[CP15_INVALIDATE_ITLB] = value; - else if (opcode_2 == 1) - CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value; - else if (opcode_2 == 2) - CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value; - else if (opcode_2 == 3) - CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value; - } else if (crm == 6) { - if (opcode_2 == 0) - CP15[CP15_INVALIDATE_DTLB] = value; - else if (opcode_2 == 1) - CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value; - else if (opcode_2 == 2) - CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value; - else if (opcode_2 == 3) - CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value; - } else if (crm == 7) { - if (opcode_2 == 0) - CP15[CP15_INVALIDATE_UTLB] = value; - else if (opcode_2 == 1) - CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value; - else if (opcode_2 == 2) - CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value; - else if (opcode_2 == 3) - CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value; - } - } else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0) { - CP15[CP15_DATA_CACHE_LOCKDOWN] = value; - } else if (crn == 10 && opcode_1 == 0) { - if (crm == 0 && opcode_2 == 0) { - CP15[CP15_TLB_LOCKDOWN] = value; - } else if (crm == 2) { - if (opcode_2 == 0) - CP15[CP15_PRIMARY_REGION_REMAP] = value; - else if (opcode_2 == 1) - CP15[CP15_NORMAL_REGION_REMAP] = value; - } - } else if (crn == 13 && opcode_1 == 0 && crm == 0) { - if (opcode_2 == 0) - CP15[CP15_PID] = value; - else if (opcode_2 == 1) - CP15[CP15_CONTEXT_ID] = value; - else if (opcode_2 == 3) - CP15[CP15_THREAD_URO] = value; - else if (opcode_2 == 4) - CP15[CP15_THREAD_PRW] = value; - } else if (crn == 15) { - if (opcode_1 == 0 && crm == 12) { - if (opcode_2 == 0) - CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value; - else if (opcode_2 == 1) - CP15[CP15_CYCLE_COUNTER] = value; - else if (opcode_2 == 2) - CP15[CP15_COUNT_0] = value; - else if (opcode_2 == 3) - CP15[CP15_COUNT_1] = value; - } else if (opcode_1 == 5) { - if (crm == 4) { - if (opcode_2 == 2) - CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value; - else if (opcode_2 == 4) - CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value; - } else if (crm == 5 && opcode_2 == 2) { - CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value; - } else if (crm == 6 && opcode_2 == 2) { - CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value; - } else if (crm == 7 && opcode_2 == 2) { - CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value; - } - } else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0) { - CP15[CP15_TLB_DEBUG_CONTROL] = value; - } - } - } - - // Unprivileged registers - if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4) { - CP15[CP15_FLUSH_PREFETCH_BUFFER] = value; - } else if (crn == 7 && opcode_1 == 0 && crm == 10) { - if (opcode_2 == 4) - CP15[CP15_DATA_SYNC_BARRIER] = value; - else if (opcode_2 == 5) - CP15[CP15_DATA_MEMORY_BARRIER] = value; - } else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) { - CP15[CP15_THREAD_UPRW] = value; - } -} 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 @@ -/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#pragma once - -#include -#include -#include "common/common_types.h" -#include "core/arm/skyeye_common/arm_regformat.h" - -// Signal levels -enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 }; - -// Cache types -enum { - NONCACHE = 0, - DATACACHE = 1, - INSTCACHE = 2, -}; - -// ARM privilege modes -enum PrivilegeMode { - USER32MODE = 16, - FIQ32MODE = 17, - IRQ32MODE = 18, - SVC32MODE = 19, - ABORT32MODE = 23, - UNDEF32MODE = 27, - SYSTEM32MODE = 31 -}; - -// ARM privilege mode register banks -enum { - USERBANK = 0, - FIQBANK = 1, - IRQBANK = 2, - SVCBANK = 3, - ABORTBANK = 4, - UNDEFBANK = 5, - DUMMYBANK = 6, - SYSTEMBANK = 7 -}; - -// Hardware vector addresses -enum { - ARMResetV = 0, - ARMUndefinedInstrV = 4, - ARMSWIV = 8, - ARMPrefetchAbortV = 12, - ARMDataAbortV = 16, - ARMAddrExceptnV = 20, - ARMIRQV = 24, - ARMFIQV = 28, - ARMErrorV = 32, // This is an offset, not an address! - - ARMul_ResetV = ARMResetV, - ARMul_UndefinedInstrV = ARMUndefinedInstrV, - ARMul_SWIV = ARMSWIV, - ARMul_PrefetchAbortV = ARMPrefetchAbortV, - ARMul_DataAbortV = ARMDataAbortV, - ARMul_AddrExceptnV = ARMAddrExceptnV, - ARMul_IRQV = ARMIRQV, - ARMul_FIQV = ARMFIQV -}; - -// Coprocessor status values -enum { - ARMul_FIRST = 0, - ARMul_TRANSFER = 1, - ARMul_BUSY = 2, - ARMul_DATA = 3, - ARMul_INTERRUPT = 4, - ARMul_DONE = 0, - ARMul_CANT = 1, - ARMul_INC = 3 -}; - -// Instruction condition codes -enum ConditionCode { - EQ = 0, - NE = 1, - CS = 2, - CC = 3, - MI = 4, - PL = 5, - VS = 6, - VC = 7, - HI = 8, - LS = 9, - GE = 10, - LT = 11, - GT = 12, - LE = 13, - AL = 14, - NV = 15, -}; - -// Flags for use with the APSR. -enum : u32 { - NBIT = (1U << 31U), - ZBIT = (1 << 30), - CBIT = (1 << 29), - VBIT = (1 << 28), - QBIT = (1 << 27), - JBIT = (1 << 24), - EBIT = (1 << 9), - ABIT = (1 << 8), - IBIT = (1 << 7), - FBIT = (1 << 6), - TBIT = (1 << 5), - - // Masks for groups of bits in the APSR. - MODEBITS = 0x1F, - INTBITS = 0x1C0, -}; - -// Values for Emulate. -enum { - STOP = 0, // Stop - CHANGEMODE = 1, // Change mode - ONCE = 2, // Execute just one iteration - RUN = 3 // Continuous execution -}; - -struct ARMul_State final { -public: - explicit ARMul_State(PrivilegeMode initial_mode); - - void ChangePrivilegeMode(u32 new_mode); - void Reset(); - - // Reads/writes data in big/little endian format based on the - // state of the E (endian) bit in the APSR. - u8 ReadMemory8(u32 address) const; - u16 ReadMemory16(u32 address) const; - u32 ReadMemory32(u32 address) const; - u64 ReadMemory64(u32 address) const; - void WriteMemory8(u32 address, u8 data); - void WriteMemory16(u32 address, u16 data); - void WriteMemory32(u32 address, u32 data); - void WriteMemory64(u32 address, u64 data); - - u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const; - void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2); - - // Exclusive memory access functions - bool IsExclusiveMemoryAccess(u32 address) const { - return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK); - } - void SetExclusiveMemoryAddress(u32 address) { - exclusive_tag = address & RESERVATION_GRANULE_MASK; - exclusive_state = true; - } - void UnsetExclusiveMemoryAddress() { - exclusive_tag = 0xFFFFFFFF; - exclusive_state = false; - } - - // Whether or not the given CPU is in big endian mode (E bit is set) - bool InBigEndianMode() const { - return (Cpsr & (1 << 9)) != 0; - } - // Whether or not the given CPU is in a mode other than user mode. - bool InAPrivilegedMode() const { - return (Mode != USER32MODE); - } - // Note that for the 3DS, a Thumb instruction will only ever be - // two bytes in size. Thus we don't need to worry about ThumbEE - // or Thumb-2 where instructions can be 4 bytes in length. - u32 GetInstructionSize() const { - return TFlag ? 2 : 4; - } - - std::array Reg{}; // The current register file - std::array Reg_usr{}; - std::array Reg_svc{}; // R13_SVC R14_SVC - std::array Reg_abort{}; // R13_ABORT R14_ABORT - std::array Reg_undef{}; // R13 UNDEF R14 UNDEF - std::array Reg_irq{}; // R13_IRQ R14_IRQ - std::array Reg_firq{}; // R8---R14 FIRQ - std::array Spsr{}; // The exception psr's - std::array CP15{}; - - // FPSID, FPSCR, and FPEXC - std::array VFP{}; - - // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). - // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), - // and only 32 singleword registers are accessible (S0-S31). - std::array ExtReg{}; - - u32 Emulate; // To start and stop emulation - u32 Cpsr; // The current PSR - u32 Spsr_copy; - u32 phys_pc; - - u32 Mode; // The current mode - u32 Bank; // The current register bank - - u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed - unsigned int shifter_carry_out; - - u32 TFlag; // Thumb state - - unsigned long long NumInstrs; // The number of instructions executed - unsigned NumInstrsToExecute; - - unsigned NresetSig; // Reset the processor - unsigned NfiqSig; - unsigned NirqSig; - - unsigned abortSig; - unsigned NtransSig; - unsigned bigendSig; - unsigned syscallSig; - - // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per - // process for our purposes), not per ARMul_State (which tracks CPU core state). - std::unordered_map instruction_cache; - -private: - void ResetMPCoreCP15Registers(); - - // Defines a reservation granule of 2 words, which protects the first 2 words starting at the - // tag. This is the smallest granule allowed by the v7 spec, and is coincidentally just large - // enough to support LDR/STREXD. - static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8; - - u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode - bool exclusive_state; -}; 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 @@ -/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "common/logging/log.h" -#include "core/arm/skyeye_common/arm_regformat.h" -#include "core/arm/skyeye_common/armstate.h" -#include "core/arm/skyeye_common/armsupp.h" - -// Unsigned sum of absolute difference -u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) { - if (left > right) - return left - right; - - return right - left; -} - -// Add with carry, indicates if a carry-out or signed overflow occurred. -u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, - bool* overflow_occurred) { - u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in; - s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in; - u64 result = (unsigned_sum & 0xFFFFFFFF); - - if (carry_out_occurred) - *carry_out_occurred = (result != unsigned_sum); - - if (overflow_occurred) - *overflow_occurred = ((s64)(s32)result != signed_sum); - - return (u32)result; -} - -// Compute whether an addition of A and B, giving RESULT, overflowed. -bool AddOverflow(u32 a, u32 b, u32 result) { - return ((NEG(a) && NEG(b) && POS(result)) || (POS(a) && POS(b) && NEG(result))); -} - -// Compute whether a subtraction of A and B, giving RESULT, overflowed. -bool SubOverflow(u32 a, u32 b, u32 result) { - return ((NEG(a) && POS(b) && POS(result)) || (POS(a) && NEG(b) && NEG(result))); -} - -// Returns true if the Q flag should be set as a result of overflow. -bool ARMul_AddOverflowQ(u32 a, u32 b) { - u32 result = a + b; - if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0) - return true; - - return false; -} - -// 8-bit signed saturated addition -u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right) { - u8 result = left + right; - - if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) { - if (left & 0x80) - result = 0x80; - else - result = 0x7F; - } - - return result; -} - -// 8-bit signed saturated subtraction -u8 ARMul_SignedSaturatedSub8(u8 left, u8 right) { - u8 result = left - right; - - if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) { - if (left & 0x80) - result = 0x80; - else - result = 0x7F; - } - - return result; -} - -// 16-bit signed saturated addition -u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right) { - u16 result = left + right; - - if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) { - if (left & 0x8000) - result = 0x8000; - else - result = 0x7FFF; - } - - return result; -} - -// 16-bit signed saturated subtraction -u16 ARMul_SignedSaturatedSub16(u16 left, u16 right) { - u16 result = left - right; - - if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) { - if (left & 0x8000) - result = 0x8000; - else - result = 0x7FFF; - } - - return result; -} - -// 8-bit unsigned saturated addition -u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right) { - u8 result = left + right; - - if (result < left) - result = 0xFF; - - return result; -} - -// 16-bit unsigned saturated addition -u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right) { - u16 result = left + right; - - if (result < left) - result = 0xFFFF; - - return result; -} - -// 8-bit unsigned saturated subtraction -u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right) { - if (left <= right) - return 0; - - return left - right; -} - -// 16-bit unsigned saturated subtraction -u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right) { - if (left <= right) - return 0; - - return left - right; -} - -// Signed saturation. -u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { - const u32 max = (1 << shift) - 1; - const s32 top = (value >> shift); - - if (top > 0) { - *saturation_occurred = true; - return max; - } else if (top < -1) { - *saturation_occurred = true; - return ~max; - } - - *saturation_occurred = false; - return (u32)value; -} - -// Unsigned saturation -u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred) { - const u32 max = (1 << shift) - 1; - - if (value < 0) { - *saturation_occurred = true; - return 0; - } else if ((u32)value > max) { - *saturation_occurred = true; - return max; - } - - *saturation_occurred = false; - return (u32)value; -} 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 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) -#define BIT(s, n) ((s >> (n)) & 1) - -#define POS(i) ((~(i)) >> 31) -#define NEG(i) ((i) >> 31) - -bool AddOverflow(u32, u32, u32); -bool SubOverflow(u32, u32, u32); - -u32 AddWithCarry(u32, u32, u32, bool*, bool*); -bool ARMul_AddOverflowQ(u32, u32); - -u8 ARMul_SignedSaturatedAdd8(u8, u8); -u8 ARMul_SignedSaturatedSub8(u8, u8); -u16 ARMul_SignedSaturatedAdd16(u16, u16); -u16 ARMul_SignedSaturatedSub16(u16, u16); - -u8 ARMul_UnsignedSaturatedAdd8(u8, u8); -u16 ARMul_UnsignedSaturatedAdd16(u16, u16); -u8 ARMul_UnsignedSaturatedSub8(u8, u8); -u16 ARMul_UnsignedSaturatedSub16(u16, u16); -u8 ARMul_UnsignedAbsoluteDifference(u8, u8); -u32 ARMul_SignedSatQ(s32, u8, bool*); -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 @@ -/* - * arch/arm/include/asm/vfp.h - * - * VFP register definitions. - * First, the standard VFP set. - */ - -#pragma once - -// ARM11 MPCore FPSID Information -// Note that these are used as values and not as flags. -enum : u32 { - VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0 - VFP_FPSID_SW = 0, // Software emulation bit value - VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number - VFP_FPSID_PARTNUM = 0x20, // Part number - VFP_FPSID_VARIANT = 0xB, // Variant number - VFP_FPSID_REVISION = 0x4 // Revision number -}; - -// FPEXC bits -enum : u32 { - FPEXC_EX = (1U << 31U), - FPEXC_EN = (1 << 30), - FPEXC_DEX = (1 << 29), - FPEXC_FP2V = (1 << 28), - FPEXC_VV = (1 << 27), - FPEXC_TFV = (1 << 26), - FPEXC_LENGTH_BIT = (8), - FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT), - FPEXC_IDF = (1 << 7), - FPEXC_IXF = (1 << 4), - FPEXC_UFF = (1 << 3), - FPEXC_OFF = (1 << 2), - FPEXC_DZF = (1 << 1), - FPEXC_IOF = (1 << 0), - FPEXC_TRAP_MASK = (FPEXC_IDF | FPEXC_IXF | FPEXC_UFF | FPEXC_OFF | FPEXC_DZF | FPEXC_IOF) -}; - -// FPSCR Flags -enum : u32 { - FPSCR_NFLAG = (1U << 31U), // Negative condition flag - FPSCR_ZFLAG = (1 << 30), // Zero condition flag - FPSCR_CFLAG = (1 << 29), // Carry condition flag - FPSCR_VFLAG = (1 << 28), // Overflow condition flag - - FPSCR_QC = (1 << 27), // Cumulative saturation bit - FPSCR_AHP = (1 << 26), // Alternative half-precision control bit - FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit - FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit - FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask - FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask - FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask - - FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable. - FPSCR_IXE = (1 << 12), // Inexact exception trap enable - FPSCR_UFE = (1 << 11), // Undeflow exception trap enable - FPSCR_OFE = (1 << 10), // Overflow exception trap enable - FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable - FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable - - FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit - FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit - FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit - FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit - FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit - FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit -}; - -// FPSCR bit offsets -enum : u32 { - FPSCR_RMODE_BIT = 22, - FPSCR_STRIDE_BIT = 20, - FPSCR_LENGTH_BIT = 16, -}; - -// FPSCR rounding modes -enum : u32 { - FPSCR_ROUND_NEAREST = (0 << 22), - FPSCR_ROUND_PLUSINF = (1 << 22), - FPSCR_ROUND_MINUSINF = (2 << 22), - FPSCR_ROUND_TOZERO = (3 << 22) -}; 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 @@ -/* - armvfp.c - ARM VFPv3 emulation unit - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* Note: this file handles interface with arm core and vfp registers */ - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/arm/skyeye_common/armstate.h" -#include "core/arm/skyeye_common/vfp/asm_vfp.h" -#include "core/arm/skyeye_common/vfp/vfp.h" - -void VFPInit(ARMul_State* state) { - state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN << 24 | VFP_FPSID_SW << 23 | VFP_FPSID_SUBARCH << 16 | - VFP_FPSID_PARTNUM << 8 | VFP_FPSID_VARIANT << 4 | VFP_FPSID_REVISION; - state->VFP[VFP_FPEXC] = 0; - state->VFP[VFP_FPSCR] = 0; - - // ARM11 MPCore instruction register reset values. - state->VFP[VFP_FPINST] = 0xEE000A00; - state->VFP[VFP_FPINST2] = 0; - - // ARM11 MPCore feature register values. - state->VFP[VFP_MVFR0] = 0x11111111; - state->VFP[VFP_MVFR1] = 0; -} - -void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value) { - if (to_arm) { - *value = state->ExtReg[n]; - } else { - state->ExtReg[n] = *value; - } -} - -void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { - if (to_arm) { - *value2 = state->ExtReg[n * 2 + 1]; - *value1 = state->ExtReg[n * 2]; - } else { - state->ExtReg[n * 2 + 1] = *value2; - state->ExtReg[n * 2] = *value1; - } -} -void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2) { - if (to_arm) { - *value1 = state->ExtReg[n + 0]; - *value2 = state->ExtReg[n + 1]; - } else { - state->ExtReg[n + 0] = *value1; - state->ExtReg[n + 1] = *value2; - } -} - -void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm) { - if (single) { - state->ExtReg[d] = imm; - } else { - /* Check endian please */ - state->ExtReg[d * 2 + 1] = imm; - state->ExtReg[d * 2] = 0; - } -} -void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) { - if (single) { - state->ExtReg[d] = state->ExtReg[m]; - } else { - /* Check endian please */ - state->ExtReg[d * 2 + 1] = state->ExtReg[m * 2 + 1]; - state->ExtReg[d * 2] = state->ExtReg[m * 2]; - } -} - -/* Miscellaneous functions */ -s32 vfp_get_float(ARMul_State* state, unsigned int reg) { - LOG_TRACE(Core_ARM, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]); - return state->ExtReg[reg]; -} - -void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) { - LOG_TRACE(Core_ARM, "VFP put float: s%d <= [%08x]", reg, val); - state->ExtReg[reg] = val; -} - -u64 vfp_get_double(ARMul_State* state, unsigned int reg) { - u64 result = ((u64)state->ExtReg[reg * 2 + 1]) << 32 | state->ExtReg[reg * 2]; - LOG_TRACE(Core_ARM, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result); - return result; -} - -void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) { - LOG_TRACE(Core_ARM, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, - (u32)(val >> 32), (u32)(val & 0xffffffff)); - state->ExtReg[reg * 2] = (u32)(val & 0xffffffff); - state->ExtReg[reg * 2 + 1] = (u32)(val >> 32); -} - -/* - * Process bitmask of exception conditions. (from vfpmodule.c) - */ -void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) { - LOG_TRACE(Core_ARM, "VFP: raising exceptions %08x", exceptions); - - if (exceptions == VFP_EXCEPTION_ERROR) { - LOG_CRITICAL(Core_ARM, "unhandled bounce %x", inst); - Crash(); - } - - /* - * If any of the status flags are set, update the FPSCR. - * Comparison instructions always return at least one of - * these flags set. - */ - if (exceptions & (FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG)) - fpscr &= ~(FPSCR_NFLAG | FPSCR_ZFLAG | FPSCR_CFLAG | FPSCR_VFLAG); - - fpscr |= exceptions; - - state->VFP[VFP_FPSCR] = fpscr; -} 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 @@ -/* - vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#pragma once - -#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ - -#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM, "in func %s, " #x " untested", __FUNCTION__); -#define CHECK_VFP_ENABLED -#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - -void VFPInit(ARMul_State* state); - -s32 vfp_get_float(ARMul_State* state, u32 reg); -void vfp_put_float(ARMul_State* state, s32 val, u32 reg); -u64 vfp_get_double(ARMul_State* state, u32 reg); -void vfp_put_double(ARMul_State* state, u64 val, u32 reg); -void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr); -u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); -u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); - -void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value); -void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); -void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2); -void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm); -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 @@ -/* - vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * The following code is derivative from Linux Android kernel vfp - * floating point support. - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#pragma once - -#include -#include "common/common_types.h" -#include "core/arm/skyeye_common/armstate.h" -#include "core/arm/skyeye_common/vfp/asm_vfp.h" - -#define do_div(n, base) \ - { n /= base; } - -enum : u32 { - FOP_MASK = 0x00b00040, - FOP_FMAC = 0x00000000, - FOP_FNMAC = 0x00000040, - FOP_FMSC = 0x00100000, - FOP_FNMSC = 0x00100040, - FOP_FMUL = 0x00200000, - FOP_FNMUL = 0x00200040, - FOP_FADD = 0x00300000, - FOP_FSUB = 0x00300040, - FOP_FDIV = 0x00800000, - FOP_EXT = 0x00b00040 -}; - -#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4) - -enum : u32 { - FEXT_MASK = 0x000f0080, - FEXT_FCPY = 0x00000000, - FEXT_FABS = 0x00000080, - FEXT_FNEG = 0x00010000, - FEXT_FSQRT = 0x00010080, - FEXT_FCMP = 0x00040000, - FEXT_FCMPE = 0x00040080, - FEXT_FCMPZ = 0x00050000, - FEXT_FCMPEZ = 0x00050080, - FEXT_FCVT = 0x00070080, - FEXT_FUITO = 0x00080000, - FEXT_FSITO = 0x00080080, - FEXT_FTOUI = 0x000c0000, - FEXT_FTOUIZ = 0x000c0080, - FEXT_FTOSI = 0x000d0000, - FEXT_FTOSIZ = 0x000d0080 -}; - -#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) - -#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22) -#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18) -#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5) -#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1) -#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7) -#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3) - -#define vfp_single(inst) (((inst)&0x0000f00) == 0xa00) - -inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) { - if (shift) { - if (shift < 32) - val = val >> shift | ((val << (32 - shift)) != 0); - else - val = val != 0; - } - return val; -} - -inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) { - if (shift) { - if (shift < 64) - val = val >> shift | ((val << (64 - shift)) != 0); - else - val = val != 0; - } - return val; -} - -inline u32 vfp_hi64to32jamming(u64 val) { - u32 v; - u32 highval = val >> 32; - u32 lowval = val & 0xffffffff; - - if (lowval >= 1) - v = highval | 1; - else - v = highval; - - return v; -} - -inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { - *resl = nl + ml; - *resh = nh + mh; - if (*resl < nl) - *resh += 1; -} - -inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) { - *resl = nl - ml; - *resh = nh - mh; - if (*resl > nl) - *resh -= 1; -} - -inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) { - u32 nh, nl, mh, ml; - u64 rh, rma, rmb, rl; - - nl = static_cast(n); - ml = static_cast(m); - rl = (u64)nl * ml; - - nh = n >> 32; - rma = (u64)nh * ml; - - mh = m >> 32; - rmb = (u64)nl * mh; - rma += rmb; - - rh = (u64)nh * mh; - rh += ((u64)(rma < rmb) << 32) + (rma >> 32); - - rma <<= 32; - rl += rma; - rh += (rl < rma); - - *resl = rl; - *resh = rh; -} - -inline void shift64left(u64* resh, u64* resl, u64 n) { - *resh = n >> 63; - *resl = n << 1; -} - -inline u64 vfp_hi64multiply64(u64 n, u64 m) { - u64 rh, rl; - mul64to128(&rh, &rl, n, m); - return rh | (rl != 0); -} - -inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) { - u64 mh, ml, remh, reml, termh, terml, z; - - if (nh >= m) - return ~0ULL; - mh = m >> 32; - if (mh << 32 <= nh) { - z = 0xffffffff00000000ULL; - } else { - z = nh; - do_div(z, mh); - z <<= 32; - } - mul64to128(&termh, &terml, m, z); - sub128(&remh, &reml, nh, nl, termh, terml); - ml = m << 32; - while ((s64)remh < 0) { - z -= 0x100000000ULL; - add128(&remh, &reml, remh, reml, mh, ml); - } - remh = (remh << 32) | (reml >> 32); - if (mh << 32 <= remh) { - z |= 0xffffffff; - } else { - do_div(remh, mh); - z |= remh; - } - return z; -} - -// Operations on unpacked elements -#define vfp_sign_negate(sign) (sign ^ 0x8000) - -// Single-precision -struct vfp_single { - s16 exponent; - u16 sign; - u32 significand; -}; - -// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa -// VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent -// VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand -// which are not propagated to the float upon packing. -#define VFP_SINGLE_MANTISSA_BITS (23) -#define VFP_SINGLE_EXPONENT_BITS (8) -#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2) -#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1) - -// The bit in an unpacked float which indicates that it is a quiet NaN -#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS)) - -// Operations on packed single-precision numbers -#define vfp_single_packed_sign(v) ((v)&0x80000000) -#define vfp_single_packed_negate(v) ((v) ^ 0x80000000) -#define vfp_single_packed_abs(v) ((v) & ~0x80000000) -#define vfp_single_packed_exponent(v) \ - (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1)) -#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1)) - -enum : u32 { - VFP_NUMBER = (1 << 0), - VFP_ZERO = (1 << 1), - VFP_DENORMAL = (1 << 2), - VFP_INFINITY = (1 << 3), - VFP_NAN = (1 << 4), - VFP_NAN_SIGNAL = (1 << 5), - - VFP_QNAN = (VFP_NAN), - VFP_SNAN = (VFP_NAN | VFP_NAN_SIGNAL) -}; - -inline int vfp_single_type(const vfp_single* s) { - int type = VFP_NUMBER; - if (s->exponent == 255) { - if (s->significand == 0) - type = VFP_INFINITY; - else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN) - type = VFP_QNAN; - else - type = VFP_SNAN; - } else if (s->exponent == 0) { - if (s->significand == 0) - type |= VFP_ZERO; - else - type |= VFP_DENORMAL; - } - return type; -} - -// Unpack a single-precision float. Note that this returns the magnitude -// of the single-precision float mantissa with the 1. if necessary, -// aligned to bit 30. -inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr) { - u32 exceptions = 0; - s->sign = vfp_single_packed_sign(val) >> 16, s->exponent = vfp_single_packed_exponent(val); - - u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2; - if (s->exponent && s->exponent != 255) - significand |= 0x40000000; - s->significand = significand; - - // If flush-to-zero mode is enabled, turn the denormal into zero. - // On a VFPv2 architecture, the sign of the zero is always positive. - if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) { - s->sign = 0; - s->exponent = 0; - s->significand = 0; - exceptions |= FPSCR_IDC; - } - return exceptions; -} - -// Re-pack a single-precision float. This assumes that the float is -// already normalised such that the MSB is bit 30, _not_ bit 31. -inline s32 vfp_single_pack(const vfp_single* s) { - u32 val = (s->sign << 16) + (s->exponent << VFP_SINGLE_MANTISSA_BITS) + - (s->significand >> VFP_SINGLE_LOW_BITS); - return (s32)val; -} - -u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, - const char* func); - -// Double-precision -struct vfp_double { - s16 exponent; - u16 sign; - u64 significand; -}; - -// VFP_REG_ZERO is a special register number for vfp_get_double -// which returns (double)0.0. This is useful for the compare with -// zero instructions. -#ifdef CONFIG_VFPv3 -#define VFP_REG_ZERO 32 -#else -#define VFP_REG_ZERO 16 -#endif - -#define VFP_DOUBLE_MANTISSA_BITS (52) -#define VFP_DOUBLE_EXPONENT_BITS (11) -#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2) -#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1) - -// The bit in an unpacked double which indicates that it is a quiet NaN -#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS)) - -// Operations on packed single-precision numbers -#define vfp_double_packed_sign(v) ((v) & (1ULL << 63)) -#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63)) -#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63)) -#define vfp_double_packed_exponent(v) \ - (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) -#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) - -inline int vfp_double_type(const vfp_double* s) { - int type = VFP_NUMBER; - if (s->exponent == 2047) { - if (s->significand == 0) - type = VFP_INFINITY; - else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN) - type = VFP_QNAN; - else - type = VFP_SNAN; - } else if (s->exponent == 0) { - if (s->significand == 0) - type |= VFP_ZERO; - else - type |= VFP_DENORMAL; - } - return type; -} - -// Unpack a double-precision float. Note that this returns the magnitude -// of the double-precision float mantissa with the 1. if necessary, -// aligned to bit 62. -inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr) { - u32 exceptions = 0; - s->sign = vfp_double_packed_sign(val) >> 48; - s->exponent = vfp_double_packed_exponent(val); - - u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2; - if (s->exponent && s->exponent != 2047) - significand |= (1ULL << 62); - s->significand = significand; - - // If flush-to-zero mode is enabled, turn the denormal into zero. - // On a VFPv2 architecture, the sign of the zero is always positive. - if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) { - s->sign = 0; - s->exponent = 0; - s->significand = 0; - exceptions |= FPSCR_IDC; - } - return exceptions; -} - -// Re-pack a double-precision float. This assumes that the float is -// already normalised such that the MSB is bit 30, _not_ bit 31. -inline s64 vfp_double_pack(const vfp_double* s) { - u64 val = ((u64)s->sign << 48) + ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + - (s->significand >> VFP_DOUBLE_LOW_BITS); - return (s64)val; -} - -u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand); - -// A special flag to tell the normalisation code not to normalise. -#define VFP_NAN_FLAG 0x100 - -// A bit pattern used to indicate the initial (unset) value of the -// exception mask, in case nothing handles an instruction. This -// doesn't include the NAN flag, which get masked out before -// we check for an error. -#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG) - -// A flag to tell vfp instruction type. -// OP_SCALAR - This operation always operates in scalar mode -// OP_SD - The instruction exceptionally writes to a single precision result. -// OP_DD - The instruction exceptionally writes to a double precision result. -// OP_SM - The instruction exceptionally reads from a single precision operand. -enum : u32 { OP_SCALAR = (1 << 0), OP_SD = (1 << 1), OP_DD = (1 << 1), OP_SM = (1 << 2) }; - -struct op { - u32 (*const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr); - u32 flags; -}; - -inline u32 fls(u32 x) { - int r = 32; - - if (!x) - return 0; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; -} - -u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); -u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); -u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions, - 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 @@ -/* - vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * This code is derived in part from : - * - Android kernel - * - John R. Housers softfloat library, which - * carries the following notice: - * - * =========================================================================== - * This C source file is part of the SoftFloat IEC/IEEE Floating-point - * Arithmetic Package, Release 2. - * - * Written by John R. Hauser. This work was made possible in part by the - * International Computer Science Institute, located at Suite 600, 1947 Center - * Street, Berkeley, California 94704. Funding was partially provided by the - * National Science Foundation under grant MIP-9311980. The original version - * of this code was written as part of a project to build a fixed-point vector - * processor in collaboration with the University of California at Berkeley, - * overseen by Profs. Nelson Morgan and John Wawrzynek. More information - * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ - * arithmetic/softfloat.html'. - * - * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort - * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT - * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO - * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY - * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - * - * Derivative works are acceptable, even for commercial purposes, so long as - * (1) they include prominent notice that the work is derivative, and (2) they - * include prominent notice akin to these three paragraphs for those parts of - * this code that are retained. - * =========================================================================== - */ - -#include -#include "common/logging/log.h" -#include "core/arm/skyeye_common/vfp/asm_vfp.h" -#include "core/arm/skyeye_common/vfp/vfp.h" -#include "core/arm/skyeye_common/vfp/vfp_helper.h" - -static struct vfp_double vfp_double_default_qnan = { - 2047, 0, VFP_DOUBLE_SIGNIFICAND_QNAN, -}; - -static void vfp_double_dump(const char* str, struct vfp_double* d) { - LOG_TRACE(Core_ARM, "VFP: %s: sign=%d exponent=%d significand=%016llx", str, d->sign != 0, - d->exponent, d->significand); -} - -static void vfp_double_normalise_denormal(struct vfp_double* vd) { - int bits = 31 - fls((u32)(vd->significand >> 32)); - if (bits == 31) - bits = 63 - fls((u32)vd->significand); - - vfp_double_dump("normalise_denormal: in", vd); - - if (bits) { - vd->exponent -= bits - 1; - vd->significand <<= bits; - } - - vfp_double_dump("normalise_denormal: out", vd); -} - -u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double* vd, u32 fpscr, - u32 exceptions, const char* func) { - u64 significand, incr; - int exponent, shift, underflow; - u32 rmode; - - vfp_double_dump("pack: in", vd); - - /* - * Infinities and NaNs are a special case. - */ - if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vd->significand == 0) { - vd->exponent = 0; - goto pack; - } - - exponent = vd->exponent; - significand = vd->significand; - - shift = 32 - fls((u32)(significand >> 32)); - if (shift == 32) - shift = 64 - fls((u32)significand); - if (shift) { - exponent -= shift; - significand <<= shift; - } - -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: normalised", vd); -#endif - - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright64jamming(significand, -exponent); - exponent = 0; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: tiny number", vd); -#endif - if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) - underflow = 0; - - int type = vfp_double_type(vd); - - if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) { - // Flush denormal to positive 0 - significand = 0; - - vd->sign = 0; - vd->significand = significand; - - underflow = 0; - exceptions |= FPSCR_UFC; - } - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1ULL << VFP_DOUBLE_LOW_BITS; - if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) - incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; - - LOG_TRACE(Core_ARM, "VFP: rounding increment = 0x%08llx", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: overflow", vd); -#endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 2046) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vd->exponent = 2045; - vd->significand = 0x7fffffffffffffffULL; - } else { - vd->exponent = 2047; /* infinity */ - vd->significand = 0; - } - } else { - if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x8000000000000000ULL) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vd->exponent = exponent; - vd->significand = significand >> 1; - } - -pack: - vfp_double_dump("pack: final", vd); - { - s64 d = vfp_double_pack(vd); - LOG_TRACE(Core_ARM, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, dd, d, exceptions); - vfp_put_double(state, d, dd); - } - return exceptions; -} - -/* - * Propagate the NaN, setting exceptions if it is signalling. - * 'n' is always a NaN. 'm' may be a number, NaN or infinity. - */ -static u32 vfp_propagate_nan(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, - u32 fpscr) { - struct vfp_double* nan; - int tn, tm = 0; - - tn = vfp_double_type(vdn); - - if (vdm) - tm = vfp_double_type(vdm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_double_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vdn; - else - nan = vdm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - } - - *vdd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; -} - -/* - * Extended operations - */ -static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); - return 0; -} - -static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vfp_put_double(state, vfp_get_double(state, dm), dd); - return 0; -} - -static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); - return 0; -} - -static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vfp_double vdm, vdd, *vdp; - int ret, tm; - u32 exceptions = 0; - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - - tm = vfp_double_type(&vdm); - if (tm & (VFP_NAN | VFP_INFINITY)) { - vdp = &vdd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vdp, &vdm, nullptr, fpscr); - else if (vdm.sign == 0) { - sqrt_copy: - vdp = &vdm; - ret = 0; - } else { - sqrt_invalid: - vdp = &vfp_double_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_double(state, vfp_double_pack(vdp), dd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * sqrt(<0) = invalid - */ - if (vdm.sign) - goto sqrt_invalid; - - vfp_double_dump("sqrt", &vdm); - - /* - * Estimate the square root. - */ - vdd.sign = 0; - vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; - vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; - - vfp_double_dump("sqrt estimate1", &vdd); - - vdm.significand >>= 1 + (vdm.exponent & 1); - vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); - - vfp_double_dump("sqrt estimate2", &vdd); - - /* - * And now adjust. - */ - if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { - if (vdd.significand < 2) { - vdd.significand = ~0ULL; - } else { - u64 termh, terml, remh, reml; - vdm.significand <<= 2; - mul64to128(&termh, &terml, vdd.significand, vdd.significand); - sub128(&remh, &reml, vdm.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - shift64left(&termh, &terml, vdd.significand); - terml |= 1; - add128(&remh, &reml, remh, reml, termh, terml); - } - vdd.significand |= (remh | reml) != 0; - } - } - vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); - - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); - - return exceptions; -} - -/* - * Equal := ZC - * Less than := N - * Greater than := C - * Unordered := CV - */ -static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) { - s64 d, m; - u32 ret = 0; - - LOG_TRACE(Core_ARM, "In %s, state=0x%p, fpscr=0x%x", __FUNCTION__, state, fpscr); - m = vfp_get_double(state, dm); - if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { - ret |= FPSCR_CFLAG | FPSCR_VFLAG; - if (signal_on_qnan || - !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - d = vfp_get_double(state, dd); - if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { - ret |= FPSCR_CFLAG | FPSCR_VFLAG; - if (signal_on_qnan || - !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - // printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); - if (d == m || vfp_double_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_ZFLAG | FPSCR_CFLAG; - // printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); - } else if (vfp_double_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_double_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_NFLAG; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_CFLAG; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_NFLAG; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_CFLAG; - } - } - LOG_TRACE(Core_ARM, "In %s, state=0x%p, ret=0x%x", __FUNCTION__, state, ret); - - return ret; -} - -static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_compare(state, dd, 0, dm, fpscr); -} - -static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_compare(state, dd, 1, dm, fpscr); -} - -static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); -} - -static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); -} - -static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - struct vfp_single vsd; - int tm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - - tm = vfp_double_type(&vdm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - vsd.sign = vdm.sign; - vsd.significand = vfp_hi64to32jamming(vdm.significand); - - /* - * If we have an infinity or a NaN, the exponent must be 255 - */ - if (tm & (VFP_INFINITY | VFP_NAN)) { - vsd.exponent = 255; - if (tm == VFP_QNAN) - vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vsd.exponent = 0; - else - vsd.exponent = vdm.exponent - (1023 - 127); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); - -pack_nan: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; -} - -static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vdm.sign = 0; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = (u64)m; - - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); -} - -static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vdm.sign = (m & 0x80000000) >> 16; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = vdm.sign ? (~m + 1) : m; - - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); -} - -static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - - /* - * Do we have a denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vdm.sign = 1; - - if (vdm.exponent >= 1023 + 32) { - d = vdm.sign ? 0 : 0xffffffff; - exceptions = FPSCR_IOC; - } else if (vdm.exponent >= 1023) { - int shift = 1023 + 63 - vdm.exponent; - u64 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (u32)((vdm.significand << 1) >> shift); - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vdm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - if (rmode == FPSCR_ROUND_NEAREST) { - if (vdm.exponent >= 1022) { - d = vdm.sign ? 0 : 1; - exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC; - } else { - exceptions |= FPSCR_IXC; - } - } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) { - d = 1; - exceptions |= FPSCR_IXC; - } else if (rmode == FPSCR_ROUND_MINUSINF) { - exceptions |= vdm.sign ? FPSCR_IOC : FPSCR_IXC; - } else { - exceptions |= FPSCR_IXC; - } - } - } - - LOG_TRACE(Core_ARM, "VFP: ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; -} - -static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_ftoui(state, sd, unused, dm, - (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); -} - -static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - vfp_double_dump("VDM", &vdm); - - /* - * Do we have denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023 + 31) { - d = 0x7fffffff; - if (vdm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023) { - int shift = 1023 + 63 - vdm.exponent; /* 58 */ - u64 rem, incr = 0; - - d = (u32)((vdm.significand << 1) >> shift); - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > (0x7fffffffU + (vdm.sign != 0))) { - d = (0x7fffffffU + (vdm.sign != 0)); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vdm.sign) - d = (~d + 1); - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_NEAREST) { - if (vdm.exponent >= 1022) { - d = vdm.sign ? 0xffffffff : 1; - } else { - d = 0; - } - } else if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) { - d = 1; - } else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { - d = 0xffffffff; - } - } - } - - LOG_TRACE(Core_ARM, "VFP: ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; -} - -static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_ftosi(state, dd, unused, dm, - (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); -} - -static struct op fops_ext[] = { - {vfp_double_fcpy, 0}, // 0x00000000 - FEXT_FCPY - {vfp_double_fabs, 0}, // 0x00000001 - FEXT_FABS - {vfp_double_fneg, 0}, // 0x00000002 - FEXT_FNEG - {vfp_double_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_double_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP - {vfp_double_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE - {vfp_double_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ - {vfp_double_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_double_fcvts, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT - {vfp_double_fuito, OP_SCALAR | OP_SM}, // 0x00000010 - FEXT_FUITO - {vfp_double_fsito, OP_SCALAR | OP_SM}, // 0x00000011 - FEXT_FSITO - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_double_ftoui, OP_SCALAR | OP_SD}, // 0x00000018 - FEXT_FTOUI - {vfp_double_ftouiz, OP_SCALAR | OP_SD}, // 0x00000019 - FEXT_FTOUIZ - {vfp_double_ftosi, OP_SCALAR | OP_SD}, // 0x0000001A - FEXT_FTOSI - {vfp_double_ftosiz, OP_SCALAR | OP_SD}, // 0x0000001B - FEXT_FTOSIZ -}; - -static u32 vfp_double_fadd_nonnumber(struct vfp_double* vdd, struct vfp_double* vdn, - struct vfp_double* vdm, u32 fpscr) { - struct vfp_double* vdp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_double_type(vdn); - tm = vfp_double_type(vdm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vdn->sign ^ vdm->sign) { - /* - * different signs -> invalid - */ - exceptions = FPSCR_IOC; - vdp = &vfp_double_default_qnan; - } else { - /* - * same signs -> valid - */ - vdp = vdn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vdp = vdn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - } - *vdd = *vdp; - return exceptions; -} - -u32 vfp_double_add(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, - u32 fpscr) { - u32 exp_diff; - u64 m_sig; - - if (vdn->significand & (1ULL << 63) || vdm->significand & (1ULL << 63)) { - LOG_INFO(Core_ARM, "VFP: bad FP values in %s", __func__); - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - std::swap(vdm, vdn); - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vdn->exponent == 2047) - return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); - - /* - * We have two proper numbers, where 'vdn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vdd = *vdn; - - /* - * Align 'm' with the result. - */ - exp_diff = vdn->exponent - vdm->exponent; - m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vdn->sign ^ vdm->sign) { - m_sig = vdn->significand - m_sig; - if ((s64)m_sig < 0) { - vdd->sign = vfp_sign_negate(vdd->sign); - m_sig = (~m_sig + 1); - } else if (m_sig == 0) { - vdd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig += vdn->significand; - } - vdd->significand = m_sig; - - return 0; -} - -u32 vfp_double_multiply(struct vfp_double* vdd, struct vfp_double* vdn, struct vfp_double* vdm, - u32 fpscr) { - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - std::swap(vdm, vdn); - LOG_TRACE(Core_ARM, "VFP: swapping M <-> N"); - } - - vdd->sign = vdn->sign ^ vdm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vdn->exponent == 2047) { - if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - if ((vdm->exponent | vdm->significand) == 0) { - *vdd = vfp_double_default_qnan; - return FPSCR_IOC; - } - vdd->exponent = vdn->exponent; - vdd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vdm->exponent | vdm->significand) == 0) { - vdd->exponent = 0; - vdd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason - * as the addition case - though this time we have +1 from - * each input operand. - */ - vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; - vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); - - vfp_double_dump("VDD", vdd); - return 0; -} - -#define NEG_MULTIPLY (1 << 0) -#define NEG_SUBTRACT (1 << 1) - -static u32 vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, - u32 negate, const char* func) { - struct vfp_double vdd, vdp, vdn, vdm; - u32 exceptions = 0; - - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions |= vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); - if (negate & NEG_MULTIPLY) - vdp.sign = vfp_sign_negate(vdp.sign); - - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dd), fpscr); - if (vdn.exponent == 0 && vdn.significand != 0) - vfp_double_normalise_denormal(&vdn); - - if (negate & NEG_SUBTRACT) - vdn.sign = vfp_sign_negate(vdn.sign); - - exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); -} - -/* - * Standard operations - */ - -/* - * sd = sd + (sn * sm) - */ -static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); -} - -/* - * sd = sd - (sn * sm) - */ -static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); -} - -/* - * sd = -sd + (sn * sm) - */ -static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); -} - -/* - * sd = -sd - (sn * sm) - */ -static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, - "fnmsc"); -} - -/* - * sd = sn * sm - */ -static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); -} - -/* - * sd = -(sn * sm) - */ -static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - vdd.sign = vfp_sign_negate(vdd.sign); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); -} - -/* - * sd = sn + sm - */ -static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); -} - -/* - * sd = sn - sm - */ -static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - /* - * Subtraction is like addition, but with a negated operand. - */ - vdm.sign = vfp_sign_negate(vdm.sign); - - exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); -} - -/* - * sd = sn / sm - */ -static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) { - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - int tm, tn; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - exceptions |= vfp_double_unpack(&vdn, vfp_get_double(state, dn), fpscr); - exceptions |= vfp_double_unpack(&vdm, vfp_get_double(state, dm), fpscr); - - vdd.sign = vdn.sign ^ vdm.sign; - - tn = vfp_double_type(&vdn); - tm = vfp_double_type(&vdm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vdn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vdm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY | VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exceptions - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdn); - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; - vdm.significand <<= 1; - if (vdm.significand <= (2 * vdn.significand)) { - vdn.significand >>= 1; - vdd.exponent++; - } - vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); - if ((vdd.significand & 0x1ff) <= 2) { - u64 termh, terml, remh, reml; - mul64to128(&termh, &terml, vdm.significand, vdd.significand); - sub128(&remh, &reml, vdn.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - add128(&remh, &reml, remh, reml, 0, vdm.significand); - } - vdd.significand |= (reml != 0); - } - return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); - -vdn_nan: - exceptions |= vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); -pack: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; - -vdm_nan: - exceptions |= vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); - goto pack; - -zero: - vdd.exponent = 0; - vdd.significand = 0; - goto pack; - -divzero: - exceptions |= FPSCR_DZC; -infinity: - vdd.exponent = 2047; - vdd.significand = 0; - goto pack; - -invalid: - vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); - return FPSCR_IOC; -} - -static struct op fops[] = { - {vfp_double_fmac, 0}, {vfp_double_fmsc, 0}, {vfp_double_fmul, 0}, - {vfp_double_fadd, 0}, {vfp_double_fnmac, 0}, {vfp_double_fnmsc, 0}, - {vfp_double_fnmul, 0}, {vfp_double_fsub, 0}, {vfp_double_fdiv, 0}, -}; - -#define FREG_BANK(x) ((x)&0x0c) -#define FREG_IDX(x) ((x)&3) - -u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int dn = vfp_get_dn(inst); - unsigned int dm; - unsigned int vecitr, veclen, vecstride; - struct op* fop; - - LOG_TRACE(Core_ARM, "In %s", __FUNCTION__); - vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtds takes an sN register number as destination, not dN. - * It also always operates on scalars. - */ - if (fop->flags & OP_SD) - dest = vfp_get_sd(inst); - else - dest = vfp_get_dd(inst); - - /* - * f[us]ito takes a sN operand, not a dN operand. - */ - if (fop->flags & OP_SM) - dm = vfp_get_sm(inst); - else - dm = vfp_get_dm(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - LOG_TRACE(Core_ARM, "VFP: vecstride=%u veclen=%u", vecstride, - (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - u32 except; - char type; - - type = (fop->flags & OP_SD) ? 's' : 'd'; - if (op == FOP_EXT) - LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = op[%u] (d%u)", vecitr >> FPSCR_LENGTH_BIT, - type, dest, dn, dm); - else - LOG_TRACE(Core_ARM, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)", - vecitr >> FPSCR_LENGTH_BIT, type, dest, dn, FOP_TO_IDX(op), dm); - - except = fop->fn(state, dest, dn, dm, fpscr); - LOG_TRACE(Core_ARM, "VFP: itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except & ~VFP_NAN_FLAG; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); - dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); - if (FREG_BANK(dm) != 0) - dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); - } - return exceptions; - -invalid: - return ~0; -} 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 @@ -// Copyright 2012 Michael Kang, 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -/* Notice: this file should not be compiled as is, and is meant to be - included in other files only. */ - -/* ----------------------------------------------------------------------- */ -/* CDP instructions */ -/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ - -/* ----------------------------------------------------------------------- */ -/* VMLA */ -/* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmla_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmla_inst)); - vmla_inst* inst_cream = (vmla_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMLA_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmla_inst* inst_cream = (vmla_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmla_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VNMLS */ -/* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmls_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmls_inst)); - vmls_inst* inst_cream = (vmls_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMLS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmls_inst* inst_cream = (vmls_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmls_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VNMLA */ -/* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vnmla_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmla_inst)); - vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VNMLA_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vnmla_inst* inst_cream = (vnmla_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vnmla_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VNMLS */ -/* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */ - -#ifdef VFP_INTERPRETER_STRUCT -struct vnmls_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmls_inst)); - vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VNMLS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vnmls_inst* inst_cream = (vnmls_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vnmls_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VNMUL */ -/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vnmul_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vnmul_inst)); - vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VNMUL_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vnmul_inst* inst_cream = (vnmul_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vnmul_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMUL */ -/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmul_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmul_inst)); - vmul_inst* inst_cream = (vmul_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMUL_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmul_inst* inst_cream = (vmul_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmul_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VADD */ -/* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vadd_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vadd_inst)); - vadd_inst* inst_cream = (vadd_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VADD_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vadd_inst* inst_cream = (vadd_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vadd_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VSUB */ -/* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vsub_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsub_inst)); - vsub_inst* inst_cream = (vsub_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VSUB_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vsub_inst* inst_cream = (vsub_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vsub_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VDIV */ -/* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vdiv_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vdiv_inst)); - vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VDIV_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vdiv_inst* inst_cream = (vdiv_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vdiv_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMOVI move immediate */ -/* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */ -/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovi_inst { - unsigned int single; - unsigned int d; - unsigned int imm; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovi_inst)); - vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - unsigned int imm8 = BITS(inst, 16, 19) << 4 | BITS(inst, 0, 3); - if (inst_cream->single) - inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 | - (BIT(imm8, 6) ? 0x1f : 0) << 25 | BITS(imm8, 0, 5) << 19; - else - inst_cream->imm = BIT(imm8, 7) << 31 | (BIT(imm8, 6) == 0) << 30 | - (BIT(imm8, 6) ? 0xff : 0) << 22 | BITS(imm8, 0, 5) << 16; - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVI_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovi_inst* inst_cream = (vmovi_inst*)inst_base->component; - - VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovi_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMOVR move register */ -/* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */ -/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovr_inst { - unsigned int single; - unsigned int d; - unsigned int m; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovr_inst)); - vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->m = (inst_cream->single ? BITS(inst, 0, 3) << 1 | BIT(inst, 5) - : BITS(inst, 0, 3) | BIT(inst, 5) << 4); - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVR_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovr_inst* inst_cream = (vmovr_inst*)inst_base->component; - - VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovr_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VABS */ -/* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -typedef struct _vabs_inst { - unsigned int instr; - unsigned int dp_operation; -} vabs_inst; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vabs_inst)); - vabs_inst* inst_cream = (vabs_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VABS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vabs_inst* inst_cream = (vabs_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vabs_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VNEG */ -/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ - -#ifdef VFP_INTERPRETER_STRUCT -struct vneg_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vneg_inst)); - vneg_inst* inst_cream = (vneg_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VNEG_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vneg_inst* inst_cream = (vneg_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vneg_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VSQRT */ -/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vsqrt_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vsqrt_inst)); - vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VSQRT_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vsqrt_inst* inst_cream = (vsqrt_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vsqrt_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VCMP VCMPE */ -/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vcmp_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp_inst)); - vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VCMP_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vcmp_inst* inst_cream = (vcmp_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vcmp_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VCMP VCMPE */ -/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vcmp2_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp2_inst)); - vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VCMP2_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vcmp2_inst* inst_cream = (vcmp2_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vcmp2_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VCVTBDS between double and single */ -/* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vcvtbds_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbds_inst)); - vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VCVTBDS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vcvtbds_inst* inst_cream = (vcvtbds_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vcvtbds_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VCVTBFF between floating point and fixed point */ -/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vcvtbff_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index) { - VFP_DEBUG_UNTESTED(VCVTBFF); - - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbff_inst)); - vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VCVTBFF_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vcvtbff_inst* inst_cream = (vcvtbff_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vcvtbff_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VCVTBFI between floating point and integer */ -/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ -#ifdef VFP_INTERPRETER_STRUCT -struct vcvtbfi_inst { - unsigned int instr; - unsigned int dp_operation; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbfi_inst)); - vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->dp_operation = BIT(inst, 8); - inst_cream->instr = inst; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VCVTBFI_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vcvtbfi_inst* inst_cream = (vcvtbfi_inst*)inst_base->component; - - int ret; - - if (inst_cream->dp_operation) - ret = vfp_double_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - else - ret = vfp_single_cpdo(cpu, inst_cream->instr, cpu->VFP[VFP_FPSCR]); - - CHECK_VFP_CDP_RET; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vcvtbfi_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* MRC / MCR instructions */ -/* cond 1110 AAAL XXXX XXXX 101C XBB1 XXXX */ -/* cond 1110 op11 CRn- Rt-- copr op21 CRm- */ - -/* ----------------------------------------------------------------------- */ -/* VMOVBRS between register and single precision */ -/* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */ -/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovbrs_inst { - unsigned int to_arm; - unsigned int t; - unsigned int n; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrs_inst)); - vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->to_arm = BIT(inst, 20) == 1; - inst_cream->t = BITS(inst, 12, 15); - inst_cream->n = BIT(inst, 7) | BITS(inst, 16, 19) << 1; - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVBRS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovbrs_inst* inst_cream = (vmovbrs_inst*)inst_base->component; - - VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovbrs_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMSR */ -/* cond 1110 1110 reg- Rt-- 1010 0001 0000 */ -/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmsr_inst { - unsigned int reg; - unsigned int Rt; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmsr_inst)); - vmsr_inst* inst_cream = (vmsr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->reg = BITS(inst, 16, 19); - inst_cream->Rt = BITS(inst, 12, 15); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMSR_INST : { - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , - and in privileged mode */ - /* Exceptions must be checked, according to v7 ref manual */ - CHECK_VFP_ENABLED; - - vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component; - - unsigned int reg = inst_cream->reg; - unsigned int rt = inst_cream->Rt; - - if (reg == 1) { - cpu->VFP[VFP_FPSCR] = cpu->Reg[rt]; - } else if (cpu->InAPrivilegedMode()) { - if (reg == 8) - cpu->VFP[VFP_FPEXC] = cpu->Reg[rt]; - else if (reg == 9) - cpu->VFP[VFP_FPINST] = cpu->Reg[rt]; - else if (reg == 10) - cpu->VFP[VFP_FPINST2] = cpu->Reg[rt]; - } - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmsr_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMOVBRC register to scalar */ -/* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */ -/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovbrc_inst { - unsigned int esize; - unsigned int index; - unsigned int d; - unsigned int t; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrc_inst)); - vmovbrc_inst* inst_cream = (vmovbrc_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4; - inst_cream->t = BITS(inst, 12, 15); - /* VFP variant of instruction */ - inst_cream->esize = 32; - inst_cream->index = BIT(inst, 21); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVBRC_INST : { - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component; - - cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovbrc_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMRS */ -/* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */ -/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmrs_inst { - unsigned int reg; - unsigned int Rt; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmrs_inst)); - vmrs_inst* inst_cream = (vmrs_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->reg = BITS(inst, 16, 19); - inst_cream->Rt = BITS(inst, 12, 15); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMRS_INST : { - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, - and in privileged mode */ - /* Exceptions must be checked, according to v7 ref manual */ - CHECK_VFP_ENABLED; - - vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component; - - unsigned int reg = inst_cream->reg; - unsigned int rt = inst_cream->Rt; - - if (reg == 1) // FPSCR - { - if (rt != 15) { - cpu->Reg[rt] = cpu->VFP[VFP_FPSCR]; - } else { - cpu->NFlag = (cpu->VFP[VFP_FPSCR] >> 31) & 1; - cpu->ZFlag = (cpu->VFP[VFP_FPSCR] >> 30) & 1; - cpu->CFlag = (cpu->VFP[VFP_FPSCR] >> 29) & 1; - cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; - } - } else if (reg == 0) { - cpu->Reg[rt] = cpu->VFP[VFP_FPSID]; - } else if (reg == 6) { - cpu->Reg[rt] = cpu->VFP[VFP_MVFR1]; - } else if (reg == 7) { - cpu->Reg[rt] = cpu->VFP[VFP_MVFR0]; - } else if (cpu->InAPrivilegedMode()) { - if (reg == 8) - cpu->Reg[rt] = cpu->VFP[VFP_FPEXC]; - else if (reg == 9) - cpu->Reg[rt] = cpu->VFP[VFP_FPINST]; - else if (reg == 10) - cpu->Reg[rt] = cpu->VFP[VFP_FPINST2]; - } - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmrs_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMOVBCR scalar to register */ -/* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */ -/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovbcr_inst { - unsigned int esize; - unsigned int index; - unsigned int d; - unsigned int t; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbcr_inst)); - vmovbcr_inst* inst_cream = (vmovbcr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->d = BITS(inst, 16, 19) | BIT(inst, 7) << 4; - inst_cream->t = BITS(inst, 12, 15); - /* VFP variant of instruction */ - inst_cream->esize = 32; - inst_cream->index = BIT(inst, 21); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVBCR_INST : { - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovbcr_inst* const inst_cream = (vmovbcr_inst*)inst_base->component; - - cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovbcr_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* MRRC / MCRR instructions */ -/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ -/* cond 1100 0100 Rt2- Rt-- copr opc1 CRm- MCRR */ - -/* ----------------------------------------------------------------------- */ -/* VMOVBRRSS between 2 registers to 2 singles */ -/* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */ -/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovbrrss_inst { - unsigned int to_arm; - unsigned int t; - unsigned int t2; - unsigned int m; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrss_inst)); - vmovbrrss_inst* inst_cream = (vmovbrrss_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->to_arm = BIT(inst, 20) == 1; - inst_cream->t = BITS(inst, 12, 15); - inst_cream->t2 = BITS(inst, 16, 19); - inst_cream->m = BITS(inst, 0, 3) << 1 | BIT(inst, 5); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVBRRSS_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovbrrss_inst* const inst_cream = (vmovbrrss_inst*)inst_base->component; - - VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, - &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovbrrss_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VMOVBRRD between 2 registers and 1 double */ -/* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */ -/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ -#ifdef VFP_INTERPRETER_STRUCT -struct vmovbrrd_inst { - unsigned int to_arm; - unsigned int t; - unsigned int t2; - unsigned int m; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrd_inst)); - vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->to_arm = BIT(inst, 20) == 1; - inst_cream->t = BITS(inst, 12, 15); - inst_cream->t2 = BITS(inst, 16, 19); - inst_cream->m = BIT(inst, 5) << 4 | BITS(inst, 0, 3); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VMOVBRRD_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vmovbrrd_inst* inst_cream = (vmovbrrd_inst*)inst_base->component; - - VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, - &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vmovbrrd_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* LDC/STC between 2 registers and 1 double */ -/* cond 110X XXX1 Rn-- CRd- copr imm- imm- LDC */ -/* cond 110X XXX0 Rn-- CRd- copr imm8 imm8 STC */ - -/* ----------------------------------------------------------------------- */ -/* VSTR */ -/* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vstr_inst { - unsigned int single; - unsigned int n; - unsigned int d; - unsigned int imm32; - unsigned int add; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstr_inst)); - vstr_inst* inst_cream = (vstr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->add = BIT(inst, 23); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->n = BITS(inst, 16, 19); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VSTR_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vstr_inst* inst_cream = (vstr_inst*)inst_base->component; - - unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 - : cpu->Reg[inst_cream->n]); - addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); - - if (inst_cream->single) { - cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]); - } else { - const u32 word1 = cpu->ExtReg[inst_cream->d * 2 + 0]; - const u32 word2 = cpu->ExtReg[inst_cream->d * 2 + 1]; - - if (cpu->InBigEndianMode()) { - cpu->WriteMemory32(addr + 0, word2); - cpu->WriteMemory32(addr + 4, word1); - } else { - cpu->WriteMemory32(addr + 0, word1); - cpu->WriteMemory32(addr + 4, word2); - } - } - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vstr_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VPUSH */ -/* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vpush_inst { - unsigned int single; - unsigned int d; - unsigned int imm32; - unsigned int regs; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpush_inst)); - vpush_inst* inst_cream = (vpush_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VPUSH_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vpush_inst* inst_cream = (vpush_inst*)inst_base->component; - - addr = cpu->Reg[R13] - inst_cream->imm32; - - for (unsigned int i = 0; i < inst_cream->regs; i++) { - if (inst_cream->single) { - cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d + i]); - addr += 4; - } else { - const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0]; - const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1]; - - if (cpu->InBigEndianMode()) { - cpu->WriteMemory32(addr + 0, word2); - cpu->WriteMemory32(addr + 4, word1); - } else { - cpu->WriteMemory32(addr + 0, word1); - cpu->WriteMemory32(addr + 4, word2); - } - - addr += 8; - } - } - - cpu->Reg[R13] -= inst_cream->imm32; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vpush_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VSTM */ -/* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vstm_inst { - unsigned int single; - unsigned int add; - unsigned int wback; - unsigned int d; - unsigned int n; - unsigned int imm32; - unsigned int regs; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vstm_inst)); - vstm_inst* inst_cream = (vstm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->add = BIT(inst, 23); - inst_cream->wback = BIT(inst, 21); - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->n = BITS(inst, 16, 19); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VSTM_INST : /* encoding 1 */ -{ - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vstm_inst* inst_cream = (vstm_inst*)inst_base->component; - - u32 address = cpu->Reg[inst_cream->n]; - - // Only possible in ARM mode, where PC accesses have an 8 byte offset. - if (inst_cream->n == 15) - address += 8; - - if (inst_cream->add == 0) - address -= inst_cream->imm32; - - for (unsigned int i = 0; i < inst_cream->regs; i++) { - if (inst_cream->single) { - cpu->WriteMemory32(address, cpu->ExtReg[inst_cream->d + i]); - address += 4; - } else { - const u32 word1 = cpu->ExtReg[(inst_cream->d + i) * 2 + 0]; - const u32 word2 = cpu->ExtReg[(inst_cream->d + i) * 2 + 1]; - - if (cpu->InBigEndianMode()) { - cpu->WriteMemory32(address + 0, word2); - cpu->WriteMemory32(address + 4, word1); - } else { - cpu->WriteMemory32(address + 0, word1); - cpu->WriteMemory32(address + 4, word2); - } - - address += 8; - } - } - if (inst_cream->wback) { - cpu->Reg[inst_cream->n] = - (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 - : cpu->Reg[inst_cream->n] - inst_cream->imm32); - } - } - cpu->Reg[15] += 4; - INC_PC(sizeof(vstm_inst)); - - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VPOP */ -/* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vpop_inst { - unsigned int single; - unsigned int d; - unsigned int imm32; - unsigned int regs; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vpop_inst)); - vpop_inst* inst_cream = (vpop_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->d = (inst_cream->single ? (BITS(inst, 12, 15) << 1) | BIT(inst, 22) - : BITS(inst, 12, 15) | (BIT(inst, 22) << 4)); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VPOP_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vpop_inst* inst_cream = (vpop_inst*)inst_base->component; - - addr = cpu->Reg[R13]; - - for (unsigned int i = 0; i < inst_cream->regs; i++) { - if (inst_cream->single) { - cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(addr); - addr += 4; - } else { - const u32 word1 = cpu->ReadMemory32(addr + 0); - const u32 word2 = cpu->ReadMemory32(addr + 4); - - if (cpu->InBigEndianMode()) { - cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2; - cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1; - } else { - cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1; - cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2; - } - - addr += 8; - } - } - cpu->Reg[R13] += inst_cream->imm32; - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vpop_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VLDR */ -/* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vldr_inst { - unsigned int single; - unsigned int n; - unsigned int d; - unsigned int imm32; - unsigned int add; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldr_inst)); - vldr_inst* inst_cream = (vldr_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->add = BIT(inst, 23); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->n = BITS(inst, 16, 19); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VLDR_INST : { - if ((inst_base->cond == ConditionCode::AL) || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vldr_inst* inst_cream = (vldr_inst*)inst_base->component; - - unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 - : cpu->Reg[inst_cream->n]); - addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); - - if (inst_cream->single) { - cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr); - } else { - const u32 word1 = cpu->ReadMemory32(addr + 0); - const u32 word2 = cpu->ReadMemory32(addr + 4); - - if (cpu->InBigEndianMode()) { - cpu->ExtReg[inst_cream->d * 2 + 0] = word2; - cpu->ExtReg[inst_cream->d * 2 + 1] = word1; - } else { - cpu->ExtReg[inst_cream->d * 2 + 0] = word1; - cpu->ExtReg[inst_cream->d * 2 + 1] = word2; - } - } - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vldr_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#endif - -/* ----------------------------------------------------------------------- */ -/* VLDM */ -/* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */ -#ifdef VFP_INTERPRETER_STRUCT -struct vldm_inst { - unsigned int single; - unsigned int add; - unsigned int wback; - unsigned int d; - unsigned int n; - unsigned int imm32; - unsigned int regs; -}; -#endif -#ifdef VFP_INTERPRETER_TRANS -static ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index) { - arm_inst* inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(vldm_inst)); - vldm_inst* inst_cream = (vldm_inst*)inst_base->component; - - inst_base->cond = BITS(inst, 28, 31); - inst_base->idx = index; - inst_base->br = TransExtData::NON_BRANCH; - - inst_cream->single = BIT(inst, 8) == 0; - inst_cream->add = BIT(inst, 23); - inst_cream->wback = BIT(inst, 21); - inst_cream->d = (inst_cream->single ? BITS(inst, 12, 15) << 1 | BIT(inst, 22) - : BITS(inst, 12, 15) | BIT(inst, 22) << 4); - inst_cream->n = BITS(inst, 16, 19); - inst_cream->imm32 = BITS(inst, 0, 7) << 2; - inst_cream->regs = (inst_cream->single ? BITS(inst, 0, 7) : BITS(inst, 1, 7)); - - return inst_base; -} -#endif -#ifdef VFP_INTERPRETER_IMPL -VLDM_INST : { - if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { - CHECK_VFP_ENABLED; - - vldm_inst* inst_cream = (vldm_inst*)inst_base->component; - - u32 address = cpu->Reg[inst_cream->n]; - - // Only possible in ARM mode, where PC accesses have an 8 byte offset. - if (inst_cream->n == 15) - address += 8; - - if (inst_cream->add == 0) - address -= inst_cream->imm32; - - for (unsigned int i = 0; i < inst_cream->regs; i++) { - if (inst_cream->single) { - cpu->ExtReg[inst_cream->d + i] = cpu->ReadMemory32(address); - address += 4; - } else { - const u32 word1 = cpu->ReadMemory32(address + 0); - const u32 word2 = cpu->ReadMemory32(address + 4); - - if (cpu->InBigEndianMode()) { - cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word2; - cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word1; - } else { - cpu->ExtReg[(inst_cream->d + i) * 2 + 0] = word1; - cpu->ExtReg[(inst_cream->d + i) * 2 + 1] = word2; - } - - address += 8; - } - } - if (inst_cream->wback) { - cpu->Reg[inst_cream->n] = - (inst_cream->add ? cpu->Reg[inst_cream->n] + inst_cream->imm32 - : cpu->Reg[inst_cream->n] - inst_cream->imm32); - } - } - cpu->Reg[15] += cpu->GetInstructionSize(); - INC_PC(sizeof(vldm_inst)); - FETCH_INST; - GOTO_NEXT_INST; -} -#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 @@ -/* - vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * This code is derived in part from : - * - Android kernel - * - John R. Housers softfloat library, which - * carries the following notice: - * - * =========================================================================== - * This C source file is part of the SoftFloat IEC/IEEE Floating-point - * Arithmetic Package, Release 2. - * - * Written by John R. Hauser. This work was made possible in part by the - * International Computer Science Institute, located at Suite 600, 1947 Center - * Street, Berkeley, California 94704. Funding was partially provided by the - * National Science Foundation under grant MIP-9311980. The original version - * of this code was written as part of a project to build a fixed-point vector - * processor in collaboration with the University of California at Berkeley, - * overseen by Profs. Nelson Morgan and John Wawrzynek. More information - * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ - * arithmetic/softfloat.html'. - * - * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort - * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT - * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO - * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY - * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - * - * Derivative works are acceptable, even for commercial purposes, so long as - * (1) they include prominent notice that the work is derivative, and (2) they - * include prominent notice akin to these three paragraphs for those parts of - * this code that are retained. - * =========================================================================== - */ - -#include -#include -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "core/arm/skyeye_common/vfp/asm_vfp.h" -#include "core/arm/skyeye_common/vfp/vfp.h" -#include "core/arm/skyeye_common/vfp/vfp_helper.h" - -static struct vfp_single vfp_single_default_qnan = { - 255, 0, VFP_SINGLE_SIGNIFICAND_QNAN, -}; - -static void vfp_single_dump(const char* str, struct vfp_single* s) { - LOG_TRACE(Core_ARM, "%s: sign=%d exponent=%d significand=%08x", str, s->sign != 0, - s->exponent, s->significand); -} - -static void vfp_single_normalise_denormal(struct vfp_single* vs) { - int bits = 31 - fls(vs->significand); - - vfp_single_dump("normalise_denormal: in", vs); - - if (bits) { - vs->exponent -= bits - 1; - vs->significand <<= bits; - } - - vfp_single_dump("normalise_denormal: out", vs); -} - -u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single* vs, u32 fpscr, - u32 exceptions, const char* func) { - u32 significand, incr, rmode; - int exponent, shift, underflow; - - vfp_single_dump("pack: in", vs); - - /* - * Infinities and NaNs are a special case. - */ - if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vs->significand == 0) { - vs->exponent = 0; - goto pack; - } - - exponent = vs->exponent; - significand = vs->significand; - - /* - * Normalise first. Note that we shift the significand up to - * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least - * significant bit. - */ - shift = 32 - fls(significand); - if (shift < 32 && shift) { - exponent -= shift; - significand <<= shift; - } - -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: normalised", vs); -#endif - - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright32jamming(significand, -exponent); - exponent = 0; -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: tiny number", vs); -#endif - if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) - underflow = 0; - - int type = vfp_single_type(vs); - - if ((type & VFP_DENORMAL) && (fpscr & FPSCR_FLUSH_TO_ZERO)) { - // Flush denormal to positive 0 - significand = 0; - - vs->sign = 0; - vs->significand = significand; - - underflow = 0; - exceptions |= FPSCR_UFC; - } - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1 << VFP_SINGLE_LOW_BITS; - if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) - incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; - - LOG_TRACE(Core_ARM, "rounding increment = 0x%08x", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: overflow", vs); -#endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 254) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vs->exponent = 253; - vs->significand = 0x7fffffff; - } else { - vs->exponent = 255; /* infinity */ - vs->significand = 0; - } - } else { - if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x80000000) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vs->exponent = exponent; - vs->significand = significand >> 1; - } - -pack: - vfp_single_dump("pack: final", vs); - { - s32 d = vfp_single_pack(vs); - LOG_TRACE(Core_ARM, "%s: d(s%d)=%08x exceptions=%08x", func, sd, d, exceptions); - vfp_put_float(state, d, sd); - } - - return exceptions; -} - -/* - * Propagate the NaN, setting exceptions if it is signalling. - * 'n' is always a NaN. 'm' may be a number, NaN or infinity. - */ -static u32 vfp_propagate_nan(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm, - u32 fpscr) { - struct vfp_single* nan; - int tn, tm = 0; - - tn = vfp_single_type(vsn); - - if (vsm) - tm = vfp_single_type(vsm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_single_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vsn; - else - nan = vsm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - } - - *vsd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; -} - -/* - * Extended operations - */ -static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, vfp_single_packed_abs(m), sd); - return 0; -} - -static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, m, sd); - return 0; -} - -static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - vfp_put_float(state, vfp_single_packed_negate(m), sd); - return 0; -} - -static const u16 sqrt_oddadjust[] = { - 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, - 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67, -}; - -static const u16 sqrt_evenadjust[] = { - 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, - 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002, -}; - -u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) { - int index; - u32 z, a; - - if ((significand & 0xc0000000) != 0x40000000) { - LOG_TRACE(Core_ARM, "invalid significand"); - } - - a = significand << 1; - index = (a >> 27) & 15; - if (exponent & 1) { - z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; - z = ((a / z) << 14) + (z << 15); - a >>= 1; - } else { - z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; - z = a / z + z; - z = (z >= 0x20000) ? 0xffff8000 : (z << 15); - if (z <= a) - return (s32)a >> 1; - } - { - u64 v = (u64)a << 31; - do_div(v, z); - return (u32)(v + (z >> 1)); - } -} - -static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm, vsd, *vsp; - int ret, tm; - u32 exceptions = 0; - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - tm = vfp_single_type(&vsm); - if (tm & (VFP_NAN | VFP_INFINITY)) { - vsp = &vsd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vsp, &vsm, nullptr, fpscr); - else if (vsm.sign == 0) { - sqrt_copy: - vsp = &vsm; - ret = 0; - } else { - sqrt_invalid: - vsp = &vfp_single_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_float(state, vfp_single_pack(vsp), sd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * sqrt(<0) = invalid - */ - if (vsm.sign) - goto sqrt_invalid; - - vfp_single_dump("sqrt", &vsm); - - /* - * Estimate the square root. - */ - vsd.sign = 0; - vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; - vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; - - vfp_single_dump("sqrt estimate", &vsd); - - /* - * And now adjust. - */ - if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { - if (vsd.significand < 2) { - vsd.significand = 0xffffffff; - } else { - u64 term; - s64 rem; - vsm.significand <<= static_cast((vsm.exponent & 1) == 0); - term = (u64)vsd.significand * vsd.significand; - rem = ((u64)vsm.significand << 32) - term; - - LOG_TRACE(Core_ARM, "term=%016" PRIx64 "rem=%016" PRIx64, term, rem); - - while (rem < 0) { - vsd.significand -= 1; - rem += ((u64)vsd.significand << 1) | 1; - } - vsd.significand |= rem != 0; - } - } - vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); - - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); - - return exceptions; -} - -/* - * Equal := ZC - * Less than := N - * Greater than := C - * Unordered := CV - */ -static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) { - s32 d; - u32 ret = 0; - - d = vfp_get_float(state, sd); - if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { - ret |= FPSCR_CFLAG | FPSCR_VFLAG; - if (signal_on_qnan || - !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { - ret |= FPSCR_CFLAG | FPSCR_VFLAG; - if (signal_on_qnan || - !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - if (d == m || vfp_single_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_ZFLAG | FPSCR_CFLAG; - } else if (vfp_single_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_single_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_NFLAG; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_CFLAG; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_NFLAG; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_CFLAG; - } - } - return ret; -} - -static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 0, m, fpscr); -} - -static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 1, m, fpscr); -} - -static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 0, 0, fpscr); -} - -static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_compare(state, sd, 1, 0, fpscr); -} - -static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - struct vfp_double vdd; - int tm; - u32 exceptions = 0; - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - - tm = vfp_single_type(&vsm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions |= FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - vdd.sign = vsm.sign; - vdd.significand = (u64)vsm.significand << 32; - - /* - * If we have an infinity or NaN, the exponent must be 2047. - */ - if (tm & (VFP_INFINITY | VFP_NAN)) { - vdd.exponent = 2047; - if (tm == VFP_QNAN) - vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vdd.exponent = 0; - else - vdd.exponent = vsm.exponent + (1023 - 127); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); - -pack_nan: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; -} - -static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vs; - - vs.sign = 0; - vs.exponent = 127 + 31 - 1; - vs.significand = (u32)m; - - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); -} - -static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vs; - - vs.sign = (m & 0x80000000) >> 16; - vs.exponent = 127 + 31 - 1; - vs.significand = vs.sign ? -m : m; - - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); -} - -static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vsm.sign = 1; - - if (vsm.exponent >= 127 + 32) { - d = vsm.sign ? 0 : 0xffffffff; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (vsm.significand << 1) >> shift; - if (shift > 0) { - rem = (vsm.significand << 1) << (32 - shift); - } else { - rem = 0; - } - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vsm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - if (rmode == FPSCR_ROUND_NEAREST) { - if (vsm.exponent >= 126) { - d = vsm.sign ? 0 : 1; - exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC; - } else { - exceptions |= FPSCR_IXC; - } - } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) { - d = 1; - exceptions |= FPSCR_IXC; - } else if (rmode == FPSCR_ROUND_MINUSINF) { - exceptions |= vsm.sign ? FPSCR_IOC : FPSCR_IXC; - } else { - exceptions |= FPSCR_IXC; - } - } - } - - LOG_TRACE(Core_ARM, "ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; -} - -static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_single_ftoui(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); -} - -static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (vfp_single_type(&vsm) & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127 + 31) { - /* - * m >= 2^31-2^7: invalid - */ - d = 0x7fffffff; - if (vsm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* 2^0 <= m <= 2^31-2^7 */ - d = (vsm.significand << 1) >> shift; - rem = (vsm.significand << 1) << (32 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > (0x7fffffffu + (vsm.sign != 0))) { - d = (0x7fffffffu + (vsm.sign != 0)); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vsm.sign) - d = (~d + 1); - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_NEAREST) { - if (vsm.exponent >= 126) - d = vsm.sign ? 0xffffffff : 1; - } else if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) { - d = 1; - } else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { - d = 0xffffffff; - } - } - } - - LOG_TRACE(Core_ARM, "ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; -} - -static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { - return vfp_single_ftosi(state, sd, unused, m, (fpscr & ~FPSCR_RMODE_MASK) | FPSCR_ROUND_TOZERO); -} - -static struct op fops_ext[] = { - {vfp_single_fcpy, 0}, // 0x00000000 - FEXT_FCPY - {vfp_single_fabs, 0}, // 0x00000001 - FEXT_FABS - {vfp_single_fneg, 0}, // 0x00000002 - FEXT_FNEG - {vfp_single_fsqrt, 0}, // 0x00000003 - FEXT_FSQRT - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_single_fcmp, OP_SCALAR}, // 0x00000008 - FEXT_FCMP - {vfp_single_fcmpe, OP_SCALAR}, // 0x00000009 - FEXT_FCMPE - {vfp_single_fcmpz, OP_SCALAR}, // 0x0000000A - FEXT_FCMPZ - {vfp_single_fcmpez, OP_SCALAR}, // 0x0000000B - FEXT_FCMPEZ - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_single_fcvtd, OP_SCALAR | OP_DD}, // 0x0000000F - FEXT_FCVT - {vfp_single_fuito, OP_SCALAR}, // 0x00000010 - FEXT_FUITO - {vfp_single_fsito, OP_SCALAR}, // 0x00000011 - FEXT_FSITO - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {nullptr, 0}, - {vfp_single_ftoui, OP_SCALAR}, // 0x00000018 - FEXT_FTOUI - {vfp_single_ftouiz, OP_SCALAR}, // 0x00000019 - FEXT_FTOUIZ - {vfp_single_ftosi, OP_SCALAR}, // 0x0000001A - FEXT_FTOSI - {vfp_single_ftosiz, OP_SCALAR}, // 0x0000001B - FEXT_FTOSIZ -}; - -static u32 vfp_single_fadd_nonnumber(struct vfp_single* vsd, struct vfp_single* vsn, - struct vfp_single* vsm, u32 fpscr) { - struct vfp_single* vsp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_single_type(vsn); - tm = vfp_single_type(vsm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vsn->sign ^ vsm->sign) { - /* - * different signs -> invalid - */ - exceptions |= FPSCR_IOC; - vsp = &vfp_single_default_qnan; - } else { - /* - * same signs -> valid - */ - vsp = vsn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vsp = vsn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - } - *vsd = *vsp; - return exceptions; -} - -static u32 vfp_single_add(struct vfp_single* vsd, struct vfp_single* vsn, struct vfp_single* vsm, - u32 fpscr) { - u32 exp_diff, m_sig; - - if (vsn->significand & 0x80000000 || vsm->significand & 0x80000000) { - LOG_WARNING(Core_ARM, "bad FP values"); - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - std::swap(vsm, vsn); - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vsn->exponent == 255) - return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); - - /* - * We have two proper numbers, where 'vsn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vsd = *vsn; - - /* - * Align both numbers. - */ - exp_diff = vsn->exponent - vsm->exponent; - m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vsn->sign ^ vsm->sign) { - m_sig = vsn->significand - m_sig; - if ((s32)m_sig < 0) { - vsd->sign = vfp_sign_negate(vsd->sign); - m_sig = (~m_sig + 1); - } else if (m_sig == 0) { - vsd->sign = (fpscr & FPSCR_RMODE_MASK) == FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig = vsn->significand + m_sig; - } - vsd->significand = m_sig; - - return 0; -} - -static u32 vfp_single_multiply(struct vfp_single* vsd, struct vfp_single* vsn, - struct vfp_single* vsm, u32 fpscr) { - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - std::swap(vsm, vsn); - LOG_TRACE(Core_ARM, "swapping M <-> N"); - } - - vsd->sign = vsn->sign ^ vsm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vsn->exponent == 255) { - if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - if ((vsm->exponent | vsm->significand) == 0) { - *vsd = vfp_single_default_qnan; - return FPSCR_IOC; - } - vsd->exponent = vsn->exponent; - vsd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vsm->exponent | vsm->significand) == 0) { - vsd->exponent = 0; - vsd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason as - * the addition case - though this time we have +1 from each - * input operand. - */ - vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; - vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); - - vfp_single_dump("VSD", vsd); - return 0; -} - -#define NEG_MULTIPLY (1 << 0) -#define NEG_SUBTRACT (1 << 1) - -static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, - u32 negate, const char* func) { - vfp_single vsd, vsp, vsn, vsm; - u32 exceptions = 0; - s32 v; - - v = vfp_get_float(state, sn); - LOG_TRACE(Core_ARM, "s%u = %08x", sn, v); - exceptions |= vfp_single_unpack(&vsn, v, fpscr); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions |= vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); - - if (negate & NEG_MULTIPLY) - vsp.sign = vfp_sign_negate(vsp.sign); - - v = vfp_get_float(state, sd); - LOG_TRACE(Core_ARM, "s%u = %08x", sd, v); - exceptions |= vfp_single_unpack(&vsn, v, fpscr); - if (vsn.exponent == 0 && vsn.significand != 0) - vfp_single_normalise_denormal(&vsn); - - if (negate & NEG_SUBTRACT) - vsn.sign = vfp_sign_negate(vsn.sign); - - exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); -} - -/* - * Standard operations - */ - -/* - * sd = sd + (sn * sm) - */ -static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); -} - -/* - * sd = sd - (sn * sm) - */ -static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - // TODO: this one has its arguments inverted, investigate. - LOG_TRACE(Core_ARM, "s%u = %08x", sd, sn); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); -} - -/* - * sd = -sd + (sn * sm) - */ -static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); -} - -/* - * sd = -sd - (sn * sm) - */ -static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, - "fnmsc"); -} - -/* - * sd = sn * sm - */ -static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - - LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); - - exceptions |= vfp_single_unpack(&vsn, n, fpscr); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); -} - -/* - * sd = -(sn * sm) - */ -static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - - LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); - - exceptions |= vfp_single_unpack(&vsn, n, fpscr); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - vsd.sign = vfp_sign_negate(vsd.sign); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); -} - -/* - * sd = sn + sm - */ -static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - - LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); - - /* - * Unpack and normalise denormals. - */ - exceptions |= vfp_single_unpack(&vsn, n, fpscr); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions |= vfp_single_add(&vsd, &vsn, &vsm, fpscr); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); -} - -/* - * sd = sn - sm - */ -static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - LOG_TRACE(Core_ARM, "s%u = %08x", sn, sd); - /* - * Subtraction is addition with one sign inverted. Unpack the second operand to perform FTZ if - * necessary, we can't let fadd do this because a denormal in m might get flushed to +0 in FTZ - * mode, and the resulting sign of 0 OP +0 differs between fadd and fsub. We do not need to do - * this for n because +0 OP 0 is always +0 for both fadd and fsub. - */ - struct vfp_single vsm; - u32 exceptions = vfp_single_unpack(&vsm, m, fpscr); - if (exceptions & FPSCR_IDC) { - // The value was flushed to zero, re-pack it. - m = vfp_single_pack(&vsm); - } - - if (m != 0x7FC00000) // Only negate if m isn't NaN. - m = vfp_single_packed_negate(m); - - return vfp_single_fadd(state, sd, sn, m, fpscr) | exceptions; -} - -/* - * sd = sn / sm - */ -static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - int tm, tn; - - LOG_TRACE(Core_ARM, "s%u = %08x", sn, n); - - exceptions |= vfp_single_unpack(&vsn, n, fpscr); - exceptions |= vfp_single_unpack(&vsm, m, fpscr); - - vsd.sign = vsn.sign ^ vsm.sign; - - tn = vfp_single_type(&vsn); - tm = vfp_single_type(&vsm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vsn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vsm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY | VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exception - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsn); - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; - vsm.significand <<= 1; - if (vsm.significand <= (2 * vsn.significand)) { - vsn.significand >>= 1; - vsd.exponent++; - } - { - u64 significand = (u64)vsn.significand << 32; - do_div(significand, vsm.significand); - vsd.significand = (u32)significand; - } - if ((vsd.significand & 0x3f) == 0) - vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); - -vsn_nan: - exceptions |= vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); -pack: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; - -vsm_nan: - exceptions |= vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); - goto pack; - -zero: - vsd.exponent = 0; - vsd.significand = 0; - goto pack; - -divzero: - exceptions |= FPSCR_DZC; -infinity: - vsd.exponent = 255; - vsd.significand = 0; - goto pack; - -invalid: - vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); - return FPSCR_IOC; -} - -static struct op fops[] = { - {vfp_single_fmac, 0}, {vfp_single_fmsc, 0}, {vfp_single_fmul, 0}, - {vfp_single_fadd, 0}, {vfp_single_fnmac, 0}, {vfp_single_fnmsc, 0}, - {vfp_single_fnmul, 0}, {vfp_single_fsub, 0}, {vfp_single_fdiv, 0}, -}; - -#define FREG_BANK(x) ((x)&0x18) -#define FREG_IDX(x) ((x)&7) - -u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int sn = vfp_get_sn(inst); - unsigned int sm = vfp_get_sm(inst); - unsigned int vecitr, veclen, vecstride; - struct op* fop; - - vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtsd takes a dN register number as destination, not sN. - * Technically, if bit 0 of dd is set, this is an invalid - * instruction. However, we ignore this for efficiency. - * It also only operates on scalars. - */ - if (fop->flags & OP_DD) - dest = vfp_get_dd(inst); - else - dest = vfp_get_sd(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - LOG_TRACE(Core_ARM, "vecstride=%u veclen=%u", vecstride, (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - LOG_CRITICAL(Core_ARM, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), - inst, state->Reg[15]); - Crash(); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - s32 m = vfp_get_float(state, sm); - u32 except; - char type; - - type = (fop->flags & OP_DD) ? 'd' : 's'; - if (op == FOP_EXT) - LOG_TRACE(Core_ARM, "itr%d (%c%u) = op[%u] (s%u=%08x)", vecitr >> FPSCR_LENGTH_BIT, - type, dest, sn, sm, m); - else - LOG_TRACE(Core_ARM, "itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)", - vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, FOP_TO_IDX(op), sm, m); - - except = fop->fn(state, dest, sn, m, fpscr); - LOG_TRACE(Core_ARM, "itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except & ~VFP_NAN_FLAG; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); - sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); - if (FREG_BANK(sm) != 0) - sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); - } - return exceptions; - -invalid: - return (u32)-1; -} -- cgit v1.2.3