qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
@ 2007-04-05 19:16 Aurelien Jarno
  2007-04-06  6:22 ` Blue Swirl
  2007-04-06  6:47 ` Blue Swirl
  0 siblings, 2 replies; 5+ messages in thread
From: Aurelien Jarno @ 2007-04-05 19:16 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1441 bytes --]

Hi,

The attached patch fully implements IEEE exceptions on the SPARC target.
Some more details:
 - Any floating point operation that does not trap should clear the ftt
   flags. Similary, any floating point operation that does not generate
   an IEEE exception should clear the cexec flags. In the patch this
   operation is actually done at the same place before emulating the 
   instruction via op_clear_ieee_excp_and_FTT, and set back to the 
   correct value in the unlikely case of a trap.
 - To compute the IEEE flags, and to trap if needed, every floating point
   instruction that can generate a trap is precedeed by a clear of the 
   IEEE flags of the softmmu functions. After the instruction, the 
   check_ieee_exceptions function copies the softmmu flags into the FSR 
   flags (aexec, cexec), and if the corresponding TEM flag is set, a trap
   is generated.
 - GEN_FCMP has to set the FSR_NVC flag, and should set the ftt flags
   to IEEE_754_exception.
 - This patch also correctly implements the fcmpes and fcmped instructions
   by adding a sixth parameter. If this parameter is set, the comparaison
   generates a trap for unordered relations even if FSR_NVM is not set.

Bye,
Aurelien

-- 
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   aurel32@debian.org         | aurelien@aurel32.net
   `-    people.debian.org/~aurel32 | www.aurel32.net

[-- Attachment #2: sparc-qemu-ieee_exceptions.diff --]
[-- Type: text/x-diff, Size: 11365 bytes --]

diff -u -d -p -r1.17 exec.h
--- qemu.orig/target-sparc/exec.h	19 Mar 2007 14:47:40 -0000	1.17
+++ qemu/target-sparc/exec.h	5 Apr 2007 18:46:48 -0000
@@ -61,6 +61,8 @@ void do_fsqrts(void);
 void do_fsqrtd(void);
 void do_fcmps(void);
 void do_fcmpd(void);
+void do_fcmpes(void);
+void do_fcmped(void);
 #ifdef TARGET_SPARC64
 void do_fabsd(void);
 void do_fcmps_fcc1(void);
@@ -69,6 +71,12 @@ void do_fcmps_fcc2(void);
 void do_fcmpd_fcc2(void);
 void do_fcmps_fcc3(void);
 void do_fcmpd_fcc3(void);
+void do_fcmpes_fcc1(void);
+void do_fcmped_fcc1(void);
+void do_fcmpes_fcc2(void);
+void do_fcmped_fcc2(void);
+void do_fcmpes_fcc3(void);
+void do_fcmped_fcc3(void);
 void do_popc();
 void do_wrpstate();
 void do_done();
@@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr);
 void do_ldd_raw(target_ulong addr);
 void do_interrupt(int intno);
 void raise_exception(int tt);
+void check_ieee_exceptions();
 void memcpy32(target_ulong *dst, const target_ulong *src);
 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
 void dump_mmu(CPUState *env);
diff -u -d -p -r1.27 op.c
--- qemu.orig/target-sparc/op.c	1 Apr 2007 15:38:17 -0000	1.27
+++ qemu/target-sparc/op.c	5 Apr 2007 18:46:48 -0000
@@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void)
     helper_flush(T0);
 }
 
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
+{
+    env->fsr &= ~(FSR_FTT_MASK | FSR_CEXEC_MASK);;
+}
+
 #define F_OP(name, p) void OPPROTO op_f##name##p(void)
 
 #define F_BINOP(name)                                           \
     F_OP(name, s)                                               \
     {                                                           \
+	set_float_exception_flags(0, &env->fp_status);		\
         FT0 = float32_ ## name (FT0, FT1, &env->fp_status);     \
+	check_ieee_exceptions();				\
     }                                                           \
     F_OP(name, d)                                               \
     {                                                           \
+	set_float_exception_flags(0, &env->fp_status);		\
         DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+	check_ieee_exceptions();				\
     }
 
 F_BINOP(add);
@@ -1554,9 +1563,11 @@ F_BINOP(div);
 
 void OPPROTO op_fsmuld(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
                       float32_to_float64(FT1, &env->fp_status),
                       &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #define F_HELPER(name)    \
@@ -1582,6 +1593,7 @@ F_OP(abs, s)
 }
 
 F_HELPER(cmp);
+F_HELPER(cmpe);
 
 #ifdef TARGET_SPARC64
 F_OP(neg, d)
@@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void)
 {
     do_fcmpd_fcc3();
 }
+
+void OPPROTO op_fcmpes_fcc1(void)
+{
+    do_fcmpes_fcc1();
+}
+
+void OPPROTO op_fcmped_fcc1(void)
+{
+    do_fcmped_fcc1();
+}
+
+void OPPROTO op_fcmpes_fcc2(void)
+{
+    do_fcmpes_fcc2();
+}
+
+void OPPROTO op_fcmped_fcc2(void)
+{
+    do_fcmped_fcc2();
+}
+
+void OPPROTO op_fcmpes_fcc3(void)
+{
+    do_fcmpes_fcc3();
+}
+
+void OPPROTO op_fcmped_fcc3(void)
+{
+    do_fcmped_fcc3();
+}
+
 #endif
 
 /* Integer to float conversion.  */
@@ -1631,23 +1674,31 @@ F_HELPER(ito);
 #else
 F_OP(ito, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(ito, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 F_OP(xto, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(xto, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 #endif
 #endif
@@ -1656,34 +1707,46 @@ F_OP(xto, d)
 /* floating point conversion */
 void OPPROTO op_fdtos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float64_to_float32(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fstod(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float32_to_float64(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 /* Float to integer conversion.  */
 void OPPROTO op_fstoi(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtoi(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 void OPPROTO op_fstox(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtox(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fmovs_cc(void)
diff -u -d -p -r1.23 op_helper.c
--- qemu.orig/target-sparc/op_helper.c	1 Apr 2007 15:15:36 -0000	1.23
+++ qemu/target-sparc/op_helper.c	5 Apr 2007 18:46:48 -0000
@@ -9,10 +9,43 @@ void raise_exception(int tt)
     cpu_loop_exit();
 }   
 
+void check_ieee_exceptions()
+{
+     T0 = get_float_exception_flags(&env->fp_status);
+     if (T0)
+     {
+	/* Copy IEEE 754 flags into FSR */
+	if (T0 & float_flag_invalid)
+	    env->fsr |= FSR_NVC;
+	if (T0 & float_flag_overflow)
+	    env->fsr |= FSR_OFC;
+	if (T0 & float_flag_underflow)
+	    env->fsr |= FSR_UFC;
+	if (T0 & float_flag_divbyzero)
+	    env->fsr |= FSR_DZC;
+	if (T0 & float_flag_inexact)
+	    env->fsr |= FSR_NXC;
+
+	if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
+	{
+	    /* Unmasked exception, generate a trap */
+	    env->fsr |= FSR_FTT_IEEE_EXCP;
+	    raise_exception(TT_FP_EXCP);
+	}
+	else
+	{
+	    /* Accumulate exceptions */
+	    env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+	}
+     }
+}
+
 #ifdef USE_INT_TO_FLOAT_HELPERS
 void do_fitos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fitod(void)
@@ -35,23 +68,29 @@ void do_fabsd(void)
 
 void do_fsqrts(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float32_sqrt(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fsqrtd(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_sqrt(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
-#define GEN_FCMP(name, size, reg1, reg2, FS)                            \
+#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
     void glue(do_, name) (void)                                         \
     {                                                                   \
         env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
             T0 = (FSR_FCC1 | FSR_FCC0) << FS;                           \
-            if (env->fsr & FSR_NVM) {                                   \
+            if ((env->fsr & FSR_NVM) || TRAP) {                         \
                 env->fsr |= T0;                                         \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
                 env->fsr |= FSR_NVA;                                    \
@@ -70,18 +109,30 @@ void do_fsqrtd(void)
         env->fsr |= T0;                                                 \
     }
 
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
+GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
 
 #ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
+GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
 
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
+GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
 
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
+GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+
+GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+
+GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+
+GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
 #endif
 
 #if defined(CONFIG_USER_ONLY) 
diff -u -d -p -r1.46 translate.c
--- qemu.orig/target-sparc/translate.c	5 Apr 2007 18:12:08 -0000	1.46
+++ qemu/target-sparc/translate.c	5 Apr 2007 18:46:49 -0000
@@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] = 
     gen_op_fcmpd_fcc2,
     gen_op_fcmpd_fcc3,
 };
+
+static GenOpFunc * const gen_fcmpes[4] = {
+    gen_op_fcmpes,
+    gen_op_fcmpes_fcc1,
+    gen_op_fcmpes_fcc2,
+    gen_op_fcmpes_fcc3,
+};
+
+static GenOpFunc * const gen_fcmped[4] = {
+    gen_op_fcmped,
+    gen_op_fcmped_fcc1,
+    gen_op_fcmped_fcc2,
+    gen_op_fcmped_fcc3,
+};
+
 #endif
 
 static int gen_trap_ifnofpu(DisasContext * dc)
@@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContex
 	    } else if (xop == 0x34) {	/* FPU Operations */
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+		gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
 	        rs2 = GET_FIELD(insn, 27, 31);
 	        xop = GET_FIELD(insn, 18, 26);
@@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContex
 #endif
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+		gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
 	        rs2 = GET_FIELD(insn, 27, 31);
 	        xop = GET_FIELD(insn, 18, 26);
@@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContex
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
 #ifdef TARGET_SPARC64
-			gen_fcmps[rd & 3]();
+			gen_fcmpes[rd & 3]();
 #else
-			gen_op_fcmps(); /* XXX should trap if qNaN or sNaN  */
+			gen_op_fcmpes();
 #endif
 			break;
 		    case 0x56: /* fcmped, V9 %fcc */
                 	gen_op_load_fpr_DT0(DFPREG(rs1));
                 	gen_op_load_fpr_DT1(DFPREG(rs2));
 #ifdef TARGET_SPARC64
-			gen_fcmpd[rd & 3]();
+			gen_fcmped[rd & 3]();
 #else
-			gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN  */
+			gen_op_fcmped();
 #endif
 			break;
 		    case 0x57: /* fcmpeq */

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
  2007-04-05 19:16 [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions Aurelien Jarno
@ 2007-04-06  6:22 ` Blue Swirl
  2007-04-06  7:06   ` Aurelien Jarno
  2007-04-06  6:47 ` Blue Swirl
  1 sibling, 1 reply; 5+ messages in thread
From: Blue Swirl @ 2007-04-06  6:22 UTC (permalink / raw)
  To: aurelien; +Cc: qemu-devel

>The attached patch fully implements IEEE exceptions on the SPARC target.

Nice work, thank you. Do you know of any code that uses the exceptions?

The flags enabling exceptions could be recorded to TB flags so that the 
check code is generated only when needed, see cpu-exec.c:180.

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE! 
http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
  2007-04-05 19:16 [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions Aurelien Jarno
  2007-04-06  6:22 ` Blue Swirl
@ 2007-04-06  6:47 ` Blue Swirl
  2007-04-06  7:07   ` Aurelien Jarno
  1 sibling, 1 reply; 5+ messages in thread
From: Blue Swirl @ 2007-04-06  6:47 UTC (permalink / raw)
  To: aurelien; +Cc: qemu-devel

>The attached patch fully implements IEEE exceptions on the SPARC target.

The patch is broken:
gcc-3.3 -Wall -O2 -g -fno-strict-aliasing  -fno-reorder-blocks  -fno-gcse    
-fno-optimize-sibling-calls  -fno-crossjumping  -fno-align-labels  
-fno-align-jumps  -fno-align-functions -mpreferred-stack-boundary=2 
-fomit-frame-pointer  -I. -I.. -I/tmp/qemu.aurel/target-sparc 
-I/tmp/qemu.aurel -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 
-I/tmp/qemu.aurel/fpu -I/tmp/qemu.aurel/slirp -c -o op.o 
/tmp/qemu.aurel/target-sparc/op.c
/tmp/qemu.aurel/target-sparc/op.c: In function `op_clear_ieee_excp_and_FTT':
/tmp/qemu.aurel/target-sparc/op.c:1539: error: `FSR_CEXEC_MASK' undeclared 
(first use in this function)
/tmp/qemu.aurel/target-sparc/op.c:1539: error: (Each undeclared identifier 
is reported only once
/tmp/qemu.aurel/target-sparc/op.c:1539: error: for each function it appears 
in.)

_________________________________________________________________
Don't just search. Find. Check out the new MSN Search! 
http://search.msn.click-url.com/go/onm00200636ave/direct/01/

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
  2007-04-06  6:22 ` Blue Swirl
@ 2007-04-06  7:06   ` Aurelien Jarno
  0 siblings, 0 replies; 5+ messages in thread
From: Aurelien Jarno @ 2007-04-06  7:06 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

On Fri, Apr 06, 2007 at 08:22:21AM +0200, Blue Swirl wrote:
> >The attached patch fully implements IEEE exceptions on the SPARC target.
> 
> Nice work, thank you. Do you know of any code that uses the exceptions?

I guess no code is using IEEE exceptions to generate a trap, because 
defining a signal handler for SIGFPE is highly non-standard. However a 
few programs are querying FSR to check the AEXC flags after a sequence 
of floating point instructions. This is the case for example of the SUN 
Java J2RE.

> The flags enabling exceptions could be recorded to TB flags so that the 
> check code is generated only when needed, see cpu-exec.c:180.

Well I doubt it is possible, because check_ieee_exceptions() generates a
trap if the TEM flags in the FSR register are set, but also update the 
AEXC flag in FSR. I even doubt lazy FSR is possible here, because it 
accumulates the exceptions of all floating points instructions since 
those flags are cleared.

-- 
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   aurel32@debian.org         | aurelien@aurel32.net
   `-    people.debian.org/~aurel32 | www.aurel32.net

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions
  2007-04-06  6:47 ` Blue Swirl
@ 2007-04-06  7:07   ` Aurelien Jarno
  0 siblings, 0 replies; 5+ messages in thread
From: Aurelien Jarno @ 2007-04-06  7:07 UTC (permalink / raw)
  To: Blue Swirl; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1313 bytes --]

On Fri, Apr 06, 2007 at 08:47:57AM +0200, Blue Swirl wrote:
> >The attached patch fully implements IEEE exceptions on the SPARC target.
> 
> The patch is broken:
> gcc-3.3 -Wall -O2 -g -fno-strict-aliasing  -fno-reorder-blocks  -fno-gcse   
> -fno-optimize-sibling-calls  -fno-crossjumping  -fno-align-labels  
> -fno-align-jumps  -fno-align-functions -mpreferred-stack-boundary=2 
> -fomit-frame-pointer  -I. -I.. -I/tmp/qemu.aurel/target-sparc 
> -I/tmp/qemu.aurel -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE 
> -I/tmp/qemu.aurel/fpu -I/tmp/qemu.aurel/slirp -c -o op.o 
> /tmp/qemu.aurel/target-sparc/op.c
> /tmp/qemu.aurel/target-sparc/op.c: In function `op_clear_ieee_excp_and_FTT':
> /tmp/qemu.aurel/target-sparc/op.c:1539: error: `FSR_CEXEC_MASK' undeclared 
> (first use in this function)
> /tmp/qemu.aurel/target-sparc/op.c:1539: error: (Each undeclared identifier 
> is reported only once
> /tmp/qemu.aurel/target-sparc/op.c:1539: error: for each function it appears 
> in.)
> 

Sorry this is a small typo in my patch, please find an update patch
attached.

-- 
  .''`.  Aurelien Jarno	            | GPG: 1024D/F1BCDB73
 : :' :  Debian developer           | Electrical Engineer
 `. `'   aurel32@debian.org         | aurelien@aurel32.net
   `-    people.debian.org/~aurel32 | www.aurel32.net

[-- Attachment #2: sparc-qemu-ieee_exceptions.diff --]
[-- Type: text/x-diff, Size: 11364 bytes --]

diff -u -d -p -r1.17 exec.h
--- qemu.orig/target-sparc/exec.h	19 Mar 2007 14:47:40 -0000	1.17
+++ qemu/target-sparc/exec.h	5 Apr 2007 18:46:48 -0000
@@ -61,6 +61,8 @@ void do_fsqrts(void);
 void do_fsqrtd(void);
 void do_fcmps(void);
 void do_fcmpd(void);
+void do_fcmpes(void);
+void do_fcmped(void);
 #ifdef TARGET_SPARC64
 void do_fabsd(void);
 void do_fcmps_fcc1(void);
@@ -69,6 +71,12 @@ void do_fcmps_fcc2(void);
 void do_fcmpd_fcc2(void);
 void do_fcmps_fcc3(void);
 void do_fcmpd_fcc3(void);
+void do_fcmpes_fcc1(void);
+void do_fcmped_fcc1(void);
+void do_fcmpes_fcc2(void);
+void do_fcmped_fcc2(void);
+void do_fcmpes_fcc3(void);
+void do_fcmped_fcc3(void);
 void do_popc();
 void do_wrpstate();
 void do_done();
@@ -79,6 +87,7 @@ void do_ldd_user(target_ulong addr);
 void do_ldd_raw(target_ulong addr);
 void do_interrupt(int intno);
 void raise_exception(int tt);
+void check_ieee_exceptions();
 void memcpy32(target_ulong *dst, const target_ulong *src);
 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
 void dump_mmu(CPUState *env);
diff -u -d -p -r1.27 op.c
--- qemu.orig/target-sparc/op.c	1 Apr 2007 15:38:17 -0000	1.27
+++ qemu/target-sparc/op.c	5 Apr 2007 18:46:48 -0000
@@ -1534,16 +1534,25 @@ void OPPROTO op_flush_T0(void)
     helper_flush(T0);
 }
 
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
+{
+    env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);;
+}
+
 #define F_OP(name, p) void OPPROTO op_f##name##p(void)
 
 #define F_BINOP(name)                                           \
     F_OP(name, s)                                               \
     {                                                           \
+	set_float_exception_flags(0, &env->fp_status);		\
         FT0 = float32_ ## name (FT0, FT1, &env->fp_status);     \
+	check_ieee_exceptions();				\
     }                                                           \
     F_OP(name, d)                                               \
     {                                                           \
+	set_float_exception_flags(0, &env->fp_status);		\
         DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+	check_ieee_exceptions();				\
     }
 
 F_BINOP(add);
@@ -1554,9 +1563,11 @@ F_BINOP(div);
 
 void OPPROTO op_fsmuld(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
                       float32_to_float64(FT1, &env->fp_status),
                       &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #define F_HELPER(name)    \
@@ -1582,6 +1593,7 @@ F_OP(abs, s)
 }
 
 F_HELPER(cmp);
+F_HELPER(cmpe);
 
 #ifdef TARGET_SPARC64
 F_OP(neg, d)
@@ -1623,6 +1635,37 @@ void OPPROTO op_fcmpd_fcc3(void)
 {
     do_fcmpd_fcc3();
 }
+
+void OPPROTO op_fcmpes_fcc1(void)
+{
+    do_fcmpes_fcc1();
+}
+
+void OPPROTO op_fcmped_fcc1(void)
+{
+    do_fcmped_fcc1();
+}
+
+void OPPROTO op_fcmpes_fcc2(void)
+{
+    do_fcmpes_fcc2();
+}
+
+void OPPROTO op_fcmped_fcc2(void)
+{
+    do_fcmped_fcc2();
+}
+
+void OPPROTO op_fcmpes_fcc3(void)
+{
+    do_fcmpes_fcc3();
+}
+
+void OPPROTO op_fcmped_fcc3(void)
+{
+    do_fcmped_fcc3();
+}
+
 #endif
 
 /* Integer to float conversion.  */
@@ -1631,23 +1674,31 @@ F_HELPER(ito);
 #else
 F_OP(ito, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(ito, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 F_OP(xto, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(xto, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 #endif
 #endif
@@ -1656,34 +1707,46 @@ F_OP(xto, d)
 /* floating point conversion */
 void OPPROTO op_fdtos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float64_to_float32(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fstod(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float32_to_float64(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 /* Float to integer conversion.  */
 void OPPROTO op_fstoi(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtoi(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 void OPPROTO op_fstox(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtox(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fmovs_cc(void)
diff -u -d -p -r1.23 op_helper.c
--- qemu.orig/target-sparc/op_helper.c	1 Apr 2007 15:15:36 -0000	1.23
+++ qemu/target-sparc/op_helper.c	5 Apr 2007 18:46:48 -0000
@@ -9,10 +9,43 @@ void raise_exception(int tt)
     cpu_loop_exit();
 }   
 
+void check_ieee_exceptions()
+{
+     T0 = get_float_exception_flags(&env->fp_status);
+     if (T0)
+     {
+	/* Copy IEEE 754 flags into FSR */
+	if (T0 & float_flag_invalid)
+	    env->fsr |= FSR_NVC;
+	if (T0 & float_flag_overflow)
+	    env->fsr |= FSR_OFC;
+	if (T0 & float_flag_underflow)
+	    env->fsr |= FSR_UFC;
+	if (T0 & float_flag_divbyzero)
+	    env->fsr |= FSR_DZC;
+	if (T0 & float_flag_inexact)
+	    env->fsr |= FSR_NXC;
+
+	if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
+	{
+	    /* Unmasked exception, generate a trap */
+	    env->fsr |= FSR_FTT_IEEE_EXCP;
+	    raise_exception(TT_FP_EXCP);
+	}
+	else
+	{
+	    /* Accumulate exceptions */
+	    env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+	}
+     }
+}
+
 #ifdef USE_INT_TO_FLOAT_HELPERS
 void do_fitos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fitod(void)
@@ -35,23 +68,29 @@ void do_fabsd(void)
 
 void do_fsqrts(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float32_sqrt(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fsqrtd(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_sqrt(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
-#define GEN_FCMP(name, size, reg1, reg2, FS)                            \
+#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
     void glue(do_, name) (void)                                         \
     {                                                                   \
         env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
             T0 = (FSR_FCC1 | FSR_FCC0) << FS;                           \
-            if (env->fsr & FSR_NVM) {                                   \
+            if ((env->fsr & FSR_NVM) || TRAP) {                         \
                 env->fsr |= T0;                                         \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
                 env->fsr |= FSR_NVA;                                    \
@@ -70,18 +109,30 @@ void do_fsqrtd(void)
         env->fsr |= T0;                                                 \
     }
 
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
+GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
 
 #ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
+GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
 
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
+GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
 
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
+GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+
+GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+
+GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+
+GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
 #endif
 
 #if defined(CONFIG_USER_ONLY) 
diff -u -d -p -r1.46 translate.c
--- qemu.orig/target-sparc/translate.c	5 Apr 2007 18:12:08 -0000	1.46
+++ qemu/target-sparc/translate.c	5 Apr 2007 18:46:49 -0000
@@ -943,6 +943,21 @@ static GenOpFunc * const gen_fcmpd[4] = 
     gen_op_fcmpd_fcc2,
     gen_op_fcmpd_fcc3,
 };
+
+static GenOpFunc * const gen_fcmpes[4] = {
+    gen_op_fcmpes,
+    gen_op_fcmpes_fcc1,
+    gen_op_fcmpes_fcc2,
+    gen_op_fcmpes_fcc3,
+};
+
+static GenOpFunc * const gen_fcmped[4] = {
+    gen_op_fcmped,
+    gen_op_fcmped_fcc1,
+    gen_op_fcmped_fcc2,
+    gen_op_fcmped_fcc3,
+};
+
 #endif
 
 static int gen_trap_ifnofpu(DisasContext * dc)
@@ -1289,6 +1304,7 @@ static void disas_sparc_insn(DisasContex
 	    } else if (xop == 0x34) {	/* FPU Operations */
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+		gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
 	        rs2 = GET_FIELD(insn, 27, 31);
 	        xop = GET_FIELD(insn, 18, 26);
@@ -1476,6 +1492,7 @@ static void disas_sparc_insn(DisasContex
 #endif
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+		gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
 	        rs2 = GET_FIELD(insn, 27, 31);
 	        xop = GET_FIELD(insn, 18, 26);
@@ -1653,18 +1670,18 @@ static void disas_sparc_insn(DisasContex
                 	gen_op_load_fpr_FT0(rs1);
                 	gen_op_load_fpr_FT1(rs2);
 #ifdef TARGET_SPARC64
-			gen_fcmps[rd & 3]();
+			gen_fcmpes[rd & 3]();
 #else
-			gen_op_fcmps(); /* XXX should trap if qNaN or sNaN  */
+			gen_op_fcmpes();
 #endif
 			break;
 		    case 0x56: /* fcmped, V9 %fcc */
                 	gen_op_load_fpr_DT0(DFPREG(rs1));
                 	gen_op_load_fpr_DT1(DFPREG(rs2));
 #ifdef TARGET_SPARC64
-			gen_fcmpd[rd & 3]();
+			gen_fcmped[rd & 3]();
 #else
-			gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN  */
+			gen_op_fcmped();
 #endif
 			break;
 		    case 0x57: /* fcmpeq */

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-04-06  7:11 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-05 19:16 [Qemu-devel] [PATCH][SPARC] Full implementation of IEEE exceptions Aurelien Jarno
2007-04-06  6:22 ` Blue Swirl
2007-04-06  7:06   ` Aurelien Jarno
2007-04-06  6:47 ` Blue Swirl
2007-04-06  7:07   ` Aurelien Jarno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).