mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-11-27 20:14:17 +01:00
- moved mmu to arm/interpreter folder
- added initial VFP code from skyeye
This commit is contained in:
parent
bdc54d0d48
commit
3e1eafa244
@ -14,7 +14,11 @@ set(SRCS core.cpp
|
|||||||
arm/interpreter/armsupp.cpp
|
arm/interpreter/armsupp.cpp
|
||||||
arm/interpreter/armvirt.cpp
|
arm/interpreter/armvirt.cpp
|
||||||
arm/interpreter/thumbemu.cpp
|
arm/interpreter/thumbemu.cpp
|
||||||
arm/mmu/arm1176jzf_s_mmu.cpp
|
arm/interpreter/vfp/vfp.cpp
|
||||||
|
arm/interpreter/vfp/vfpdouble.cpp
|
||||||
|
arm/interpreter/vfp/vfpinsr.cpp
|
||||||
|
arm/interpreter/vfp/vfpsingle.cpp
|
||||||
|
arm/interpreter/mmu/arm1176jzf_s_mmu.cpp
|
||||||
elf/elf_reader.cpp
|
elf/elf_reader.cpp
|
||||||
file_sys/directory_file_system.cpp
|
file_sys/directory_file_system.cpp
|
||||||
file_sys/meta_file_system.cpp
|
file_sys/meta_file_system.cpp
|
||||||
|
84
src/core/arm/interpreter/vfp/asm_vfp.h
Normal file
84
src/core/arm/interpreter/vfp/asm_vfp.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* arch/arm/include/asm/vfp.h
|
||||||
|
*
|
||||||
|
* VFP register definitions.
|
||||||
|
* First, the standard VFP set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define FPSID cr0
|
||||||
|
#define FPSCR cr1
|
||||||
|
#define MVFR1 cr6
|
||||||
|
#define MVFR0 cr7
|
||||||
|
#define FPEXC cr8
|
||||||
|
#define FPINST cr9
|
||||||
|
#define FPINST2 cr10
|
||||||
|
|
||||||
|
/* FPSID bits */
|
||||||
|
#define FPSID_IMPLEMENTER_BIT (24)
|
||||||
|
#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT)
|
||||||
|
#define FPSID_SOFTWARE (1<<23)
|
||||||
|
#define FPSID_FORMAT_BIT (21)
|
||||||
|
#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT)
|
||||||
|
#define FPSID_NODOUBLE (1<<20)
|
||||||
|
#define FPSID_ARCH_BIT (16)
|
||||||
|
#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT)
|
||||||
|
#define FPSID_PART_BIT (8)
|
||||||
|
#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT)
|
||||||
|
#define FPSID_VARIANT_BIT (4)
|
||||||
|
#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT)
|
||||||
|
#define FPSID_REV_BIT (0)
|
||||||
|
#define FPSID_REV_MASK (0xF << FPSID_REV_BIT)
|
||||||
|
|
||||||
|
/* FPEXC bits */
|
||||||
|
#define FPEXC_EX (1 << 31)
|
||||||
|
#define FPEXC_EN (1 << 30)
|
||||||
|
#define FPEXC_DEX (1 << 29)
|
||||||
|
#define FPEXC_FP2V (1 << 28)
|
||||||
|
#define FPEXC_VV (1 << 27)
|
||||||
|
#define FPEXC_TFV (1 << 26)
|
||||||
|
#define FPEXC_LENGTH_BIT (8)
|
||||||
|
#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
|
||||||
|
#define FPEXC_IDF (1 << 7)
|
||||||
|
#define FPEXC_IXF (1 << 4)
|
||||||
|
#define FPEXC_UFF (1 << 3)
|
||||||
|
#define FPEXC_OFF (1 << 2)
|
||||||
|
#define FPEXC_DZF (1 << 1)
|
||||||
|
#define FPEXC_IOF (1 << 0)
|
||||||
|
#define FPEXC_TRAP_MASK (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
|
||||||
|
|
||||||
|
/* FPSCR bits */
|
||||||
|
#define FPSCR_DEFAULT_NAN (1<<25)
|
||||||
|
#define FPSCR_FLUSHTOZERO (1<<24)
|
||||||
|
#define FPSCR_ROUND_NEAREST (0<<22)
|
||||||
|
#define FPSCR_ROUND_PLUSINF (1<<22)
|
||||||
|
#define FPSCR_ROUND_MINUSINF (2<<22)
|
||||||
|
#define FPSCR_ROUND_TOZERO (3<<22)
|
||||||
|
#define FPSCR_RMODE_BIT (22)
|
||||||
|
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
|
||||||
|
#define FPSCR_STRIDE_BIT (20)
|
||||||
|
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
|
||||||
|
#define FPSCR_LENGTH_BIT (16)
|
||||||
|
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
|
||||||
|
#define FPSCR_IOE (1<<8)
|
||||||
|
#define FPSCR_DZE (1<<9)
|
||||||
|
#define FPSCR_OFE (1<<10)
|
||||||
|
#define FPSCR_UFE (1<<11)
|
||||||
|
#define FPSCR_IXE (1<<12)
|
||||||
|
#define FPSCR_IDE (1<<15)
|
||||||
|
#define FPSCR_IOC (1<<0)
|
||||||
|
#define FPSCR_DZC (1<<1)
|
||||||
|
#define FPSCR_OFC (1<<2)
|
||||||
|
#define FPSCR_UFC (1<<3)
|
||||||
|
#define FPSCR_IXC (1<<4)
|
||||||
|
#define FPSCR_IDC (1<<7)
|
||||||
|
|
||||||
|
/* MVFR0 bits */
|
||||||
|
#define MVFR0_A_SIMD_BIT (0)
|
||||||
|
#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT)
|
||||||
|
|
||||||
|
/* Bit patterns for decoding the packaged operation descriptors */
|
||||||
|
#define VFPOPDESC_LENGTH_BIT (9)
|
||||||
|
#define VFPOPDESC_LENGTH_MASK (0x07 << VFPOPDESC_LENGTH_BIT)
|
||||||
|
#define VFPOPDESC_UNUSED_BIT (24)
|
||||||
|
#define VFPOPDESC_UNUSED_MASK (0xFF << VFPOPDESC_UNUSED_BIT)
|
||||||
|
#define VFPOPDESC_OPDESC_MASK (~(VFPOPDESC_LENGTH_MASK | VFPOPDESC_UNUSED_MASK))
|
357
src/core/arm/interpreter/vfp/vfp.cpp
Normal file
357
src/core/arm/interpreter/vfp/vfp.cpp
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* Opens debug for classic interpreter only */
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
#include "common/common.h"
|
||||||
|
|
||||||
|
#include "core/arm/interpreter/armdefs.h"
|
||||||
|
#include "core/arm/interpreter/vfp/vfp.h"
|
||||||
|
|
||||||
|
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPInit (ARMul_State *state)
|
||||||
|
{
|
||||||
|
state->VFP[VFP_OFFSET(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_OFFSET(VFP_FPEXC)] = 0;
|
||||||
|
state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
|
||||||
|
|
||||||
|
//persistent_state = state;
|
||||||
|
/* Reset only specify VFP_FPEXC_EN = '0' */
|
||||||
|
|
||||||
|
return No_exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
||||||
|
{
|
||||||
|
/* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int OPC_1 = BITS (21, 23);
|
||||||
|
int Rt = BITS (12, 15);
|
||||||
|
int CRn = BITS (16, 19);
|
||||||
|
int CRm = BITS (0, 3);
|
||||||
|
int OPC_2 = BITS (5, 7);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#define VFP_MRC_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MRC_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
|
||||||
|
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
||||||
|
{
|
||||||
|
/* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int OPC_1 = BITS (21, 23);
|
||||||
|
int Rt = BITS (12, 15);
|
||||||
|
int CRn = BITS (16, 19);
|
||||||
|
int CRm = BITS (0, 3);
|
||||||
|
int OPC_2 = BITS (5, 7);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#define VFP_MCR_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MCR_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
|
||||||
|
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
|
||||||
|
{
|
||||||
|
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int OPC_1 = BITS (4, 7);
|
||||||
|
int Rt = BITS (12, 15);
|
||||||
|
int Rt2 = BITS (16, 19);
|
||||||
|
int CRm = BITS (0, 3);
|
||||||
|
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#define VFP_MRRC_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MRRC_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
||||||
|
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
|
||||||
|
{
|
||||||
|
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int OPC_1 = BITS (4, 7);
|
||||||
|
int Rt = BITS (12, 15);
|
||||||
|
int Rt2 = BITS (16, 19);
|
||||||
|
int CRm = BITS (0, 3);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
|
if (CoProc == 11 || CoProc == 10)
|
||||||
|
{
|
||||||
|
#define VFP_MCRR_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MCRR_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
||||||
|
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
||||||
|
{
|
||||||
|
/* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int CRd = BITS (12, 15);
|
||||||
|
int Rn = BITS (16, 19);
|
||||||
|
int imm8 = BITS (0, 7);
|
||||||
|
int P = BIT(24);
|
||||||
|
int U = BIT(23);
|
||||||
|
int D = BIT(22);
|
||||||
|
int W = BIT(21);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
/* VSTM */
|
||||||
|
if ( (P|U|D|W) == 0 )
|
||||||
|
{
|
||||||
|
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
|
||||||
|
}
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
if (P == 0 && U == 0 && W == 0)
|
||||||
|
{
|
||||||
|
DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
|
||||||
|
}
|
||||||
|
if (P == U && W == 1)
|
||||||
|
{
|
||||||
|
DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VFP_STC_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_STC_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
|
||||||
|
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
||||||
|
{
|
||||||
|
/* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int CRd = BITS (12, 15);
|
||||||
|
int Rn = BITS (16, 19);
|
||||||
|
int imm8 = BITS (0, 7);
|
||||||
|
int P = BIT(24);
|
||||||
|
int U = BIT(23);
|
||||||
|
int D = BIT(22);
|
||||||
|
int W = BIT(21);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
if ( (P|U|D|W) == 0 )
|
||||||
|
{
|
||||||
|
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
|
||||||
|
}
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#define VFP_LDC_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_LDC_TRANS
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
|
||||||
|
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
||||||
|
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned
|
||||||
|
VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
|
||||||
|
{
|
||||||
|
/* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
|
||||||
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
|
int OPC_1 = BITS (20, 23);
|
||||||
|
int CRd = BITS (12, 15);
|
||||||
|
int CRn = BITS (16, 19);
|
||||||
|
int CRm = BITS (0, 3);
|
||||||
|
int OPC_2 = BITS (5, 7);
|
||||||
|
|
||||||
|
/* TODO check access permission */
|
||||||
|
|
||||||
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
|
if (CoProc == 10 || CoProc == 11)
|
||||||
|
{
|
||||||
|
#define VFP_CDP_TRANS
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_CDP_TRANS
|
||||||
|
|
||||||
|
int exceptions = 0;
|
||||||
|
if (CoProc == 10)
|
||||||
|
exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
|
||||||
|
else
|
||||||
|
exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
|
||||||
|
|
||||||
|
vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
|
||||||
|
|
||||||
|
return ARMul_DONE;
|
||||||
|
}
|
||||||
|
DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
|
||||||
|
return ARMul_CANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------- MRC ------------ */
|
||||||
|
#define VFP_MRC_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MRC_IMPL
|
||||||
|
|
||||||
|
#define VFP_MRRC_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MRRC_IMPL
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------- MCR ------------ */
|
||||||
|
#define VFP_MCR_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MCR_IMPL
|
||||||
|
|
||||||
|
#define VFP_MCRR_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_MCRR_IMPL
|
||||||
|
|
||||||
|
/* Memory operation are not inlined, as old Interpreter and Fast interpreter
|
||||||
|
don't have the same memory operation interface.
|
||||||
|
Old interpreter framework does one access to coprocessor per data, and
|
||||||
|
handles already data write, as well as address computation,
|
||||||
|
which is not the case for Fast interpreter. Therefore, implementation
|
||||||
|
of vfp instructions in old interpreter and fast interpreter are separate. */
|
||||||
|
|
||||||
|
/* ----------- STC ------------ */
|
||||||
|
#define VFP_STC_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_STC_IMPL
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------- LDC ------------ */
|
||||||
|
#define VFP_LDC_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_LDC_IMPL
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------- CDP ------------ */
|
||||||
|
#define VFP_CDP_IMPL
|
||||||
|
#include "core/arm/interpreter/vfp/vfpinstr.cpp"
|
||||||
|
#undef VFP_CDP_IMPL
|
||||||
|
|
||||||
|
/* Miscellaneous functions */
|
||||||
|
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
|
||||||
|
{
|
||||||
|
DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
|
||||||
|
return state->ExtReg[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
|
||||||
|
{
|
||||||
|
DBG("VFP put float: s%d <= [%08x]\n", reg, val);
|
||||||
|
state->ExtReg[reg] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
|
||||||
|
{
|
||||||
|
uint64_t result;
|
||||||
|
result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
|
||||||
|
DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
|
||||||
|
{
|
||||||
|
DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
|
||||||
|
state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
|
||||||
|
state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process bitmask of exception conditions. (from vfpmodule.c)
|
||||||
|
*/
|
||||||
|
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
|
||||||
|
{
|
||||||
|
int si_code = 0;
|
||||||
|
|
||||||
|
vfpdebug("VFP: raising exceptions %08x\n", exceptions);
|
||||||
|
|
||||||
|
if (exceptions == VFP_EXCEPTION_ERROR) {
|
||||||
|
DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
|
||||||
|
exit(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_N|FPSCR_Z|FPSCR_C|FPSCR_V))
|
||||||
|
fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
|
||||||
|
|
||||||
|
fpscr |= exceptions;
|
||||||
|
|
||||||
|
state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
|
||||||
|
}
|
111
src/core/arm/interpreter/vfp/vfp.h
Normal file
111
src/core/arm/interpreter/vfp/vfp.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VFP_H__
|
||||||
|
#define __VFP_H__
|
||||||
|
|
||||||
|
#define DBG(msg) DEBUG_LOG(ARM11, msg)
|
||||||
|
|
||||||
|
#define vfpdebug //printf
|
||||||
|
|
||||||
|
#include "core/arm/interpreter/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
|
||||||
|
|
||||||
|
unsigned VFPInit (ARMul_State *state);
|
||||||
|
unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
|
||||||
|
unsigned VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value);
|
||||||
|
unsigned VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2);
|
||||||
|
unsigned VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
|
||||||
|
unsigned VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
|
||||||
|
unsigned VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value);
|
||||||
|
unsigned VFPCDP (ARMul_State * state, unsigned type, ARMword instr);
|
||||||
|
|
||||||
|
/* FPSID Information */
|
||||||
|
#define VFP_FPSID_IMPLMEN 0 /* should be the same as cp15 0 c0 0*/
|
||||||
|
#define VFP_FPSID_SW 0
|
||||||
|
#define VFP_FPSID_SUBARCH 0x2 /* VFP version. Current is v3 (not strict) */
|
||||||
|
#define VFP_FPSID_PARTNUM 0x1
|
||||||
|
#define VFP_FPSID_VARIANT 0x1
|
||||||
|
#define VFP_FPSID_REVISION 0x1
|
||||||
|
|
||||||
|
/* FPEXC Flags */
|
||||||
|
#define VFP_FPEXC_EX 1<<31
|
||||||
|
#define VFP_FPEXC_EN 1<<30
|
||||||
|
|
||||||
|
/* FPSCR Flags */
|
||||||
|
#define VFP_FPSCR_NFLAG 1<<31
|
||||||
|
#define VFP_FPSCR_ZFLAG 1<<30
|
||||||
|
#define VFP_FPSCR_CFLAG 1<<29
|
||||||
|
#define VFP_FPSCR_VFLAG 1<<28
|
||||||
|
|
||||||
|
#define VFP_FPSCR_AHP 1<<26 /* Alternative Half Precision */
|
||||||
|
#define VFP_FPSCR_DN 1<<25 /* Default NaN */
|
||||||
|
#define VFP_FPSCR_FZ 1<<24 /* Flush-to-zero */
|
||||||
|
#define VFP_FPSCR_RMODE 3<<22 /* Rounding Mode */
|
||||||
|
#define VFP_FPSCR_STRIDE 3<<20 /* Stride (vector) */
|
||||||
|
#define VFP_FPSCR_LEN 7<<16 /* Stride (vector) */
|
||||||
|
|
||||||
|
#define VFP_FPSCR_IDE 1<<15 /* Input Denormal exc */
|
||||||
|
#define VFP_FPSCR_IXE 1<<12 /* Inexact exc */
|
||||||
|
#define VFP_FPSCR_UFE 1<<11 /* Undeflow exc */
|
||||||
|
#define VFP_FPSCR_OFE 1<<10 /* Overflow exc */
|
||||||
|
#define VFP_FPSCR_DZE 1<<9 /* Division by Zero exc */
|
||||||
|
#define VFP_FPSCR_IOE 1<<8 /* Invalid Operation exc */
|
||||||
|
|
||||||
|
#define VFP_FPSCR_IDC 1<<7 /* Input Denormal cum exc */
|
||||||
|
#define VFP_FPSCR_IXC 1<<4 /* Inexact cum exc */
|
||||||
|
#define VFP_FPSCR_UFC 1<<3 /* Undeflow cum exc */
|
||||||
|
#define VFP_FPSCR_OFC 1<<2 /* Overflow cum exc */
|
||||||
|
#define VFP_FPSCR_DZC 1<<1 /* Division by Zero cum exc */
|
||||||
|
#define VFP_FPSCR_IOC 1<<0 /* Invalid Operation cum exc */
|
||||||
|
|
||||||
|
/* Inline instructions. Note: Used in a cpp file as well */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
int32_t vfp_get_float(ARMul_State * state, unsigned int reg);
|
||||||
|
void vfp_put_float(ARMul_State * state, int32_t val, unsigned int reg);
|
||||||
|
uint64_t vfp_get_double(ARMul_State * state, unsigned int reg);
|
||||||
|
void vfp_put_double(ARMul_State * state, uint64_t val, unsigned int reg);
|
||||||
|
void vfp_raise_exceptions(ARMul_State * state, uint32_t exceptions, uint32_t inst, uint32_t fpscr);
|
||||||
|
extern uint32_t vfp_single_cpdo(ARMul_State * state, uint32_t inst, uint32_t fpscr);
|
||||||
|
extern uint32_t vfp_double_cpdo(ARMul_State * state, uint32_t inst, uint32_t fpscr);
|
||||||
|
|
||||||
|
/* MRC */
|
||||||
|
inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
|
||||||
|
inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
|
||||||
|
inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
|
||||||
|
inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
|
||||||
|
inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
|
||||||
|
/* MCR */
|
||||||
|
inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
|
||||||
|
/* STC */
|
||||||
|
inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
|
||||||
|
inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
|
||||||
|
inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
|
||||||
|
/* LDC */
|
||||||
|
inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
|
||||||
|
inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
|
||||||
|
inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
541
src/core/arm/interpreter/vfp/vfp_helper.h
Normal file
541
src/core/arm/interpreter/vfp/vfp_helper.h
Normal file
@ -0,0 +1,541 @@
|
|||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VFP_HELPER_H__
|
||||||
|
#define __VFP_HELPER_H__
|
||||||
|
|
||||||
|
/* Custom edit */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "core/arm/interpreter/armdefs.h"
|
||||||
|
|
||||||
|
#define u16 uint16_t
|
||||||
|
#define u32 uint32_t
|
||||||
|
#define u64 uint64_t
|
||||||
|
#define s16 int16_t
|
||||||
|
#define s32 int32_t
|
||||||
|
#define s64 int64_t
|
||||||
|
|
||||||
|
#define pr_info //printf
|
||||||
|
#define pr_debug //printf
|
||||||
|
|
||||||
|
static u32 fls(int x);
|
||||||
|
#define do_div(n, base) {n/=base;}
|
||||||
|
|
||||||
|
/* From vfpinstr.h */
|
||||||
|
|
||||||
|
#define INST_CPRTDO(inst) (((inst) & 0x0f000000) == 0x0e000000)
|
||||||
|
#define INST_CPRT(inst) ((inst) & (1 << 4))
|
||||||
|
#define INST_CPRT_L(inst) ((inst) & (1 << 20))
|
||||||
|
#define INST_CPRT_Rd(inst) (((inst) & (15 << 12)) >> 12)
|
||||||
|
#define INST_CPRT_OP(inst) (((inst) >> 21) & 7)
|
||||||
|
#define INST_CPNUM(inst) ((inst) & 0xf00)
|
||||||
|
#define CPNUM(cp) ((cp) << 8)
|
||||||
|
|
||||||
|
#define FOP_MASK (0x00b00040)
|
||||||
|
#define FOP_FMAC (0x00000000)
|
||||||
|
#define FOP_FNMAC (0x00000040)
|
||||||
|
#define FOP_FMSC (0x00100000)
|
||||||
|
#define FOP_FNMSC (0x00100040)
|
||||||
|
#define FOP_FMUL (0x00200000)
|
||||||
|
#define FOP_FNMUL (0x00200040)
|
||||||
|
#define FOP_FADD (0x00300000)
|
||||||
|
#define FOP_FSUB (0x00300040)
|
||||||
|
#define FOP_FDIV (0x00800000)
|
||||||
|
#define FOP_EXT (0x00b00040)
|
||||||
|
|
||||||
|
#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4)
|
||||||
|
|
||||||
|
#define FEXT_MASK (0x000f0080)
|
||||||
|
#define FEXT_FCPY (0x00000000)
|
||||||
|
#define FEXT_FABS (0x00000080)
|
||||||
|
#define FEXT_FNEG (0x00010000)
|
||||||
|
#define FEXT_FSQRT (0x00010080)
|
||||||
|
#define FEXT_FCMP (0x00040000)
|
||||||
|
#define FEXT_FCMPE (0x00040080)
|
||||||
|
#define FEXT_FCMPZ (0x00050000)
|
||||||
|
#define FEXT_FCMPEZ (0x00050080)
|
||||||
|
#define FEXT_FCVT (0x00070080)
|
||||||
|
#define FEXT_FUITO (0x00080000)
|
||||||
|
#define FEXT_FSITO (0x00080080)
|
||||||
|
#define FEXT_FTOUI (0x000c0000)
|
||||||
|
#define FEXT_FTOUIZ (0x000c0080)
|
||||||
|
#define FEXT_FTOSI (0x000d0000)
|
||||||
|
#define 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)
|
||||||
|
|
||||||
|
#define FPSCR_N (1 << 31)
|
||||||
|
#define FPSCR_Z (1 << 30)
|
||||||
|
#define FPSCR_C (1 << 29)
|
||||||
|
#define FPSCR_V (1 << 28)
|
||||||
|
|
||||||
|
/* -------------- */
|
||||||
|
|
||||||
|
/* From asm/include/vfp.h */
|
||||||
|
|
||||||
|
/* FPSCR bits */
|
||||||
|
#define FPSCR_DEFAULT_NAN (1<<25)
|
||||||
|
#define FPSCR_FLUSHTOZERO (1<<24)
|
||||||
|
#define FPSCR_ROUND_NEAREST (0<<22)
|
||||||
|
#define FPSCR_ROUND_PLUSINF (1<<22)
|
||||||
|
#define FPSCR_ROUND_MINUSINF (2<<22)
|
||||||
|
#define FPSCR_ROUND_TOZERO (3<<22)
|
||||||
|
#define FPSCR_RMODE_BIT (22)
|
||||||
|
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
|
||||||
|
#define FPSCR_STRIDE_BIT (20)
|
||||||
|
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
|
||||||
|
#define FPSCR_LENGTH_BIT (16)
|
||||||
|
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
|
||||||
|
#define FPSCR_IOE (1<<8)
|
||||||
|
#define FPSCR_DZE (1<<9)
|
||||||
|
#define FPSCR_OFE (1<<10)
|
||||||
|
#define FPSCR_UFE (1<<11)
|
||||||
|
#define FPSCR_IXE (1<<12)
|
||||||
|
#define FPSCR_IDE (1<<15)
|
||||||
|
#define FPSCR_IOC (1<<0)
|
||||||
|
#define FPSCR_DZC (1<<1)
|
||||||
|
#define FPSCR_OFC (1<<2)
|
||||||
|
#define FPSCR_UFC (1<<3)
|
||||||
|
#define FPSCR_IXC (1<<4)
|
||||||
|
#define FPSCR_IDC (1<<7)
|
||||||
|
|
||||||
|
/* ---------------- */
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mul64to128(u64 *resh, u64 *resl, u64 n, u64 m)
|
||||||
|
{
|
||||||
|
u32 nh, nl, mh, ml;
|
||||||
|
u64 rh, rma, rmb, rl;
|
||||||
|
|
||||||
|
nl = n;
|
||||||
|
ml = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void shift64left(u64 *resh, u64 *resl, u64 n)
|
||||||
|
{
|
||||||
|
*resh = n >> 63;
|
||||||
|
*resl = n << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 vfp_hi64multiply64(u64 n, u64 m)
|
||||||
|
{
|
||||||
|
u64 rh, rl;
|
||||||
|
mul64to128(&rh, &rl, n, m);
|
||||||
|
return rh | (rl != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern s32 vfp_get_float(ARMul_State * state, unsigned int reg);
|
||||||
|
extern void vfp_put_float(ARMul_State * state, s32 val, unsigned int reg);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static inline void vfp_single_unpack(struct vfp_single *s, s32 val)
|
||||||
|
{
|
||||||
|
u32 significand;
|
||||||
|
|
||||||
|
s->sign = vfp_single_packed_sign(val) >> 16,
|
||||||
|
s->exponent = vfp_single_packed_exponent(val);
|
||||||
|
|
||||||
|
significand = (u32) val;
|
||||||
|
significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
|
||||||
|
if (s->exponent && s->exponent != 255)
|
||||||
|
significand |= 0x40000000;
|
||||||
|
s->significand = significand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-pack a single-precision float. This assumes that the float is
|
||||||
|
* already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||||
|
*/
|
||||||
|
static inline s32 vfp_single_pack(struct vfp_single *s)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
val = (s->sign << 16) +
|
||||||
|
(s->exponent << VFP_SINGLE_MANTISSA_BITS) +
|
||||||
|
(s->significand >> VFP_SINGLE_LOW_BITS);
|
||||||
|
return (s32)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VFP_NUMBER (1<<0)
|
||||||
|
#define VFP_ZERO (1<<1)
|
||||||
|
#define VFP_DENORMAL (1<<2)
|
||||||
|
#define VFP_INFINITY (1<<3)
|
||||||
|
#define VFP_NAN (1<<4)
|
||||||
|
#define VFP_NAN_SIGNAL (1<<5)
|
||||||
|
|
||||||
|
#define VFP_QNAN (VFP_NAN)
|
||||||
|
#define VFP_SNAN (VFP_NAN|VFP_NAN_SIGNAL)
|
||||||
|
|
||||||
|
static inline int vfp_single_type(struct 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct 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
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern u64 vfp_get_double(ARMul_State * state, unsigned int reg);
|
||||||
|
extern void vfp_put_double(ARMul_State * state, u64 val, unsigned int reg);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#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))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static inline void vfp_double_unpack(struct vfp_double *s, s64 val)
|
||||||
|
{
|
||||||
|
u64 significand;
|
||||||
|
|
||||||
|
s->sign = vfp_double_packed_sign(val) >> 48;
|
||||||
|
s->exponent = vfp_double_packed_exponent(val);
|
||||||
|
|
||||||
|
significand = (u64) val;
|
||||||
|
significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
|
||||||
|
if (s->exponent && s->exponent != 2047)
|
||||||
|
significand |= (1ULL << 62);
|
||||||
|
s->significand = significand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Re-pack a double-precision float. This assumes that the float is
|
||||||
|
* already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||||
|
*/
|
||||||
|
static inline s64 vfp_double_pack(struct vfp_double *s)
|
||||||
|
{
|
||||||
|
u64 val;
|
||||||
|
val = ((u64)s->sign << 48) +
|
||||||
|
((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
|
||||||
|
(s->significand >> VFP_DOUBLE_LOW_BITS);
|
||||||
|
return (s64)val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int vfp_double_type(struct 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
#define OP_SCALAR (1 << 0)
|
||||||
|
#define OP_SD (1 << 1)
|
||||||
|
#define OP_DD (1 << 1)
|
||||||
|
#define OP_SM (1 << 2)
|
||||||
|
|
||||||
|
struct op {
|
||||||
|
u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline u32 fls(int 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1262
src/core/arm/interpreter/vfp/vfpdouble.cpp
Normal file
1262
src/core/arm/interpreter/vfp/vfpdouble.cpp
Normal file
File diff suppressed because it is too large
Load Diff
5123
src/core/arm/interpreter/vfp/vfpinstr.cpp
Normal file
5123
src/core/arm/interpreter/vfp/vfpinstr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1277
src/core/arm/interpreter/vfp/vfpsingle.cpp
Normal file
1277
src/core/arm/interpreter/vfp/vfpsingle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -147,6 +147,10 @@
|
|||||||
<ClCompile Include="arm\interpreter\armvirt.cpp" />
|
<ClCompile Include="arm\interpreter\armvirt.cpp" />
|
||||||
<ClCompile Include="arm\interpreter\arm_interpreter.cpp" />
|
<ClCompile Include="arm\interpreter\arm_interpreter.cpp" />
|
||||||
<ClCompile Include="arm\interpreter\thumbemu.cpp" />
|
<ClCompile Include="arm\interpreter\thumbemu.cpp" />
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfp.cpp" />
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpdouble.cpp" />
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpinstr.cpp" />
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" />
|
||||||
<ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp" />
|
<ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp" />
|
||||||
<ClCompile Include="core.cpp" />
|
<ClCompile Include="core.cpp" />
|
||||||
<ClCompile Include="core_timing.cpp" />
|
<ClCompile Include="core_timing.cpp" />
|
||||||
@ -182,6 +186,9 @@
|
|||||||
<ClInclude Include="arm\interpreter\arm_interpreter.h" />
|
<ClInclude Include="arm\interpreter\arm_interpreter.h" />
|
||||||
<ClInclude Include="arm\interpreter\arm_regformat.h" />
|
<ClInclude Include="arm\interpreter\arm_regformat.h" />
|
||||||
<ClInclude Include="arm\interpreter\skyeye_defs.h" />
|
<ClInclude Include="arm\interpreter\skyeye_defs.h" />
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\asm_vfp.h" />
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\vfp.h" />
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\vfp_helper.h" />
|
||||||
<ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h" />
|
<ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h" />
|
||||||
<ClInclude Include="arm\mmu\cache.h" />
|
<ClInclude Include="arm\mmu\cache.h" />
|
||||||
<ClInclude Include="arm\mmu\rb.h" />
|
<ClInclude Include="arm\mmu\rb.h" />
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
<Filter Include="hle\service">
|
<Filter Include="hle\service">
|
||||||
<UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier>
|
<UniqueIdentifier>{812c5189-ca49-4704-b842-3ffad09092d3}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="arm\interpreter\vfp">
|
||||||
|
<UniqueIdentifier>{de62238f-a28e-4a33-8495-23fed6784588}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="arm\disassembler\arm_disasm.cpp">
|
<ClCompile Include="arm\disassembler\arm_disasm.cpp">
|
||||||
@ -114,6 +117,18 @@
|
|||||||
<ClCompile Include="hle\config_mem.cpp">
|
<ClCompile Include="hle\config_mem.cpp">
|
||||||
<Filter>hle</Filter>
|
<Filter>hle</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfp.cpp">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpinstr.cpp">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpdouble.cpp">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="arm\disassembler\arm_disasm.h">
|
<ClInclude Include="arm\disassembler\arm_disasm.h">
|
||||||
@ -223,6 +238,15 @@
|
|||||||
<ClInclude Include="hle\config_mem.h">
|
<ClInclude Include="hle\config_mem.h">
|
||||||
<Filter>hle</Filter>
|
<Filter>hle</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\asm_vfp.h">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\vfp.h">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="arm\interpreter\vfp\vfp_helper.h">
|
||||||
|
<Filter>arm\interpreter\vfp</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Text Include="CMakeLists.txt" />
|
<Text Include="CMakeLists.txt" />
|
||||||
|
Loading…
Reference in New Issue
Block a user