From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1D2U4t-00082L-Tq for qemu-devel@nongnu.org; Sat, 19 Feb 2005 07:51:20 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1D2U4O-0007rt-Ja for qemu-devel@nongnu.org; Sat, 19 Feb 2005 07:51:16 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1D2U4O-0007mW-CT for qemu-devel@nongnu.org; Sat, 19 Feb 2005 07:50:48 -0500 Received: from [62.210.158.41] (helo=moscou.magic.fr) by monty-python.gnu.org with esmtp (Exim 4.34) id 1D2Taw-0005xU-2n for qemu-devel@nongnu.org; Sat, 19 Feb 2005 07:20:22 -0500 From: "J. Mayer" Content-Type: multipart/mixed; boundary="=-KT/wFPLZiqNJI5Fif/mt" Message-Id: <1108815616.21864.4627.camel@rapid> Mime-Version: 1.0 Date: Sat, 19 Feb 2005 13:20:16 +0100 Subject: [Qemu-devel] PPC floating point fixes Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --=-KT/wFPLZiqNJI5Fif/mt Content-Type: text/plain Content-Transfer-Encoding: 7bit I did some systematic tests on PPC FPU emulation. Then, I found some bugs: - single-precision operations are to be done in double precision, then rounded to single precision. - Make fctiw & fctiwz return the values a real G3 does - Sign was false for fabs/fnabs whith +/- 0.0 operand - fsel operands were interverted - fres major opcode is 0x3B, not 0x3F It also appears that most FPU flags are wrong, even when flag updates are explicitely wanted (using '.' opcode) so more fixes will come soon. -- J. Mayer Never organized --=-KT/wFPLZiqNJI5Fif/mt Content-Disposition: attachment; filename=ppc_float_fixes.diff Content-Type: text/x-patch; name=ppc_float_fixes.diff; charset=ISO-8859-15 Content-Transfer-Encoding: 7bit Index: exec.h =================================================================== RCS file: /cvsroot/qemu/qemu/target-ppc/exec.h,v retrieving revision 1.9 diff -u -d -w -B -b -d -p -r1.9 exec.h --- exec.h 3 Jan 2005 23:42:39 -0000 1.9 +++ exec.h 18 Feb 2005 21:12:08 -0000 @@ -32,9 +32,6 @@ register uint32_t T2 asm(AREG3); #define FT0 (env->ft0) #define FT1 (env->ft1) #define FT2 (env->ft2) -#define FTS0 ((float)env->ft0) -#define FTS1 ((float)env->ft1) -#define FTS2 ((float)env->ft2) #if defined (DEBUG_OP) #define RETURN() __asm__ __volatile__("nop"); @@ -146,8 +143,6 @@ void do_fsqrte (void); void do_fsel (void); void do_fcmpu (void); void do_fcmpo (void); -void do_fabs (void); -void do_fnabs (void); void do_check_reservation (void); void do_icbi (void); Index: op.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-ppc/op.c,v retrieving revision 1.15 diff -u -d -w -B -b -d -p -r1.15 op.c --- op.c 15 Feb 2005 23:06:19 -0000 1.15 +++ op.c 18 Feb 2005 21:12:09 -0000 @@ -32,10 +32,6 @@ #define FT1 (env->ft1) #define FT2 (env->ft2) -#define FTS0 ((float)env->ft0) -#define FTS1 ((float)env->ft1) -#define FTS2 ((float)env->ft2) - #define PPC_OP(name) void glue(op_, name)(void) #define REG 0 @@ -1207,7 +1203,7 @@ PPC_OP(fadd) /* fadds - fadds. */ PPC_OP(fadds) { - FT0 = FTS0 + FTS1; + FT0 = (float)(FT0 + FT1); RETURN(); } @@ -1221,7 +1217,7 @@ PPC_OP(fsub) /* fsubs - fsubs. */ PPC_OP(fsubs) { - FT0 = FTS0 - FTS1; + FT0 = (float)(FT0 - FT1); RETURN(); } @@ -1235,21 +1231,23 @@ PPC_OP(fmul) /* fmuls - fmuls. */ PPC_OP(fmuls) { - FT0 = FTS0 * FTS1; + FT0 = (float)(FT0 * FT1); RETURN(); } /* fdiv - fdiv. */ +void do_fdiv (void); PPC_OP(fdiv) { - FT0 /= FT1; + do_fdiv(); RETURN(); } /* fdivs - fdivs. */ +void do_fdivs (void); PPC_OP(fdivs) { - FT0 = FTS0 / FTS1; + do_fdivs(); RETURN(); } @@ -1299,7 +1297,7 @@ PPC_OP(fmadd) /* fmadds - fmadds. */ PPC_OP(fmadds) { - FT0 = (FTS0 * FTS1) + FTS2; + FT0 = (float)((FT0 * FT1) + FT2); RETURN(); } @@ -1313,7 +1311,7 @@ PPC_OP(fmsub) /* fmsubs - fmsubs. */ PPC_OP(fmsubs) { - FT0 = (FTS0 * FTS1) - FTS2; + FT0 = (float)((FT0 * FT1) - FT2); RETURN(); } @@ -1385,6 +1382,7 @@ PPC_OP(fcmpo) /*** Floating-point move ***/ /* fabs */ +void do_fabs (void); PPC_OP(fabs) { do_fabs(); @@ -1392,6 +1390,7 @@ PPC_OP(fabs) } /* fnabs */ +void do_fnabs (void); PPC_OP(fnabs) { do_fnabs(); Index: op_helper.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-ppc/op_helper.c,v retrieving revision 1.11 diff -u -d -w -B -b -d -p -r1.11 op_helper.c --- op_helper.c 15 Feb 2005 23:06:19 -0000 1.11 +++ op_helper.c 18 Feb 2005 21:12:09 -0000 @@ -249,16 +249,21 @@ void do_fctiw (void) union { double d; uint64_t i; - } *p = (void *)&FT1; + } 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 = 0xFFF80000ULL << 32; if (FT0 > (double)0x7FFFFFFF) - p->i = 0x7FFFFFFFULL << 32; + p.i |= 0x7FFFFFFFULL; else if (FT0 < -(double)0x80000000) - p->i = 0x80000000ULL << 32; + p.i |= 0x80000000ULL; + else if (FT0 < 0.0 || FT0 == -0.0) + p.i |= 0x100000000ULL | (uint32_t)FT0; else - p->i = 0; - p->i |= (uint32_t)FT0; - FT0 = p->d; + p.i |= (uint32_t)FT0; + FT0 = p.d; } void do_fctiwz (void) @@ -266,18 +271,23 @@ void do_fctiwz (void) union { double d; uint64_t i; - } *p = (void *)&FT1; + } p; int cround = fegetround(); + /* 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 = 0xFFF80000ULL << 32; fesetround(FE_TOWARDZERO); if (FT0 > (double)0x7FFFFFFF) - p->i = 0x7FFFFFFFULL << 32; + p.i |= 0x7FFFFFFFULL; else if (FT0 < -(double)0x80000000) - p->i = 0x80000000ULL << 32; + p.i |= 0x80000000ULL; + else if (FT0 < 0.0 || FT0 == -0.0) + p.i |= 0x100000000ULL | (uint32_t)FT0; else - p->i = 0; - p->i |= (uint32_t)FT0; - FT0 = p->d; + p.i |= (uint32_t)FT0; + FT0 = p.d; fesetround(cround); } @@ -293,12 +303,28 @@ void do_fnmsub (void) void do_fnmadds (void) { - FT0 = -((FTS0 * FTS1) + FTS2); + FT0 = (float)(-((FT0 * FT1) + FT2)); } void do_fnmsubs (void) { - FT0 = -((FTS0 * FTS1) - FTS2); + FT0 = (float)(-((FT0 * FT1) - FT2)); +} + +void do_fdiv (void) +{ + if (FT0 == -0.0 && FT1 == -0.0) + FT0 = 0.0 / 0.0; + else + FT0 /= FT1; +} + +void do_fdivs (void) +{ + if (FT0 == -0.0 && FT1 == -0.0) + FT0 = (float)(0.0 / 0.0); + else + FT0 = (float)(FT0 / FT1); } void do_fsqrt (void) @@ -308,12 +334,12 @@ void do_fsqrt (void) void do_fsqrts (void) { - FT0 = (float)sqrt((float)FT0); + FT0 = (float)sqrt(FT0); } void do_fres (void) { - FT0 = 1.0 / FT0; + FT0 = (float)(1.0 / FT0); } void do_fsqrte (void) @@ -324,9 +350,9 @@ void do_fsqrte (void) void do_fsel (void) { if (FT0 >= 0) - FT0 = FT2; - else FT0 = FT1; + else + FT0 = FT2; } void do_fcmpu (void) @@ -371,12 +397,18 @@ void do_fcmpo (void) void do_fabs (void) { - FT0 = fabsl(FT0); + if (FT0 == -0.0) + FT0 = +0.0; + else if (FT0 < 0.0) + FT0 = -FT0; } void do_fnabs (void) { - FT0 = -fabsl(FT0); + if (FT0 == +0.0) + FT0 = -0.0; + else if (FT0 >= +0.0) + FT0 = -FT0; } /* Instruction cache invalidation helper */ Index: translate.c =================================================================== RCS file: /cvsroot/qemu/qemu/target-ppc/translate.c,v retrieving revision 1.27 diff -u -d -w -B -b -d -p -r1.27 translate.c --- translate.c 15 Feb 2005 23:06:19 -0000 1.27 +++ translate.c 18 Feb 2005 21:12:10 -0000 @@ -823,8 +823,8 @@ GEN_HANDLER(f##name, 0x3F, op2, op3, 0x0 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); \ @@ -846,10 +846,10 @@ GEN_FLOAT_AB(div, 0x12, 0x000007C0); 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); @@ -857,7 +857,7 @@ _GEN_FLOAT_ACB(sel, 0x3F, 0x17); 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) { --=-KT/wFPLZiqNJI5Fif/mt--