#else
-typedef {
+typedef union {
double d;
#ifndef WORDS_BIGENDIAN
struct {
ST0 = ldfq((void *)A0);
}
+#ifdef USE_X86LDOUBLE
+void OPPROTO op_fldt_ST0_A0(void)
+{
+ ST0 = *(long double *)A0;
+}
+#else
+void helper_fldt_ST0_A0(void)
+{
+ CPU86_LDoubleU temp;
+ int upper, e;
+ /* mantissa */
+ upper = lduw((uint8_t *)A0 + 8);
+ /* XXX: handle overflow ? */
+ e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
+ e |= (upper >> 4) & 0x800; /* sign */
+ temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52);
+ ST0 = temp.d;
+}
+
+void OPPROTO op_fldt_ST0_A0(void)
+{
+ helper_fldt_ST0_A0();
+}
+#endif
+
void OPPROTO op_fild_ST0_A0(void)
{
ST0 = (CPU86_LDouble)ldsw((void *)A0);
void OPPROTO op_fstl_ST0_A0(void)
{
- ST0 = ldfq((void *)A0);
+ stfq((void *)A0, (double)ST0);
}
+#ifdef USE_X86LDOUBLE
+void OPPROTO op_fstt_ST0_A0(void)
+{
+ *(long double *)A0 = ST0;
+}
+#else
+void helper_fstt_ST0_A0(void)
+{
+ CPU86_LDoubleU temp;
+ int e;
+ temp.d = ST0;
+ /* mantissa */
+ stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63));
+ /* exponent + sign */
+ e = EXPD(temp) - EXPBIAS + 16383;
+ e |= SIGND(temp) >> 16;
+ stw((uint8_t *)A0 + 8, e);
+}
+
+void OPPROTO op_fstt_ST0_A0(void)
+{
+ helper_fstt_ST0_A0();
+}
+#endif
+
void OPPROTO op_fist_ST0_A0(void)
{
int val;
stq((void *)A0, val);
}
+/* BCD ops */
+
+#define MUL10(iv) ( iv + iv + (iv << 3) )
+
+void helper_fbld_ST0_A0(void)
+{
+ uint8_t *seg;
+ CPU86_LDouble fpsrcop;
+ int m32i;
+ unsigned int v;
+
+ /* in this code, seg/m32i will be used as temporary ptr/int */
+ seg = (uint8_t *)A0 + 8;
+ v = ldub(seg--);
+ /* XXX: raise exception */
+ if (v != 0)
+ return;
+ v = ldub(seg--);
+ /* XXX: raise exception */
+ if ((v & 0xf0) != 0)
+ return;
+ m32i = v; /* <-- d14 */
+ v = ldub(seg--);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */
+ v = ldub(seg--);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */
+ v = ldub(seg--);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */
+ fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0;
+
+ v = ldub(seg--);
+ m32i = (v >> 4); /* <-- d7 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */
+ v = ldub(seg--);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */
+ v = ldub(seg--);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */
+ v = ldub(seg);
+ m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */
+ m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */
+ fpsrcop += ((CPU86_LDouble)m32i);
+ if ( ldub(seg+9) & 0x80 )
+ fpsrcop = -fpsrcop;
+ ST0 = fpsrcop;
+}
+
+void OPPROTO op_fbld_ST0_A0(void)
+{
+ helper_fbld_ST0_A0();
+}
+
+void helper_fbst_ST0_A0(void)
+{
+ CPU86_LDouble fptemp;
+ CPU86_LDouble fpsrcop;
+ int v;
+ uint8_t *mem_ref, *mem_end;
+
+ fpsrcop = rint(ST0);
+ mem_ref = (uint8_t *)A0;
+ mem_end = mem_ref + 8;
+ if ( fpsrcop < 0.0 ) {
+ stw(mem_end, 0x8000);
+ fpsrcop = -fpsrcop;
+ } else {
+ stw(mem_end, 0x0000);
+ }
+ while (mem_ref < mem_end) {
+ if (fpsrcop == 0.0)
+ break;
+ fptemp = floor(fpsrcop/10.0);
+ v = ((int)(fpsrcop - fptemp*10.0));
+ if (fptemp == 0.0) {
+ stb(mem_ref++, v);
+ break;
+ }
+ fpsrcop = fptemp;
+ fptemp = floor(fpsrcop/10.0);
+ v |= (((int)(fpsrcop - fptemp*10.0)) << 4);
+ stb(mem_ref++, v);
+ fpsrcop = fptemp;
+ }
+ while (mem_ref < mem_end) {
+ stb(mem_ref++, 0);
+ }
+}
+
+void OPPROTO op_fbst_ST0_A0(void)
+{
+ helper_fbst_ST0_A0();
+}
+
/* FPU move */
static inline void fpush(void)
FORCE_RET();
}
+/* XXX: handle nans */
+void OPPROTO op_fucom_ST0_FT0(void)
+{
+ env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */
+ if (ST0 < FT0)
+ env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */
+ else if (ST0 == FT0)
+ env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
+ FORCE_RET();
+}
+
void OPPROTO op_fadd_ST0_FT0(void)
{
ST0 += FT0;
ST0 = fabs(ST0);
}
-void OPPROTO op_fxam_ST0(void)
+void helper_fxam_ST0(void)
{
CPU86_LDoubleU temp;
int expdif;
} else {
env->fpus |= 0x400;
}
- FORCE_RET();
+}
+
+void OPPROTO op_fxam_ST0(void)
+{
+ helper_fxam_ST0();
}
void OPPROTO op_fld1_ST0(void)
ST0 = *(CPU86_LDouble *)&f15rk[1];
}
-void OPPROTO op_fld2t_ST0(void)
+void OPPROTO op_fldl2t_ST0(void)
{
ST0 = *(CPU86_LDouble *)&f15rk[6];
}
-void OPPROTO op_fld2e_ST0(void)
+void OPPROTO op_fldl2e_ST0(void)
{
ST0 = *(CPU86_LDouble *)&f15rk[5];
}
stw((void *)A0, fpus);
}
+void OPPROTO op_fnstsw_EAX(void)
+{
+ int fpus;
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ EAX = (EAX & 0xffff0000) | fpus;
+}
+
void OPPROTO op_fnstcw_A0(void)
{
stw((void *)A0, env->fpuc);
eflags & CC_P ? 'P' : '-',
eflags & CC_C ? 'C' : '-'
);
+#if 1
+ fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
+ (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
+#endif
}
#endif
cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc);
},
};
+static GenOpFunc *gen_op_bsx_T0_cc[2][2] = {
+ [0] = {
+ gen_op_bsfw_T0_cc,
+ gen_op_bsrw_T0_cc,
+ },
+ [1] = {
+ gen_op_bsfl_T0_cc,
+ gen_op_bsrl_T0_cc,
+ },
+};
+
static GenOpFunc *gen_op_lds_T0_A0[3] = {
gen_op_ldsb_T0_A0,
gen_op_ldsw_T0_A0,
gen_op_fdivr_ST0_FT0,
};
+/* NOTE the exception in "r" op ordering */
static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
gen_op_fadd_STN_ST0,
gen_op_fmul_STN_ST0,
NULL,
NULL,
- gen_op_fsub_STN_ST0,
gen_op_fsubr_STN_ST0,
- gen_op_fdiv_STN_ST0,
+ gen_op_fsub_STN_ST0,
gen_op_fdivr_STN_ST0,
+ gen_op_fdiv_STN_ST0,
};
static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
case 0x0f: /* fnstcw mem */
gen_op_fnstcw_A0();
break;
+ case 0x1d: /* fldt mem */
+ gen_op_fpush();
+ gen_op_fldt_ST0_A0();
+ break;
+ case 0x1f: /* fstpt mem */
+ gen_op_fstt_ST0_A0();
+ gen_op_fpop();
+ break;
case 0x2f: /* fnstsw mem */
gen_op_fnstsw_A0();
break;
case 0x3c: /* fbld */
+ gen_op_fpush();
+ op_fbld_ST0_A0();
+ break;
case 0x3e: /* fbstp */
- error("float BCD not hanlded");
- return -1;
+ gen_op_fbst_ST0_A0();
+ gen_op_fpop();
+ break;
case 0x3d: /* fildll */
gen_op_fpush();
gen_op_fildll_ST0_A0();
gen_op_fpop();
break;
default:
- error("unhandled memory FP [op=0x%02x]\n", op);
+ error("unhandled FPm [op=0x%02x]\n", op);
return -1;
}
} else {
gen_op_fmov_ST0_STN((opreg + 1) & 7);
break;
case 0x09: /* fxchg sti */
- gen_op_fxchg_ST0_STN((opreg + 1) & 7);
+ gen_op_fxchg_ST0_STN(opreg);
break;
case 0x0a: /* grp d9/2 */
switch(rm) {
{
switch(rm) {
case 0:
+ gen_op_fpush();
gen_op_fld1_ST0();
break;
case 1:
- gen_op_fld2t_ST0();
+ gen_op_fpush();
+ gen_op_fldl2t_ST0();
break;
case 2:
- gen_op_fld2e_ST0();
+ gen_op_fpush();
+ gen_op_fldl2e_ST0();
break;
case 3:
+ gen_op_fpush();
gen_op_fldpi_ST0();
break;
case 4:
+ gen_op_fpush();
gen_op_fldlg2_ST0();
break;
case 5:
+ gen_op_fpush();
gen_op_fldln2_ST0();
break;
case 6:
+ gen_op_fpush();
gen_op_fldz_ST0();
break;
default:
op1 = op & 7;
if (op >= 0x20) {
gen_op_fp_arith_STN_ST0[op1](opreg);
+ if (op >= 0x30)
+ gen_op_fpop();
} else {
gen_op_fmov_FT0_STN(opreg);
gen_op_fp_arith_ST0_FT0[op1]();
}
- if (op >= 0x30)
- gen_op_fpop();
}
break;
case 0x02: /* fcom */
switch(rm) {
case 1: /* fucompp */
gen_op_fmov_FT0_STN(1);
- gen_op_fcom_ST0_FT0();
+ gen_op_fucom_ST0_FT0();
gen_op_fpop();
gen_op_fpop();
break;
gen_op_fmov_STN_ST0(opreg);
gen_op_fpop();
break;
+ case 0x2c: /* fucom st(i) */
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fucom_ST0_FT0();
+ break;
+ case 0x2d: /* fucomp st(i) */
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fucom_ST0_FT0();
+ gen_op_fpop();
+ break;
case 0x33: /* de/3 */
switch(rm) {
case 1: /* fcompp */
break;
case 0x3c: /* df/4 */
switch(rm) {
-#if 0
case 0:
- gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO);
+ gen_op_fnstsw_EAX();
break;
-#endif
default:
- error("unhandled FP df/4\n");
+ error("unhandled FP %x df/4\n", rm);
return -1;
}
break;
default:
- error("unhandled FP\n");
+ error("unhandled FPr [op=0x%x]\n", op);
return -1;
}
}
gen_op_mov_reg_T0[ot][rm]();
}
break;
-
+ case 0x1bc: /* bsf */
+ case 0x1bd: /* bsr */
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+ gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
+ /* NOTE: we always write back the result. Intel doc says it is
+ undefined if T0 == 0 */
+ gen_op_mov_reg_T0[ot][reg]();
+ s->cc_op = CC_OP_LOGICB + ot;
+ break;
/************************/
/* misc */
case 0x90: /* nop */