Commit 2ee73ac3a855fb0cfba3db91fdd1ecebdbc6f971
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
Showing
5 changed files
with
64 additions
and
6 deletions
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 */ |