Commit 2ee73ac3a855fb0cfba3db91fdd1ecebdbc6f971

Authored by bellard
1 parent 28c3ee3f

division by zero FPU exception support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@795 c046a42c-6fe2-441c-8c8c-71466251a162
target-i386/cpu.h
@@ -143,6 +143,7 @@ @@ -143,6 +143,7 @@
143 #define CR0_MP_MASK (1 << 1) 143 #define CR0_MP_MASK (1 << 1)
144 #define CR0_EM_MASK (1 << 2) 144 #define CR0_EM_MASK (1 << 2)
145 #define CR0_TS_MASK (1 << 3) 145 #define CR0_TS_MASK (1 << 3)
  146 +#define CR0_ET_MASK (1 << 4)
146 #define CR0_NE_MASK (1 << 5) 147 #define CR0_NE_MASK (1 << 5)
147 #define CR0_WP_MASK (1 << 16) 148 #define CR0_WP_MASK (1 << 16)
148 #define CR0_AM_MASK (1 << 18) 149 #define CR0_AM_MASK (1 << 18)
@@ -373,6 +374,8 @@ CPUX86State *cpu_x86_init(void); @@ -373,6 +374,8 @@ CPUX86State *cpu_x86_init(void);
373 int cpu_x86_exec(CPUX86State *s); 374 int cpu_x86_exec(CPUX86State *s);
374 void cpu_x86_close(CPUX86State *s); 375 void cpu_x86_close(CPUX86State *s);
375 int cpu_get_pic_interrupt(CPUX86State *s); 376 int cpu_get_pic_interrupt(CPUX86State *s);
  377 +/* MSDOS compatibility mode FPU exception support */
  378 +void cpu_set_ferr(CPUX86State *s);
376 379
377 /* this function must always be used to load data in the segment 380 /* this function must always be used to load data in the segment
378 cache: it synchronizes the hflags with the segment cache values */ 381 cache: it synchronizes the hflags with the segment cache values */
target-i386/exec.h
@@ -478,10 +478,24 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) @@ -478,10 +478,24 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
478 478
479 #endif /* USE_X86LDOUBLE */ 479 #endif /* USE_X86LDOUBLE */
480 480
  481 +#define FPUS_IE (1 << 0)
  482 +#define FPUS_DE (1 << 1)
  483 +#define FPUS_ZE (1 << 2)
  484 +#define FPUS_OE (1 << 3)
  485 +#define FPUS_UE (1 << 4)
  486 +#define FPUS_PE (1 << 5)
  487 +#define FPUS_SF (1 << 6)
  488 +#define FPUS_SE (1 << 7)
  489 +#define FPUS_B (1 << 15)
  490 +
  491 +#define FPUC_EM 0x3f
  492 +
481 const CPU86_LDouble f15rk[7]; 493 const CPU86_LDouble f15rk[7];
482 494
483 void helper_fldt_ST0_A0(void); 495 void helper_fldt_ST0_A0(void);
484 void helper_fstt_ST0_A0(void); 496 void helper_fstt_ST0_A0(void);
  497 +void fpu_raise_exception(void);
  498 +CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b);
485 void helper_fbld_ST0_A0(void); 499 void helper_fbld_ST0_A0(void);
486 void helper_fbst_ST0_A0(void); 500 void helper_fbst_ST0_A0(void);
487 void helper_f2xm1(void); 501 void helper_f2xm1(void);
target-i386/helper.c
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 #if 0 24 #if 0
25 #define raise_exception_err(a, b)\ 25 #define raise_exception_err(a, b)\
26 do {\ 26 do {\
27 - printf("raise_exception line=%d\n", __LINE__);\ 27 + fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
28 (raise_exception_err)(a, b);\ 28 (raise_exception_err)(a, b);\
29 } while (0) 29 } while (0)
30 #endif 30 #endif
@@ -859,10 +859,11 @@ void do_interrupt(int intno, int is_int, int error_code, @@ -859,10 +859,11 @@ void do_interrupt(int intno, int is_int, int error_code,
859 if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) { 859 if (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) {
860 if ((env->cr[0] & CR0_PE_MASK)) { 860 if ((env->cr[0] & CR0_PE_MASK)) {
861 static int count; 861 static int count;
862 - fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x SP=%04x:%08x", 862 + fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:%08x pc=%08x SP=%04x:%08x",
863 count, intno, error_code, is_int, 863 count, intno, error_code, is_int,
864 env->hflags & HF_CPL_MASK, 864 env->hflags & HF_CPL_MASK,
865 env->segs[R_CS].selector, EIP, 865 env->segs[R_CS].selector, EIP,
  866 + (int)env->segs[R_CS].base + EIP,
866 env->segs[R_SS].selector, ESP); 867 env->segs[R_SS].selector, ESP);
867 if (intno == 0x0e) { 868 if (intno == 0x0e) {
868 fprintf(logfile, " CR2=%08x", env->cr[2]); 869 fprintf(logfile, " CR2=%08x", env->cr[2]);
@@ -1990,6 +1991,32 @@ void helper_fstt_ST0_A0(void) @@ -1990,6 +1991,32 @@ void helper_fstt_ST0_A0(void)
1990 helper_fstt(ST0, (uint8_t *)A0); 1991 helper_fstt(ST0, (uint8_t *)A0);
1991 } 1992 }
1992 1993
  1994 +void fpu_set_exception(int mask)
  1995 +{
  1996 + env->fpus |= mask;
  1997 + if (env->fpus & (~env->fpuc & FPUC_EM))
  1998 + env->fpus |= FPUS_SE | FPUS_B;
  1999 +}
  2000 +
  2001 +CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
  2002 +{
  2003 + if (b == 0.0)
  2004 + fpu_set_exception(FPUS_ZE);
  2005 + return a / b;
  2006 +}
  2007 +
  2008 +void fpu_raise_exception(void)
  2009 +{
  2010 + if (env->cr[0] & CR0_NE_MASK) {
  2011 + raise_exception(EXCP10_COPR);
  2012 + }
  2013 +#if !defined(CONFIG_USER_ONLY)
  2014 + else {
  2015 + cpu_set_ferr(env);
  2016 + }
  2017 +#endif
  2018 +}
  2019 +
1993 /* BCD ops */ 2020 /* BCD ops */
1994 2021
1995 void helper_fbld_ST0_A0(void) 2022 void helper_fbld_ST0_A0(void)
target-i386/op.c
@@ -1738,12 +1738,12 @@ void OPPROTO op_fsubr_ST0_FT0(void) @@ -1738,12 +1738,12 @@ void OPPROTO op_fsubr_ST0_FT0(void)
1738 1738
1739 void OPPROTO op_fdiv_ST0_FT0(void) 1739 void OPPROTO op_fdiv_ST0_FT0(void)
1740 { 1740 {
1741 - ST0 /= FT0; 1741 + ST0 = helper_fdiv(ST0, FT0);
1742 } 1742 }
1743 1743
1744 void OPPROTO op_fdivr_ST0_FT0(void) 1744 void OPPROTO op_fdivr_ST0_FT0(void)
1745 { 1745 {
1746 - ST0 = FT0 / ST0; 1746 + ST0 = helper_fdiv(FT0, ST0);
1747 } 1747 }
1748 1748
1749 /* fp operations between STN and ST0 */ 1749 /* fp operations between STN and ST0 */
@@ -1772,14 +1772,16 @@ void OPPROTO op_fsubr_STN_ST0(void) @@ -1772,14 +1772,16 @@ void OPPROTO op_fsubr_STN_ST0(void)
1772 1772
1773 void OPPROTO op_fdiv_STN_ST0(void) 1773 void OPPROTO op_fdiv_STN_ST0(void)
1774 { 1774 {
1775 - ST(PARAM1) /= ST0; 1775 + CPU86_LDouble *p;
  1776 + p = &ST(PARAM1);
  1777 + *p = helper_fdiv(*p, ST0);
1776 } 1778 }
1777 1779
1778 void OPPROTO op_fdivr_STN_ST0(void) 1780 void OPPROTO op_fdivr_STN_ST0(void)
1779 { 1781 {
1780 CPU86_LDouble *p; 1782 CPU86_LDouble *p;
1781 p = &ST(PARAM1); 1783 p = &ST(PARAM1);
1782 - *p = ST0 / *p; 1784 + *p = helper_fdiv(ST0, *p);
1783 } 1785 }
1784 1786
1785 /* misc FPU operations */ 1787 /* misc FPU operations */
@@ -1959,6 +1961,13 @@ void OPPROTO op_fclex(void) @@ -1959,6 +1961,13 @@ void OPPROTO op_fclex(void)
1959 env->fpus &= 0x7f00; 1961 env->fpus &= 0x7f00;
1960 } 1962 }
1961 1963
  1964 +void OPPROTO op_fwait(void)
  1965 +{
  1966 + if (env->fpus & FPUS_SE)
  1967 + fpu_raise_exception();
  1968 + FORCE_RET();
  1969 +}
  1970 +
1962 void OPPROTO op_fninit(void) 1971 void OPPROTO op_fninit(void)
1963 { 1972 {
1964 env->fpus = 0; 1973 env->fpus = 0;
target-i386/translate.c
@@ -3761,6 +3761,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3761,6 +3761,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
3761 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 3761 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
3762 (HF_MP_MASK | HF_TS_MASK)) { 3762 (HF_MP_MASK | HF_TS_MASK)) {
3763 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); 3763 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
  3764 + } else {
  3765 + if (s->cc_op != CC_OP_DYNAMIC)
  3766 + gen_op_set_cc_op(s->cc_op);
  3767 + gen_op_jmp_im(pc_start - s->cs_base);
  3768 + gen_op_fwait();
3764 } 3769 }
3765 break; 3770 break;
3766 case 0xcc: /* int3 */ 3771 case 0xcc: /* int3 */