uint32_t u[2];
} s;
} u;
- int i;
+ int i, rnd_type;
u.d = FT0;
if (mask & 0x80)
switch (env->fpscr[0] & 0x3) {
case 0:
/* Best approximation (round to nearest) */
- fesetround(FE_TONEAREST);
+ rnd_type = float_round_nearest_even;
break;
case 1:
/* Smaller magnitude (round toward zero) */
- fesetround(FE_TOWARDZERO);
+ rnd_type = float_round_to_zero;
break;
case 2:
/* Round toward +infinite */
- fesetround(FE_UPWARD);
+ rnd_type = float_round_up;
break;
+ default:
case 3:
/* Round toward -infinite */
- fesetround(FE_DOWNWARD);
+ rnd_type = float_round_down;
break;
}
+ set_float_rounding_mode(rnd_type, &env->fp_status);
}
void do_fctiw (void)
union {
double d;
uint64_t i;
- } *p = (void *)&FT1;
+ } p;
- if (FT0 > (double)0x7FFFFFFF)
- p->i = 0x7FFFFFFFULL << 32;
- else if (FT0 < -(double)0x80000000)
- p->i = 0x80000000ULL << 32;
- else
- p->i = 0;
- p->i |= (uint32_t)FT0;
- FT0 = p->d;
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PPC 750 (aka G3)
+ */
+ p.i = float64_to_int32(FT0, &env->fp_status);
+ p.i |= 0xFFF80000ULL << 32;
+ FT0 = p.d;
}
void do_fctiwz (void)
union {
double d;
uint64_t i;
- } *p = (void *)&FT1;
- int cround = fegetround();
-
- fesetround(FE_TOWARDZERO);
- if (FT0 > (double)0x7FFFFFFF)
- p->i = 0x7FFFFFFFULL << 32;
- else if (FT0 < -(double)0x80000000)
- p->i = 0x80000000ULL << 32;
- else
- p->i = 0;
- p->i |= (uint32_t)FT0;
- FT0 = p->d;
- fesetround(cround);
+ } p;
+
+ /* XXX: higher bits are not supposed to be significant.
+ * to make tests easier, return the same as a real PPC 750 (aka G3)
+ */
+ p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
+ p.i |= 0xFFF80000ULL << 32;
+ FT0 = p.d;
}
void do_fnmadd (void)
{
- FT0 = -((FT0 * FT1) + FT2);
+ FT0 = (FT0 * FT1) + FT2;
+ if (!isnan(FT0))
+ FT0 = -FT0;
}
void do_fnmsub (void)
{
- FT0 = -((FT0 * FT1) - FT2);
+ FT0 = (FT0 * FT1) - FT2;
+ if (!isnan(FT0))
+ FT0 = -FT0;
}
-void do_fnmadds (void)
+void do_fdiv (void)
{
- FT0 = -((FTS0 * FTS1) + FTS2);
-}
-
-void do_fnmsubs (void)
-{
- FT0 = -((FTS0 * FTS1) - FTS2);
+ if (FT0 == -0.0 && FT1 == -0.0)
+ FT0 = 0.0 / 0.0;
+ else
+ FT0 /= FT1;
}
void do_fsqrt (void)
FT0 = sqrt(FT0);
}
-void do_fsqrts (void)
-{
- FT0 = (float)sqrt((float)FT0);
-}
-
void do_fres (void)
{
- FT0 = 1.0 / FT0;
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ if (isnormal(FT0)) {
+ FT0 = (float)(1.0 / FT0);
+ } else {
+ p.d = FT0;
+ if (p.i == 0x8000000000000000ULL) {
+ p.i = 0xFFF0000000000000ULL;
+ } else if (p.i == 0x0000000000000000ULL) {
+ p.i = 0x7FF0000000000000ULL;
+ } else if (isnan(FT0)) {
+ p.i = 0x7FF8000000000000ULL;
+ } else if (FT0 < 0.0) {
+ p.i = 0x8000000000000000ULL;
+ } else {
+ p.i = 0x0000000000000000ULL;
+ }
+ FT0 = p.d;
+ }
}
-void do_fsqrte (void)
+void do_frsqrte (void)
{
- FT0 = 1.0 / sqrt(FT0);
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ if (isnormal(FT0) && FT0 > 0.0) {
+ FT0 = (float)(1.0 / sqrt(FT0));
+ } else {
+ p.d = FT0;
+ if (p.i == 0x8000000000000000ULL) {
+ p.i = 0xFFF0000000000000ULL;
+ } else if (p.i == 0x0000000000000000ULL) {
+ p.i = 0x7FF0000000000000ULL;
+ } else if (isnan(FT0)) {
+ if (!(p.i & 0x0008000000000000ULL))
+ p.i |= 0x000FFFFFFFFFFFFFULL;
+ } else if (FT0 < 0) {
+ p.i = 0x7FF8000000000000ULL;
+ } else {
+ p.i = 0x0000000000000000ULL;
+ }
+ FT0 = p.d;
+ }
}
void do_fsel (void)
{
if (FT0 >= 0)
- FT0 = FT2;
- else
FT0 = FT1;
+ else
+ FT0 = FT2;
}
void do_fcmpu (void)
void do_fabs (void)
{
- FT0 = fabsl(FT0);
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.d = FT0;
+ p.i &= ~0x8000000000000000ULL;
+ FT0 = p.d;
}
void do_fnabs (void)
{
- FT0 = -fabsl(FT0);
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.d = FT0;
+ p.i |= 0x8000000000000000ULL;
+ FT0 = p.d;
}
/* Instruction cache invalidation helper */
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (SH(ctx->opcode) != 0)
gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
if (Rc(ctx->opcode) != 0)
gen_op_set_Rc0();
__GEN_LOGICAL2(srw, 0x18, 0x10);
/*** Floating-Point arithmetic ***/
-#define _GEN_FLOAT_ACB(name, op1, op2) \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
if (!ctx->fpu_enabled) { \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
gen_op_load_fpr_FT2(rB(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_ACB(name, op2) \
-_GEN_FLOAT_ACB(name, 0x3F, op2); \
-_GEN_FLOAT_ACB(name##s, 0x3B, op2);
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
-#define _GEN_FLOAT_AB(name, op1, op2, inval) \
+#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
if (!ctx->fpu_enabled) { \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rB(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AB(name, op2, inval) \
-_GEN_FLOAT_AB(name, 0x3F, op2, inval); \
-_GEN_FLOAT_AB(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
+_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
-#define _GEN_FLOAT_AC(name, op1, op2, inval) \
+#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
if (!ctx->fpu_enabled) { \
gen_op_reset_scrfx(); \
gen_op_load_fpr_FT0(rA(ctx->opcode)); \
gen_op_load_fpr_FT1(rC(ctx->opcode)); \
- gen_op_f##name(); \
+ gen_op_f##op(); \
+ if (isfloat) { \
+ gen_op_frsp(); \
+ } \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
if (Rc(ctx->opcode)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AC(name, op2, inval) \
-_GEN_FLOAT_AC(name, 0x3F, op2, inval); \
-_GEN_FLOAT_AC(name##s, 0x3B, op2, inval);
+_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
+_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
#define GEN_FLOAT_B(name, op2, op3) \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
gen_op_set_Rc1(); \
}
-#define GEN_FLOAT_BS(name, op2) \
-GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
+#define GEN_FLOAT_BS(name, op1, op2) \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
{ \
if (!ctx->fpu_enabled) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
/* fadd - fadds */
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
-/* fdiv */
+/* fdiv - fdivs */
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
-/* fmul */
+/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
/* fres */
-GEN_FLOAT_BS(res, 0x18);
+GEN_FLOAT_BS(res, 0x3B, 0x18);
/* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x1A);
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
/* fsel */
-_GEN_FLOAT_ACB(sel, 0x3F, 0x17);
-/* fsub */
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
+/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
/* Optional: */
/* fsqrt */
-GEN_FLOAT_BS(sqrt, 0x16);
+GEN_FLOAT_BS(sqrt, 0x3F, 0x16);
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
}
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rB(ctx->opcode));
- gen_op_fsqrts();
+ gen_op_fsqrt();
+ gen_op_frsp();
gen_op_store_FT0_fpr(rD(ctx->opcode));
if (Rc(ctx->opcode))
gen_op_set_Rc1();
}
/*** Floating-Point multiply-and-add ***/
-/* fmadd */
+/* fmadd - fmadds */
GEN_FLOAT_ACB(madd, 0x1D);
-/* fmsub */
+/* fmsub - fmsubs */
GEN_FLOAT_ACB(msub, 0x1C);
-/* fnmadd */
+/* fnmadd - fnmadds */
GEN_FLOAT_ACB(nmadd, 0x1F);
-/* fnmsub */
+/* fnmsub - fnmsubs */
GEN_FLOAT_ACB(nmsub, 0x1E);
/*** Floating-Point round & convert ***/
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_set_T0(simm); \
} else { \
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
RET_INVAL(ctx); \
#define GEN_LDUXF(width, opc) \
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0 || \
rA(ctx->opcode) == rD(ctx->opcode)) { \
RET_INVAL(ctx); \
#define GEN_LDXF(width, opc2, opc3) \
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
} else { \
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_set_T0(simm); \
} else { \
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
{ \
uint32_t simm = SIMM(ctx->opcode); \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
RET_INVAL(ctx); \
return; \
#define GEN_STUXF(width, opc) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
RET_INVAL(ctx); \
return; \
#define GEN_STXF(width, opc2, opc3) \
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
{ \
+ if (!ctx->fpu_enabled) { \
+ RET_EXCP(ctx, EXCP_NO_FP, 0); \
+ return; \
+ } \
if (rA(ctx->opcode) == 0) { \
gen_op_load_gpr_T0(rB(ctx->opcode)); \
} else { \