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:
parent
28c3ee3fed
commit
2ee73ac3a8
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user