mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-23 02:20:10 +00:00
ARM: Merge latest VFP fixes from 3dmoo team.
This commit is contained in:
parent
2ca12e7f38
commit
bc6989b075
@ -28,6 +28,8 @@
|
|||||||
#include "core/arm/skyeye_common/armdefs.h"
|
#include "core/arm/skyeye_common/armdefs.h"
|
||||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||||
|
|
||||||
|
#define DEBUG DBG
|
||||||
|
|
||||||
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
|
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
@ -41,11 +43,11 @@ VFPInit (ARMul_State *state)
|
|||||||
//persistent_state = state;
|
//persistent_state = state;
|
||||||
/* Reset only specify VFP_FPEXC_EN = '0' */
|
/* Reset only specify VFP_FPEXC_EN = '0' */
|
||||||
|
|
||||||
return No_exp;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
|
||||||
{
|
{
|
||||||
/* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
/* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -59,20 +61,19 @@ VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
|||||||
|
|
||||||
/* CRn/opc1 CRm/opc2 */
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#define VFP_MRC_TRANS
|
||||||
#define VFP_MRC_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_MRC_TRANS
|
||||||
#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",
|
DEBUG("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);
|
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
|
||||||
{
|
{
|
||||||
/* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
/* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -85,20 +86,19 @@ VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
|||||||
/* TODO check access permission */
|
/* TODO check access permission */
|
||||||
|
|
||||||
/* CRn/opc1 CRm/opc2 */
|
/* CRn/opc1 CRm/opc2 */
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#define VFP_MCR_TRANS
|
||||||
#define VFP_MCR_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_MCR_TRANS
|
||||||
#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",
|
DEBUG("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);
|
instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
|
VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
|
||||||
{
|
{
|
||||||
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -107,20 +107,19 @@ VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, AR
|
|||||||
int Rt2 = BITS (16, 19);
|
int Rt2 = BITS (16, 19);
|
||||||
int CRm = BITS (0, 3);
|
int CRm = BITS (0, 3);
|
||||||
|
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#define VFP_MRRC_TRANS
|
||||||
#define VFP_MRRC_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_MRRC_TRANS
|
||||||
#undef VFP_MRRC_TRANS
|
|
||||||
}
|
}
|
||||||
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
||||||
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
|
VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
|
||||||
{
|
{
|
||||||
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
/* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -133,20 +132,19 @@ VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMw
|
|||||||
|
|
||||||
/* CRn/opc1 CRm/opc2 */
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
if (CoProc == 11 || CoProc == 10)
|
if (CoProc == 11 || CoProc == 10) {
|
||||||
{
|
#define VFP_MCRR_TRANS
|
||||||
#define VFP_MCRR_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_MCRR_TRANS
|
||||||
#undef VFP_MCRR_TRANS
|
|
||||||
}
|
}
|
||||||
DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
|
||||||
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
instr, CoProc, OPC_1, Rt, Rt2, CRm);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
|
||||||
{
|
{
|
||||||
/* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
|
/* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -161,35 +159,34 @@ VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
|
|||||||
/* TODO check access permission */
|
/* TODO check access permission */
|
||||||
|
|
||||||
/* VSTM */
|
/* VSTM */
|
||||||
if ( (P|U|D|W) == 0 )
|
if ( (P|U|D|W) == 0 ) {
|
||||||
{
|
DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
|
||||||
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#if 1
|
||||||
#if 1
|
if (P == 0 && U == 0 && W == 0) {
|
||||||
if (P == 0 && U == 0 && W == 0)
|
DEBUG("VSTM Related encodings\n");
|
||||||
{
|
exit(-1);
|
||||||
DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
|
|
||||||
}
|
}
|
||||||
if (P == U && W == 1)
|
if (P == U && W == 1) {
|
||||||
{
|
DEBUG("UNDEFINED\n");
|
||||||
DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VFP_STC_TRANS
|
#define VFP_STC_TRANS
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#undef VFP_STC_TRANS
|
#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",
|
DEBUG("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);
|
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
|
||||||
{
|
{
|
||||||
/* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
|
/* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -203,24 +200,23 @@ VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
|
|||||||
|
|
||||||
/* TODO check access permission */
|
/* TODO check access permission */
|
||||||
|
|
||||||
if ( (P|U|D|W) == 0 )
|
if ( (P|U|D|W) == 0 ) {
|
||||||
{
|
DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
|
||||||
DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#define VFP_LDC_TRANS
|
||||||
#define VFP_LDC_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_LDC_TRANS
|
||||||
#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",
|
DEBUG("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);
|
instr, CoProc, CRd, Rn, imm8, P, U, D, W);
|
||||||
|
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
|
VFPCDP (ARMul_State * state, unsigned type, u32 instr)
|
||||||
{
|
{
|
||||||
/* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
|
/* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
|
||||||
int CoProc = BITS (8, 11); /* 10 or 11 */
|
int CoProc = BITS (8, 11); /* 10 or 11 */
|
||||||
@ -230,15 +226,59 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
|
|||||||
int CRm = BITS (0, 3);
|
int CRm = BITS (0, 3);
|
||||||
int OPC_2 = BITS (5, 7);
|
int OPC_2 = BITS (5, 7);
|
||||||
|
|
||||||
|
//ichfly
|
||||||
|
/*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6)
|
||||||
|
{
|
||||||
|
struct vfp_double vdd;
|
||||||
|
struct vfp_single vsd;
|
||||||
|
int dn = BITS(12, 15) + (BIT(22) << 4);
|
||||||
|
int sd = (BITS(0, 3) << 1) + BIT(5);
|
||||||
|
s32 n = vfp_get_float(state, sd);
|
||||||
|
vfp_single_unpack(&vsd, n);
|
||||||
|
if (vsd.exponent & 0x80)
|
||||||
|
{
|
||||||
|
vdd.exponent = (vsd.exponent&~0x80) | 0x400;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vdd.exponent = vsd.exponent | 0x380;
|
||||||
|
}
|
||||||
|
vdd.sign = vsd.sign;
|
||||||
|
vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand
|
||||||
|
vfp_put_double(state, vfp_double_pack(&vdd), dn);
|
||||||
|
return ARMul_DONE;
|
||||||
|
}
|
||||||
|
if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6
|
||||||
|
{
|
||||||
|
struct vfp_double vdd;
|
||||||
|
struct vfp_single vsd;
|
||||||
|
int sd = BITS(0, 3) + (BIT(5) << 4);
|
||||||
|
int dn = (BITS(12, 15) << 1) + BIT(22);
|
||||||
|
vfp_double_unpack(&vdd, vfp_get_double(state, sd));
|
||||||
|
if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert
|
||||||
|
{
|
||||||
|
vsd.exponent = (vdd.exponent) | 0x80;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vsd.exponent = vdd.exponent & ~0x80;
|
||||||
|
}
|
||||||
|
vsd.exponent &= 0xFF;
|
||||||
|
// vsd.exponent = vdd.exponent >> 3;
|
||||||
|
vsd.sign = vdd.sign;
|
||||||
|
vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000;
|
||||||
|
vfp_put_float(state, vfp_single_pack(&vsd), dn);
|
||||||
|
return ARMul_DONE;
|
||||||
|
}*/
|
||||||
|
|
||||||
/* TODO check access permission */
|
/* TODO check access permission */
|
||||||
|
|
||||||
/* CRn/opc1 CRm/opc2 */
|
/* CRn/opc1 CRm/opc2 */
|
||||||
|
|
||||||
if (CoProc == 10 || CoProc == 11)
|
if (CoProc == 10 || CoProc == 11) {
|
||||||
{
|
#define VFP_CDP_TRANS
|
||||||
#define VFP_CDP_TRANS
|
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
||||||
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
|
#undef VFP_CDP_TRANS
|
||||||
#undef VFP_CDP_TRANS
|
|
||||||
|
|
||||||
int exceptions = 0;
|
int exceptions = 0;
|
||||||
if (CoProc == 10)
|
if (CoProc == 10)
|
||||||
@ -250,7 +290,7 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
|
|||||||
|
|
||||||
return ARMul_DONE;
|
return ARMul_DONE;
|
||||||
}
|
}
|
||||||
DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
|
DEBUG("Can't identify %x\n", instr);
|
||||||
return ARMul_CANT;
|
return ARMul_CANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,13 +341,13 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
|
|||||||
/* Miscellaneous functions */
|
/* Miscellaneous functions */
|
||||||
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
|
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
|
||||||
{
|
{
|
||||||
DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
|
DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
|
||||||
return state->ExtReg[reg];
|
return state->ExtReg[reg];
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfp_put_float(arm_core_t* state, int32_t val, unsigned int 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);
|
DEBUG("VFP put float: s%d <= [%08x]\n", reg, val);
|
||||||
state->ExtReg[reg] = val;
|
state->ExtReg[reg] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,13 +355,13 @@ uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
|
|||||||
{
|
{
|
||||||
uint64_t result;
|
uint64_t result;
|
||||||
result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
|
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);
|
DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
|
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));
|
DEBUG("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] = (uint32_t) (val & 0xffffffff);
|
||||||
state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
|
state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
|
||||||
}
|
}
|
||||||
@ -338,7 +378,7 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
|
|||||||
vfpdebug("VFP: raising exceptions %08x\n", exceptions);
|
vfpdebug("VFP: raising exceptions %08x\n", exceptions);
|
||||||
|
|
||||||
if (exceptions == VFP_EXCEPTION_ERROR) {
|
if (exceptions == VFP_EXCEPTION_ERROR) {
|
||||||
DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
|
DEBUG("unhandled bounce %x\n", inst);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
#define pr_info //printf
|
#define pr_info //printf
|
||||||
#define pr_debug //printf
|
#define pr_debug //printf
|
||||||
|
|
||||||
static u32 vfp_fls(int x);
|
static u32 fls(int x);
|
||||||
#define do_div(n, base) {n/=base;}
|
#define do_div(n, base) {n/=base;}
|
||||||
|
|
||||||
/* From vfpinstr.h */
|
/* From vfpinstr.h */
|
||||||
@ -502,7 +502,7 @@ struct op {
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 vfp_fls(int x)
|
static u32 fls(int x)
|
||||||
{
|
{
|
||||||
int r = 32;
|
int r = 32;
|
||||||
|
|
||||||
@ -532,4 +532,9 @@ static u32 vfp_fls(int x)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
|
||||||
|
u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
|
||||||
|
u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
|
||||||
|
u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,9 +56,9 @@
|
|||||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||||
|
|
||||||
static struct vfp_double vfp_double_default_qnan = {
|
static struct vfp_double vfp_double_default_qnan = {
|
||||||
//.exponent = 2047,
|
2047,
|
||||||
//.sign = 0,
|
0,
|
||||||
//.significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
|
VFP_DOUBLE_SIGNIFICAND_QNAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vfp_double_dump(const char *str, struct vfp_double *d)
|
static void vfp_double_dump(const char *str, struct vfp_double *d)
|
||||||
@ -69,9 +69,9 @@ static void vfp_double_dump(const char *str, struct vfp_double *d)
|
|||||||
|
|
||||||
static void vfp_double_normalise_denormal(struct vfp_double *vd)
|
static void vfp_double_normalise_denormal(struct vfp_double *vd)
|
||||||
{
|
{
|
||||||
int bits = 31 - vfp_fls(vd->significand >> 32);
|
int bits = 31 - fls((ARMword)(vd->significand >> 32));
|
||||||
if (bits == 31)
|
if (bits == 31)
|
||||||
bits = 63 - vfp_fls(vd->significand);
|
bits = 63 - fls((ARMword)vd->significand);
|
||||||
|
|
||||||
vfp_double_dump("normalise_denormal: in", vd);
|
vfp_double_dump("normalise_denormal: in", vd);
|
||||||
|
|
||||||
@ -83,6 +83,134 @@ static void vfp_double_normalise_denormal(struct vfp_double *vd)
|
|||||||
vfp_double_dump("normalise_denormal: out", vd);
|
vfp_double_dump("normalise_denormal: out", vd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 vfp_double_normaliseroundintern(ARMul_State* state, 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((ARMword)(significand >> 32));
|
||||||
|
if (shift == 32)
|
||||||
|
shift = 64 - fls((ARMword)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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
pr_debug("VFP: rounding increment = 0x%08llx\n", 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:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
|
u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
|
||||||
{
|
{
|
||||||
u64 significand, incr;
|
u64 significand, incr;
|
||||||
@ -108,9 +236,9 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
|
|||||||
exponent = vd->exponent;
|
exponent = vd->exponent;
|
||||||
significand = vd->significand;
|
significand = vd->significand;
|
||||||
|
|
||||||
shift = 32 - vfp_fls(significand >> 32);
|
shift = 32 - fls((ARMword)(significand >> 32));
|
||||||
if (shift == 32)
|
if (shift == 32)
|
||||||
shift = 64 - vfp_fls(significand);
|
shift = 64 - fls((ARMword)significand);
|
||||||
if (shift) {
|
if (shift) {
|
||||||
exponent -= shift;
|
exponent -= shift;
|
||||||
significand <<= shift;
|
significand <<= shift;
|
||||||
@ -204,7 +332,7 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
|
|||||||
vd->significand = significand >> 1;
|
vd->significand = significand >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pack:
|
pack:
|
||||||
vfp_double_dump("pack: final", vd);
|
vfp_double_dump("pack: final", vd);
|
||||||
{
|
{
|
||||||
s64 d = vfp_double_pack(vd);
|
s64 d = vfp_double_pack(vd);
|
||||||
@ -287,7 +415,7 @@ static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 f
|
|||||||
static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
|
||||||
{
|
{
|
||||||
pr_debug("In %s\n", __FUNCTION__);
|
pr_debug("In %s\n", __FUNCTION__);
|
||||||
struct vfp_double vdm, vdd, *vdp;
|
vfp_double vdm, vdd, *vdp;
|
||||||
int ret, tm;
|
int ret, tm;
|
||||||
|
|
||||||
vfp_double_unpack(&vdm, vfp_get_double(state, dm));
|
vfp_double_unpack(&vdm, vfp_get_double(state, dm));
|
||||||
@ -298,11 +426,11 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32
|
|||||||
if (tm & VFP_NAN)
|
if (tm & VFP_NAN)
|
||||||
ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
|
ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
|
||||||
else if (vdm.sign == 0) {
|
else if (vdm.sign == 0) {
|
||||||
sqrt_copy:
|
sqrt_copy:
|
||||||
vdp = &vdm;
|
vdp = &vdm;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
sqrt_invalid:
|
sqrt_invalid:
|
||||||
vdp = &vfp_double_default_qnan;
|
vdp = &vfp_double_default_qnan;
|
||||||
ret = FPSCR_IOC;
|
ret = FPSCR_IOC;
|
||||||
}
|
}
|
||||||
@ -464,6 +592,49 @@ static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32
|
|||||||
return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
|
return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only
|
||||||
|
{
|
||||||
|
struct vfp_single vsd;
|
||||||
|
int tm;
|
||||||
|
u32 exceptions = 0;
|
||||||
|
|
||||||
|
pr_debug("In %s\n", __FUNCTION__);
|
||||||
|
|
||||||
|
tm = vfp_double_type(dm);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have a signalling NaN, signal invalid operation.
|
||||||
|
*/
|
||||||
|
if (tm == VFP_SNAN)
|
||||||
|
exceptions = FPSCR_IOC;
|
||||||
|
|
||||||
|
if (tm & VFP_DENORMAL)
|
||||||
|
vfp_double_normalise_denormal(dm);
|
||||||
|
|
||||||
|
vsd.sign = dm->sign;
|
||||||
|
vsd.significand = vfp_hi64to32jamming(dm->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 = dm->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_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
|
||||||
{
|
{
|
||||||
struct vfp_double vdm;
|
struct vfp_double vdm;
|
||||||
@ -503,7 +674,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32
|
|||||||
|
|
||||||
return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
|
return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
|
||||||
|
|
||||||
pack_nan:
|
pack_nan:
|
||||||
vfp_put_float(state, vfp_single_pack(&vsd), sd);
|
vfp_put_float(state, vfp_single_pack(&vsd), sd);
|
||||||
return exceptions;
|
return exceptions;
|
||||||
}
|
}
|
||||||
@ -564,7 +735,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
|
|||||||
/*
|
/*
|
||||||
* 2^0 <= m < 2^32-2^8
|
* 2^0 <= m < 2^32-2^8
|
||||||
*/
|
*/
|
||||||
d = (vdm.significand << 1) >> shift;
|
d = (ARMword)((vdm.significand << 1) >> shift);
|
||||||
rem = vdm.significand << (65 - shift);
|
rem = vdm.significand << (65 - shift);
|
||||||
|
|
||||||
if (rmode == FPSCR_ROUND_NEAREST) {
|
if (rmode == FPSCR_ROUND_NEAREST) {
|
||||||
@ -645,7 +816,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
|
|||||||
int shift = 1023 + 63 - vdm.exponent; /* 58 */
|
int shift = 1023 + 63 - vdm.exponent; /* 58 */
|
||||||
u64 rem, incr = 0;
|
u64 rem, incr = 0;
|
||||||
|
|
||||||
d = (vdm.significand << 1) >> shift;
|
d = (ARMword)((vdm.significand << 1) >> shift);
|
||||||
rem = vdm.significand << (65 - shift);
|
rem = vdm.significand << (65 - shift);
|
||||||
|
|
||||||
if (rmode == FPSCR_ROUND_NEAREST) {
|
if (rmode == FPSCR_ROUND_NEAREST) {
|
||||||
@ -660,8 +831,8 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
|
|||||||
|
|
||||||
if ((rem + incr) < rem && d < 0xffffffff)
|
if ((rem + incr) < rem && d < 0xffffffff)
|
||||||
d += 1;
|
d += 1;
|
||||||
if (d > 0x7fffffff + (vdm.sign != 0)) {
|
if (d > (0x7fffffff + (vdm.sign != 0))) {
|
||||||
d = 0x7fffffff + (vdm.sign != 0);
|
d = (0x7fffffff + (vdm.sign != 0));
|
||||||
exceptions |= FPSCR_IOC;
|
exceptions |= FPSCR_IOC;
|
||||||
} else if (rem)
|
} else if (rem)
|
||||||
exceptions |= FPSCR_IXC;
|
exceptions |= FPSCR_IXC;
|
||||||
@ -768,16 +939,14 @@ vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||||||
return exceptions;
|
return exceptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32
|
u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr)
|
||||||
vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
|
|
||||||
struct vfp_double *vdm, u32 fpscr)
|
|
||||||
{
|
{
|
||||||
u32 exp_diff;
|
u32 exp_diff;
|
||||||
u64 m_sig;
|
u64 m_sig;
|
||||||
|
|
||||||
if (vdn->significand & (1ULL << 63) ||
|
if (vdn->significand & (1ULL << 63) ||
|
||||||
vdm->significand & (1ULL << 63)) {
|
vdm->significand & (1ULL << 63)) {
|
||||||
pr_info("VFP: bad FP values\n");
|
pr_info("VFP: bad FP values in %s\n", __func__);
|
||||||
vfp_double_dump("VDN", vdn);
|
vfp_double_dump("VDN", vdn);
|
||||||
vfp_double_dump("VDM", vdm);
|
vfp_double_dump("VDM", vdm);
|
||||||
}
|
}
|
||||||
@ -833,7 +1002,7 @@ vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32
|
u32
|
||||||
vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
|
vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
|
||||||
struct vfp_double *vdm, u32 fpscr)
|
struct vfp_double *vdm, u32 fpscr)
|
||||||
{
|
{
|
||||||
@ -895,7 +1064,7 @@ vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
|
|||||||
#define NEG_SUBTRACT (1 << 1)
|
#define NEG_SUBTRACT (1 << 1)
|
||||||
|
|
||||||
static u32
|
static u32
|
||||||
vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func)
|
vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func)
|
||||||
{
|
{
|
||||||
struct vfp_double vdd, vdp, vdn, vdm;
|
struct vfp_double vdd, vdp, vdn, vdm;
|
||||||
u32 exceptions;
|
u32 exceptions;
|
||||||
@ -1136,29 +1305,29 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
|
|||||||
}
|
}
|
||||||
return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
|
return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
|
||||||
|
|
||||||
vdn_nan:
|
vdn_nan:
|
||||||
exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
|
exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
|
||||||
pack:
|
pack:
|
||||||
vfp_put_double(state, vfp_double_pack(&vdd), dd);
|
vfp_put_double(state, vfp_double_pack(&vdd), dd);
|
||||||
return exceptions;
|
return exceptions;
|
||||||
|
|
||||||
vdm_nan:
|
vdm_nan:
|
||||||
exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
|
exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
zero:
|
zero:
|
||||||
vdd.exponent = 0;
|
vdd.exponent = 0;
|
||||||
vdd.significand = 0;
|
vdd.significand = 0;
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
divzero:
|
divzero:
|
||||||
exceptions = FPSCR_DZC;
|
exceptions = FPSCR_DZC;
|
||||||
infinity:
|
infinity:
|
||||||
vdd.exponent = 2047;
|
vdd.exponent = 2047;
|
||||||
vdd.significand = 0;
|
vdd.significand = 0;
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
invalid:
|
invalid:
|
||||||
vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
|
vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
|
||||||
return FPSCR_IOC;
|
return FPSCR_IOC;
|
||||||
}
|
}
|
||||||
@ -1258,6 +1427,6 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||||||
}
|
}
|
||||||
return exceptions;
|
return exceptions;
|
||||||
|
|
||||||
invalid:
|
invalid:
|
||||||
return ~0;
|
return ~0;
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,9 @@
|
|||||||
#include "core/arm/skyeye_common/vfp/vfp.h"
|
#include "core/arm/skyeye_common/vfp/vfp.h"
|
||||||
|
|
||||||
static struct vfp_single vfp_single_default_qnan = {
|
static struct vfp_single vfp_single_default_qnan = {
|
||||||
//.exponent = 255,
|
255,
|
||||||
//.sign = 0,
|
0,
|
||||||
//.significand = VFP_SINGLE_SIGNIFICAND_QNAN,
|
VFP_SINGLE_SIGNIFICAND_QNAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vfp_single_dump(const char *str, struct vfp_single *s)
|
static void vfp_single_dump(const char *str, struct vfp_single *s)
|
||||||
@ -69,7 +69,7 @@ static void vfp_single_dump(const char *str, struct vfp_single *s)
|
|||||||
|
|
||||||
static void vfp_single_normalise_denormal(struct vfp_single *vs)
|
static void vfp_single_normalise_denormal(struct vfp_single *vs)
|
||||||
{
|
{
|
||||||
int bits = 31 - vfp_fls(vs->significand);
|
int bits = 31 - fls(vs->significand);
|
||||||
|
|
||||||
vfp_single_dump("normalise_denormal: in", vs);
|
vfp_single_dump("normalise_denormal: in", vs);
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
|
|||||||
* bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
|
* bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
|
||||||
* significant bit.
|
* significant bit.
|
||||||
*/
|
*/
|
||||||
shift = 32 - vfp_fls(significand);
|
shift = 32 - fls(significand);
|
||||||
if (shift < 32 && shift) {
|
if (shift < 32 && shift) {
|
||||||
exponent -= shift;
|
exponent -= shift;
|
||||||
significand <<= shift;
|
significand <<= shift;
|
||||||
@ -205,7 +205,7 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
|
|||||||
vs->significand = significand >> 1;
|
vs->significand = significand >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pack:
|
pack:
|
||||||
vfp_single_dump("pack: final", vs);
|
vfp_single_dump("pack: final", vs);
|
||||||
{
|
{
|
||||||
s32 d = vfp_single_pack(vs);
|
s32 d = vfp_single_pack(vs);
|
||||||
@ -321,7 +321,7 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
|
|||||||
{
|
{
|
||||||
u64 v = (u64)a << 31;
|
u64 v = (u64)a << 31;
|
||||||
do_div(v, z);
|
do_div(v, z);
|
||||||
return v + (z >> 1);
|
return (u32)(v + (z >> 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,11 +338,11 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||||||
if (tm & VFP_NAN)
|
if (tm & VFP_NAN)
|
||||||
ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
|
ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
|
||||||
else if (vsm.sign == 0) {
|
else if (vsm.sign == 0) {
|
||||||
sqrt_copy:
|
sqrt_copy:
|
||||||
vsp = &vsm;
|
vsp = &vsm;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
sqrt_invalid:
|
sqrt_invalid:
|
||||||
vsp = &vfp_single_default_qnan;
|
vsp = &vfp_single_default_qnan;
|
||||||
ret = FPSCR_IOC;
|
ret = FPSCR_IOC;
|
||||||
}
|
}
|
||||||
@ -491,6 +491,47 @@ static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32
|
|||||||
return vfp_compare(state, sd, 1, 0, fpscr);
|
return vfp_compare(state, sd, 1, 0, fpscr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only
|
||||||
|
{
|
||||||
|
struct vfp_single vsm;
|
||||||
|
struct vfp_double vdd;
|
||||||
|
int tm;
|
||||||
|
u32 exceptions = 0;
|
||||||
|
|
||||||
|
vfp_single_unpack(&vsm, m);
|
||||||
|
|
||||||
|
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);
|
||||||
|
pack_nan:
|
||||||
|
vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd");
|
||||||
|
return vfp_double_pack(&vdd);
|
||||||
|
}
|
||||||
|
|
||||||
static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
|
static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
|
||||||
{
|
{
|
||||||
struct vfp_single vsm;
|
struct vfp_single vsm;
|
||||||
@ -529,7 +570,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f
|
|||||||
|
|
||||||
return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
|
return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
|
||||||
|
|
||||||
pack_nan:
|
pack_nan:
|
||||||
vfp_put_double(state, vfp_double_pack(&vdd), dd);
|
vfp_put_double(state, vfp_double_pack(&vdd), dd);
|
||||||
return exceptions;
|
return exceptions;
|
||||||
}
|
}
|
||||||
@ -684,14 +725,14 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
|
|||||||
|
|
||||||
if ((rem + incr) < rem && d < 0xffffffff)
|
if ((rem + incr) < rem && d < 0xffffffff)
|
||||||
d += 1;
|
d += 1;
|
||||||
if (d > 0x7fffffff + (vsm.sign != 0)) {
|
if (d > (0x7fffffffu + (vsm.sign != 0))) {
|
||||||
d = 0x7fffffff + (vsm.sign != 0);
|
d = (0x7fffffffu + (vsm.sign != 0));
|
||||||
exceptions |= FPSCR_IOC;
|
exceptions |= FPSCR_IOC;
|
||||||
} else if (rem)
|
} else if (rem)
|
||||||
exceptions |= FPSCR_IXC;
|
exceptions |= FPSCR_IXC;
|
||||||
|
|
||||||
if (vsm.sign)
|
if (vsm.sign)
|
||||||
d = -d;
|
d = 0-d;
|
||||||
} else {
|
} else {
|
||||||
d = 0;
|
d = 0;
|
||||||
if (vsm.exponent | vsm.significand) {
|
if (vsm.exponent | vsm.significand) {
|
||||||
@ -800,7 +841,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||||||
|
|
||||||
if (vsn->significand & 0x80000000 ||
|
if (vsn->significand & 0x80000000 ||
|
||||||
vsm->significand & 0x80000000) {
|
vsm->significand & 0x80000000) {
|
||||||
pr_info("VFP: bad FP values\n");
|
pr_info("VFP: bad FP values in %s\n", __func__);
|
||||||
vfp_single_dump("VSN", vsn);
|
vfp_single_dump("VSN", vsn);
|
||||||
vfp_single_dump("VSM", vsm);
|
vfp_single_dump("VSM", vsm);
|
||||||
}
|
}
|
||||||
@ -843,7 +884,7 @@ vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
|
|||||||
m_sig = vsn->significand - m_sig;
|
m_sig = vsn->significand - m_sig;
|
||||||
if ((s32)m_sig < 0) {
|
if ((s32)m_sig < 0) {
|
||||||
vsd->sign = vfp_sign_negate(vsd->sign);
|
vsd->sign = vfp_sign_negate(vsd->sign);
|
||||||
m_sig = -m_sig;
|
m_sig = 0-m_sig;
|
||||||
} else if (m_sig == 0) {
|
} else if (m_sig == 0) {
|
||||||
vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
|
vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
|
||||||
FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
|
||||||
@ -917,12 +958,16 @@ vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_s
|
|||||||
#define NEG_SUBTRACT (1 << 1)
|
#define NEG_SUBTRACT (1 << 1)
|
||||||
|
|
||||||
static u32
|
static u32
|
||||||
vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func)
|
vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
{
|
||||||
struct vfp_single vsd, vsp, vsn, vsm;
|
struct vfp_single vsd, vsp, vsn, vsm;
|
||||||
u32 exceptions;
|
u32 exceptions;
|
||||||
s32 v;
|
s32 v;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
v = vfp_get_float(state, sn);
|
v = vfp_get_float(state, sn);
|
||||||
pr_debug("VFP: s%u = %08x\n", sn, v);
|
pr_debug("VFP: s%u = %08x\n", sn, v);
|
||||||
vfp_single_unpack(&vsn, v);
|
vfp_single_unpack(&vsn, v);
|
||||||
@ -934,6 +979,7 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
|
|||||||
vfp_single_normalise_denormal(&vsm);
|
vfp_single_normalise_denormal(&vsm);
|
||||||
|
|
||||||
exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
|
exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
|
||||||
|
|
||||||
if (negate & NEG_MULTIPLY)
|
if (negate & NEG_MULTIPLY)
|
||||||
vsp.sign = vfp_sign_negate(vsp.sign);
|
vsp.sign = vfp_sign_negate(vsp.sign);
|
||||||
|
|
||||||
@ -946,6 +992,38 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
|
|||||||
exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
|
exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
|
||||||
|
|
||||||
return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
|
return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vfp_double vsd, vsp, vsn, vsm;
|
||||||
|
u32 exceptions;
|
||||||
|
s32 v;
|
||||||
|
s64 vd;
|
||||||
|
s64 md;
|
||||||
|
|
||||||
|
v = vfp_get_float(state, sn);
|
||||||
|
vd = vfp_single_to_doubleintern(state, v, fpscr);
|
||||||
|
vfp_double_unpack(&vsn, vd);
|
||||||
|
|
||||||
|
md = vfp_single_to_doubleintern(state, m, fpscr);
|
||||||
|
vfp_double_unpack(&vsm, md);
|
||||||
|
|
||||||
|
exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr);
|
||||||
|
if (negate & NEG_MULTIPLY)
|
||||||
|
vsp.sign = vfp_sign_negate(vsp.sign);
|
||||||
|
|
||||||
|
v = vfp_get_float(state, sd);
|
||||||
|
vd = vfp_single_to_doubleintern(state, v, fpscr);
|
||||||
|
vfp_double_unpack(&vsn, vd);
|
||||||
|
|
||||||
|
if (negate & NEG_SUBTRACT)
|
||||||
|
vsn.sign = vfp_sign_negate(vsn.sign);
|
||||||
|
|
||||||
|
exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr);
|
||||||
|
|
||||||
|
s64 debug = vfp_double_pack(&vsd);
|
||||||
|
|
||||||
|
return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1148,36 +1226,36 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
|
|||||||
{
|
{
|
||||||
u64 significand = (u64)vsn.significand << 32;
|
u64 significand = (u64)vsn.significand << 32;
|
||||||
do_div(significand, vsm.significand);
|
do_div(significand, vsm.significand);
|
||||||
vsd.significand = significand;
|
vsd.significand = (u32)significand;
|
||||||
}
|
}
|
||||||
if ((vsd.significand & 0x3f) == 0)
|
if ((vsd.significand & 0x3f) == 0)
|
||||||
vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
|
vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
|
||||||
|
|
||||||
return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
|
return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
|
||||||
|
|
||||||
vsn_nan:
|
vsn_nan:
|
||||||
exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
|
exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
|
||||||
pack:
|
pack:
|
||||||
vfp_put_float(state, vfp_single_pack(&vsd), sd);
|
vfp_put_float(state, vfp_single_pack(&vsd), sd);
|
||||||
return exceptions;
|
return exceptions;
|
||||||
|
|
||||||
vsm_nan:
|
vsm_nan:
|
||||||
exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
|
exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
zero:
|
zero:
|
||||||
vsd.exponent = 0;
|
vsd.exponent = 0;
|
||||||
vsd.significand = 0;
|
vsd.significand = 0;
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
divzero:
|
divzero:
|
||||||
exceptions = FPSCR_DZC;
|
exceptions = FPSCR_DZC;
|
||||||
infinity:
|
infinity:
|
||||||
vsd.exponent = 255;
|
vsd.exponent = 255;
|
||||||
vsd.significand = 0;
|
vsd.significand = 0;
|
||||||
goto pack;
|
goto pack;
|
||||||
|
|
||||||
invalid:
|
invalid:
|
||||||
vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
|
vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
|
||||||
return FPSCR_IOC;
|
return FPSCR_IOC;
|
||||||
}
|
}
|
||||||
@ -1273,6 +1351,6 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
|
|||||||
}
|
}
|
||||||
return exceptions;
|
return exceptions;
|
||||||
|
|
||||||
invalid:
|
invalid:
|
||||||
return (u32)-1;
|
return (u32)-1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user