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:
bellard 2004-05-08 21:08:41 +00:00
parent 28c3ee3fed
commit 2ee73ac3a8
5 changed files with 64 additions and 6 deletions

View File

@ -143,6 +143,7 @@
#define CR0_MP_MASK (1 << 1) #define CR0_MP_MASK (1 << 1)
#define CR0_EM_MASK (1 << 2) #define CR0_EM_MASK (1 << 2)
#define CR0_TS_MASK (1 << 3) #define CR0_TS_MASK (1 << 3)
#define CR0_ET_MASK (1 << 4)
#define CR0_NE_MASK (1 << 5) #define CR0_NE_MASK (1 << 5)
#define CR0_WP_MASK (1 << 16) #define CR0_WP_MASK (1 << 16)
#define CR0_AM_MASK (1 << 18) #define CR0_AM_MASK (1 << 18)
@ -373,6 +374,8 @@ CPUX86State *cpu_x86_init(void);
int cpu_x86_exec(CPUX86State *s); int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s); void cpu_x86_close(CPUX86State *s);
int cpu_get_pic_interrupt(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 /* this function must always be used to load data in the segment
cache: it synchronizes the hflags with the segment cache values */ cache: it synchronizes the hflags with the segment cache values */

View File

@ -478,10 +478,24 @@ static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
#endif /* USE_X86LDOUBLE */ #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]; const CPU86_LDouble f15rk[7];
void helper_fldt_ST0_A0(void); void helper_fldt_ST0_A0(void);
void helper_fstt_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_fbld_ST0_A0(void);
void helper_fbst_ST0_A0(void); void helper_fbst_ST0_A0(void);
void helper_f2xm1(void); void helper_f2xm1(void);

View File

@ -24,7 +24,7 @@
#if 0 #if 0
#define raise_exception_err(a, b)\ #define raise_exception_err(a, b)\
do {\ do {\
printf("raise_exception line=%d\n", __LINE__);\ fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
(raise_exception_err)(a, b);\ (raise_exception_err)(a, b);\
} while (0) } while (0)
#endif #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 (loglevel & (CPU_LOG_PCALL | CPU_LOG_INT)) {
if ((env->cr[0] & CR0_PE_MASK)) { if ((env->cr[0] & CR0_PE_MASK)) {
static int count; 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, count, intno, error_code, is_int,
env->hflags & HF_CPL_MASK, env->hflags & HF_CPL_MASK,
env->segs[R_CS].selector, EIP, env->segs[R_CS].selector, EIP,
(int)env->segs[R_CS].base + EIP,
env->segs[R_SS].selector, ESP); env->segs[R_SS].selector, ESP);
if (intno == 0x0e) { if (intno == 0x0e) {
fprintf(logfile, " CR2=%08x", env->cr[2]); fprintf(logfile, " CR2=%08x", env->cr[2]);
@ -1990,6 +1991,32 @@ void helper_fstt_ST0_A0(void)
helper_fstt(ST0, (uint8_t *)A0); 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 */ /* BCD ops */
void helper_fbld_ST0_A0(void) void helper_fbld_ST0_A0(void)

View File

@ -1738,12 +1738,12 @@ void OPPROTO op_fsubr_ST0_FT0(void)
void OPPROTO op_fdiv_ST0_FT0(void) void OPPROTO op_fdiv_ST0_FT0(void)
{ {
ST0 /= FT0; ST0 = helper_fdiv(ST0, FT0);
} }
void OPPROTO op_fdivr_ST0_FT0(void) void OPPROTO op_fdivr_ST0_FT0(void)
{ {
ST0 = FT0 / ST0; ST0 = helper_fdiv(FT0, ST0);
} }
/* fp operations between STN and 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) 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) void OPPROTO op_fdivr_STN_ST0(void)
{ {
CPU86_LDouble *p; CPU86_LDouble *p;
p = &ST(PARAM1); p = &ST(PARAM1);
*p = ST0 / *p; *p = helper_fdiv(ST0, *p);
} }
/* misc FPU operations */ /* misc FPU operations */
@ -1959,6 +1961,13 @@ void OPPROTO op_fclex(void)
env->fpus &= 0x7f00; env->fpus &= 0x7f00;
} }
void OPPROTO op_fwait(void)
{
if (env->fpus & FPUS_SE)
fpu_raise_exception();
FORCE_RET();
}
void OPPROTO op_fninit(void) void OPPROTO op_fninit(void)
{ {
env->fpus = 0; env->fpus = 0;

View 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)) == if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
(HF_MP_MASK | HF_TS_MASK)) { (HF_MP_MASK | HF_TS_MASK)) {
gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); 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; break;
case 0xcc: /* int3 */ case 0xcc: /* int3 */