summaryrefslogtreecommitdiffstats
path: root/src/core/arm/skyeye_common/vfp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/skyeye_common/vfp/asm_vfp.h83
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp137
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h43
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h433
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp1247
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp1703
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp1272
7 files changed, 0 insertions, 4918 deletions
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 <skyeye-developer@lists.gro.clinux.org>
-
- 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 <skyeye-developer@lists.gro.clinux.org>
-
- 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 <skyeye-developer@lists.gro.clinux.org>
-
- 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 <cstdio>
-#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<u32>(n);
- ml = static_cast<u32>(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 <skyeye-developer@lists.gro.clinux.org>
-
- 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 <algorithm>
-#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 <skyeye-developer@lists.gro.clinux.org>
-
- 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 <algorithm>
-#include <cinttypes>
-#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<u32>((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;
-}