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_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 */

View 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);

View 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)

View 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;

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)) ==
(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 */