division by zero FPU exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@795 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		| @@ -143,6 +143,7 @@ | ||||
| #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 */ | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user