]> git.proxmox.com Git - qemu.git/commitdiff
division by zero FPU exception support
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 8 May 2004 21:08:41 +0000 (21:08 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 8 May 2004 21:08:41 +0000 (21:08 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@795 c046a42c-6fe2-441c-8c8c-71466251a162

target-i386/cpu.h
target-i386/exec.h
target-i386/helper.c
target-i386/op.c
target-i386/translate.c

index 6b2a89bb9a259fe01f610c0f409e8cad83e3a7d0..6939a2c6e66e10fc2005a33cf2fb9caec3098c48 100644 (file)
 #define CR0_MP_MASK  (1 << 1)
 #define CR0_EM_MASK  (1 << 2)
 #define CR0_TS_MASK  (1 << 3)
+#define CR0_ET_MASK  (1 << 4)
 #define CR0_NE_MASK  (1 << 5)
 #define CR0_WP_MASK  (1 << 16)
 #define CR0_AM_MASK  (1 << 18)
@@ -373,6 +374,8 @@ CPUX86State *cpu_x86_init(void);
 int cpu_x86_exec(CPUX86State *s);
 void cpu_x86_close(CPUX86State *s);
 int cpu_get_pic_interrupt(CPUX86State *s);
+/* MSDOS compatibility mode FPU exception support */
+void cpu_set_ferr(CPUX86State *s);
 
 /* this function must always be used to load data in the segment
    cache: it synchronizes the hflags with the segment cache values */
index 63010f745dfacf4eb53ffd3bc85af2da966ad405..fb9cc772f9654db94609251f2b0921acd9a2ccd1 100644 (file)
@@ -478,10 +478,24 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
 
 #endif /* USE_X86LDOUBLE */
 
+#define FPUS_IE (1 << 0)
+#define FPUS_DE (1 << 1)
+#define FPUS_ZE (1 << 2)
+#define FPUS_OE (1 << 3)
+#define FPUS_UE (1 << 4)
+#define FPUS_PE (1 << 5)
+#define FPUS_SF (1 << 6)
+#define FPUS_SE (1 << 7)
+#define FPUS_B  (1 << 15)
+
+#define FPUC_EM 0x3f
+
 const CPU86_LDouble f15rk[7];
 
 void helper_fldt_ST0_A0(void);
 void helper_fstt_ST0_A0(void);
+void fpu_raise_exception(void);
+CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b);
 void helper_fbld_ST0_A0(void);
 void helper_fbst_ST0_A0(void);
 void helper_f2xm1(void);
index 27a7a5559ca33f51aba187ff45b24d226a9a0268..f2305e32c491b91d0526e7c32524a9f5697e5508 100644 (file)
@@ -24,7 +24,7 @@
 #if 0
 #define raise_exception_err(a, b)\
 do {\
-    printf("raise_exception line=%d\n", __LINE__);\
+    fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
     (raise_exception_err)(a, b);\
 } while (0)
 #endif
@@ -859,10 +859,11 @@ void do_interrupt(int intno, int is_int, int error_code,
     if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) {
         if ((env->cr[0] & CR0_PE_MASK)) {
             static int count;
-            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x SP=%04x:%08x",
+            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x pc=%08x SP=%04x:%08x",
                     count, intno, error_code, is_int,
                     env->hflags & HF_CPL_MASK,
                     env->segs[R_CS].selector, EIP,
+                    (int)env->segs[R_CS].base + EIP,
                     env->segs[R_SS].selector, ESP);
             if (intno == 0x0e) {
                 fprintf(logfile, " CR2=%08x", env->cr[2]);
@@ -1990,6 +1991,32 @@ void helper_fstt_ST0_A0(void)
     helper_fstt(ST0, (uint8_t *)A0);
 }
 
+void fpu_set_exception(int mask)
+{
+    env->fpus |= mask;
+    if (env->fpus & (~env->fpuc & FPUC_EM))
+        env->fpus |= FPUS_SE | FPUS_B;
+}
+
+CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
+{
+    if (b == 0.0) 
+        fpu_set_exception(FPUS_ZE);
+    return a / b;
+}
+
+void fpu_raise_exception(void)
+{
+    if (env->cr[0] & CR0_NE_MASK) {
+        raise_exception(EXCP10_COPR);
+    } 
+#if !defined(CONFIG_USER_ONLY) 
+    else {
+        cpu_set_ferr(env);
+    }
+#endif
+}
+
 /* BCD ops */
 
 void helper_fbld_ST0_A0(void)
index 1169f121adc2de71928dc34535d201b3a1ab42e4..37823319d6c6a2faf89814fc953f7e3fb0454a19 100644 (file)
@@ -1738,12 +1738,12 @@ void OPPROTO op_fsubr_ST0_FT0(void)
 
 void OPPROTO op_fdiv_ST0_FT0(void)
 {
-    ST0 /= FT0;
+    ST0 = helper_fdiv(ST0, FT0);
 }
 
 void OPPROTO op_fdivr_ST0_FT0(void)
 {
-    ST0 = FT0 / ST0;
+    ST0 = helper_fdiv(FT0, ST0);
 }
 
 /* fp operations between STN and ST0 */
@@ -1772,14 +1772,16 @@ void OPPROTO op_fsubr_STN_ST0(void)
 
 void OPPROTO op_fdiv_STN_ST0(void)
 {
-    ST(PARAM1) /= ST0;
+    CPU86_LDouble *p;
+    p = &ST(PARAM1);
+    *p = helper_fdiv(*p, ST0);
 }
 
 void OPPROTO op_fdivr_STN_ST0(void)
 {
     CPU86_LDouble *p;
     p = &ST(PARAM1);
-    *p = ST0 / *p;
+    *p = helper_fdiv(ST0, *p);
 }
 
 /* misc FPU operations */
@@ -1959,6 +1961,13 @@ void OPPROTO op_fclex(void)
     env->fpus &= 0x7f00;
 }
 
+void OPPROTO op_fwait(void)
+{
+    if (env->fpus & FPUS_SE)
+        fpu_raise_exception();
+    FORCE_RET();
+}
+
 void OPPROTO op_fninit(void)
 {
     env->fpus = 0;
index a1a4c633dcab649ade558c647e7be29405e04200..c6aa5030ed5c4dbdac2e788d184510dccc37caa8 100644 (file)
@@ -3761,6 +3761,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 
             (HF_MP_MASK | HF_TS_MASK)) {
             gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
+        } else {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            gen_op_jmp_im(pc_start - s->cs_base);
+            gen_op_fwait();
         }
         break;
     case 0xcc: /* int3 */