2
1
Fork 0
mirror of https://github.com/yuzu-emu/yuzu.git synced 2024-07-04 23:31:19 +01:00

ARM: Merge latest VFP fixes from 3dmoo team.

This commit is contained in:
bunnei 2014-10-29 22:25:54 -04:00
parent 2ca12e7f38
commit bc6989b075
4 changed files with 2161 additions and 1869 deletions

View file

@ -28,230 +28,270 @@
#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
VFPInit (ARMul_State *state) VFPInit (ARMul_State *state)
{ {
state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | 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; VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
//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 */
int OPC_1 = BITS (21, 23); int OPC_1 = BITS (21, 23);
int Rt = BITS (12, 15); int Rt = BITS (12, 15);
int CRn = BITS (16, 19); int CRn = BITS (16, 19);
int CRm = BITS (0, 3); int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7); int OPC_2 = BITS (5, 7);
/* 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_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("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
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);
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 */
int OPC_1 = BITS (21, 23); int OPC_1 = BITS (21, 23);
int Rt = BITS (12, 15); int Rt = BITS (12, 15);
int CRn = BITS (16, 19); int CRn = BITS (16, 19);
int CRm = BITS (0, 3); int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7); int OPC_2 = BITS (5, 7);
/* 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("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
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);
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 */
int OPC_1 = BITS (4, 7); int OPC_1 = BITS (4, 7);
int Rt = BITS (12, 15); int Rt = BITS (12, 15);
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("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
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);
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 */
int OPC_1 = BITS (4, 7); int OPC_1 = BITS (4, 7);
int Rt = BITS (12, 15); int Rt = BITS (12, 15);
int Rt2 = BITS (16, 19); int Rt2 = BITS (16, 19);
int CRm = BITS (0, 3); int CRm = BITS (0, 3);
/* TODO check access permission */ /* TODO check access permission */
/* 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("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
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);
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 */
int CRd = BITS (12, 15); int CRd = BITS (12, 15);
int Rn = BITS (16, 19); int Rn = BITS (16, 19);
int imm8 = BITS (0, 7); int imm8 = BITS (0, 7);
int P = BIT(24); int P = BIT(24);
int U = BIT(23); int U = BIT(23);
int D = BIT(22); int D = BIT(22);
int W = BIT(21); int W = BIT(21);
/* 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");
{ exit(-1);
DEBUG_LOG(ARM11, "UNDEFINED\n"); 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 */
int CRd = BITS (12, 15); int CRd = BITS (12, 15);
int Rn = BITS (16, 19); int Rn = BITS (16, 19);
int imm8 = BITS (0, 7); int imm8 = BITS (0, 7);
int P = BIT(24); int P = BIT(24);
int U = BIT(23); int U = BIT(23);
int D = BIT(22); int D = BIT(22);
int W = BIT(21); int W = BIT(21);
/* 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("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
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);
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 */
int OPC_1 = BITS (20, 23); int OPC_1 = BITS (20, 23);
int CRd = BITS (12, 15); int CRd = BITS (12, 15);
int CRn = BITS (16, 19); int CRn = BITS (16, 19);
int CRm = BITS (0, 3); int CRm = BITS (0, 3);
int OPC_2 = BITS (5, 7); int OPC_2 = BITS (5, 7);
/* TODO check access permission */ //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;
}*/
/* CRn/opc1 CRm/opc2 */ /* TODO check access permission */
if (CoProc == 10 || CoProc == 11) /* CRn/opc1 CRm/opc2 */
{
#define VFP_CDP_TRANS
#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_CDP_TRANS
int exceptions = 0; if (CoProc == 10 || CoProc == 11) {
if (CoProc == 10) #define VFP_CDP_TRANS
exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
else #undef VFP_CDP_TRANS
exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); 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)]);
return ARMul_DONE; vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
}
DEBUG_LOG(ARM11, "Can't identify %x\n", instr); return ARMul_DONE;
return ARMul_CANT; }
DEBUG("Can't identify %x\n", instr);
return ARMul_CANT;
} }
@ -301,29 +341,29 @@ 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;
} }
uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) 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);
} }
@ -333,25 +373,25 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
*/ */
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
{ {
int si_code = 0; int si_code = 0;
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;
} }
/* /*
* If any of the status flags are set, update the FPSCR. * If any of the status flags are set, update the FPSCR.
* Comparison instructions always return at least one of * Comparison instructions always return at least one of
* these flags set. * these flags set.
*/ */
if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
fpscr |= exceptions; fpscr |= exceptions;
state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
} }

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff