* [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-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-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: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).