/* * optable.c * * Copyright (C) 2003, 2004 Jonathan Campbell * * Opcode jumptable. * * Allows the recognition of many opcodes without having to write approximately * 500+ if...then...else statements which is a) inefficient and b) apparently can * cause some compilers such as Microsoft C++ to crash during the compile stage with * an error. Since it's a table, it can be referred to via a pointer that can be easily * redirected to other opcode tables (i.e., one for the 8086, one for the 80286, etc.) * without much hassle. * * The table contains two pointers: one for an "execute" function, and one for a * "decompile" function. The execute function is given the context and the initial opcode. * If more opcodes are needed the function calls softx86_fetch_exec_byte(). The decode * function is also given the opcode but also a char[] array where it is expected to * sprintf() or strcpy() the disassembled output. If that function needs more opcodes * it calls softx86_fetch_dec_byte(). * *********************************************************************************** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ************************************************************************************/ #include #include #include #include #include #include "optab87.h" void op_fcom(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src); void op_fadd(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src); void op_fsub(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src); void op_fdiv(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src); void op_fdivr(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src); char s87op1_tmp[32]; char s87op2_tmp[32]; /* pops value from FPU stack */ void softx86_popstack(softx87_ctx* ctx87) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); SX87_FPUTAGW_TAG_SET(ctx87->state.tag_word,TOP,SX87_FPUTAGVAL_EMPTY); TOP = (TOP+1)&7; SX87_FPUSTAT_TOP_SET(ctx87->state.status_word,TOP); } /* given an FPU register, convert to an integer */ sx86_uldword sx87_getint(softx87_reg80 *r) { sx86_uldword m; sx86_uword e; // TODO: take into consideration the rounding mode e = 63 - (r->exponent - 16383); if (e > 63) { m = 0; } else if (e > 0) { // TODO: rounding mode? m = r->mantissa >> ((sx86_uldword)(e)); } else if (e < 0) { sx86_uldword n; /* first figure out if bits will be shifted out (too large). if that's the case compensate by setting the mantissa to the largest possible __uint64 value. */ n = ((sx86_uldword)-1) << ((sx86_uldword)(63 + e)); if (((sx86_uldword)(r->mantissa & n)) != ((sx86_uldword)0)) m = (sx86_uldword)-1; else m = r->mantissa << ((sx86_uldword)(-e)); } else { m = r->mantissa; } return m; } /* FBSTP 80 */ void op_fbstp80(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; int i; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 10 || !ctx87) return; TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); /* TODO: check and perform cases as documented: -infinity = #IA exception -infinity = #IA exception TODO: what do we do really if the entry is empty? */ tmp.sign_bit = ctx87->state.st[TOP].sign_bit; tmp.mantissa = ctx87->state.st[TOP].mantissa; tmp.exponent = ctx87->state.st[TOP].exponent; /* shift data around to produce integer version. */ /* if it's too large, clip it */ tmp.mantissa = sx87_getint(&tmp); /* if too large for BCD coding, clip it. */ if (tmp.mantissa > 999999999999999999) /* 18 digits usable, so... */ tmp.mantissa = 999999999999999999; /* clip if >= 10^19 */ /* put it out there */ for (i=0;i < 9;i++) { datz[i] = (char)(tmp.mantissa % ((sx86_uldword)10)); tmp.mantissa /= (sx86_uldword)10; datz[i] |= ((char)(tmp.mantissa % ((sx86_uldword)10)))<<4; tmp.mantissa /= (sx86_uldword)10; } datz[9] = tmp.sign_bit ? ((char)0x80) : 0x00; /* pop */ softx86_popstack(ctx->ref_softx87_ctx); } /* the hard work behind FLD [mem32] is here */ void op_fld32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx87->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx87->state.status_word |= SX87_FPUSTAT_C1; else ctx87->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx87->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx87->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store */ ctx87->state.st[TOP].exponent = tmp.exponent; ctx87->state.st[TOP].mantissa = tmp.mantissa; ctx87->state.st[TOP].sign_bit = tmp.sign_bit; } /* the hard work behind FLD [mem64] is here */ void op_fld64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx87->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx87->state.status_word |= SX87_FPUSTAT_C1; else ctx87->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx87->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx87->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store */ ctx87->state.st[TOP].exponent = tmp.exponent; ctx87->state.st[TOP].mantissa = tmp.mantissa; ctx87->state.st[TOP].sign_bit = tmp.sign_bit; } /* FIADD [mem16] */ void op_fiadd16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fadd(ctx87,&ctx87->state.st[TOP],&tmp); } /* FICOM [mem16] */ void op_ficom16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fcom(ctx87,&ctx87->state.st[TOP],&tmp); } /* FICOMP [mem16] */ void op_ficomp16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fcom(ctx87,&ctx87->state.st[TOP],&tmp); softx86_popstack(ctx87); } /* FICOM [mem32] */ void op_ficom32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fcom(ctx87,&ctx87->state.st[TOP],&tmp); } /* FICOMP [mem32] */ void op_ficomp32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fcom(ctx87,&ctx87->state.st[TOP],&tmp); softx86_popstack(ctx87); } /* FISUB [mem16] */ void op_fisub16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fsub(ctx87,&ctx87->state.st[TOP],&tmp); } /* FIADD [mem32] */ void op_fiadd32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fadd(ctx87,&ctx87->state.st[TOP],&tmp); } /* FISUB [mem32] */ void op_fisub32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fsub(ctx87,&ctx87->state.st[TOP],&tmp); } /* FIDIV [mem32] */ void op_fidiv32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdiv(ctx87,&ctx87->state.st[TOP],&tmp); } /* FIDIVR [mem32] */ void op_fidivr32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdivr(ctx87,&ctx87->state.st[TOP],&tmp); } /* FIDIV [mem16] */ void op_fidiv16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdiv(ctx87,&ctx87->state.st[TOP],&tmp); } /* FIDIVR [mem16] */ void op_fidivr16(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 2 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_int16(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdivr(ctx87,&ctx87->state.st[TOP],&tmp); } /* FADD [mem32] */ void op_fadd32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fadd(ctx87,&ctx87->state.st[TOP],&tmp); } /* FDIV [mem32] */ void op_fdiv32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdiv(ctx87,&ctx87->state.st[TOP],&tmp); } /* FDIVR [mem32] */ void op_fdivr32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdivr(ctx87,&ctx87->state.st[TOP],&tmp); } /* FDIVR [mem64] */ void op_fdivr64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdivr(ctx87,&ctx87->state.st[TOP],&tmp); } /* FDIV [mem64] */ void op_fdiv64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fdiv(ctx87,&ctx87->state.st[TOP],&tmp); } /* FSUB [mem32] */ void op_fsub32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fsub(ctx87,&ctx87->state.st[TOP],&tmp); } /* FADD [mem64] */ void op_fadd64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fadd(ctx87,&ctx87->state.st[TOP],&tmp); } /* FSUB [mem64] */ void op_fsub64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&tmp); /* normalize */ softx87_normalize(ctx87,&tmp); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); op_fsub(ctx87,&ctx87->state.st[TOP],&tmp); } static void op_fcom_compflags(softx87_ctx* ctx,softx87_reg80 *diff) { if (diff->mantissa == 0) { // equal (basically zero no matter what the exponent) ctx->state.status_word |= SX87_FPUSTAT_C3; ctx->state.status_word &= ~(SX87_FPUSTAT_C2 | SX87_FPUSTAT_C0); } else if (diff->sign_bit == 1) { // st0 < src ctx->state.status_word |= SX87_FPUSTAT_C0; ctx->state.status_word &= ~(SX87_FPUSTAT_C3 | SX87_FPUSTAT_C2); } else if (diff->sign_bit == 0) { // st0 > src ctx->state.status_word &= ~(SX87_FPUSTAT_C3 | SX87_FPUSTAT_C2 | SX87_FPUSTAT_C0); } else { // TODO } } /* FCOM [mem64] */ void op_fcom64(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 src; softx87_reg80 st0; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 8 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp64(ctx87,datz,&src); /* normalize */ softx87_normalize(ctx87,&src); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); memcpy(&st0,&ctx87->state.st[TOP],sizeof(softx87_reg80)); softx87_normalize(ctx87,&st0); op_fsub(ctx87,&st0,&src); // st0 -= src /* what is the result? */ op_fcom_compflags(ctx87,&st0); } /* FCOMP [mem64] */ void op_fcomp64(softx86_ctx* ctx,char *datz,int sz) { op_fcom64(ctx,datz,sz); softx86_popstack(ctx->ref_softx87_ctx); } /* FCOM [mem32] */ void op_fcom32(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 src; softx87_reg80 st0; softx87_ctx* ctx87; int TOP; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 4 || !ctx87) return; /* convert to 80-bit floating point */ softx87_unpack_raw_fp32(ctx87,datz,&src); /* normalize */ softx87_normalize(ctx87,&src); /* do it */ TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); memcpy(&st0,&ctx87->state.st[TOP],sizeof(softx87_reg80)); softx87_normalize(ctx87,&st0); op_fsub(ctx87,&st0,&src); // st0 -= src /* what is the result? */ op_fcom_compflags(ctx87,&st0); } /* FCOMP [mem32] */ void op_fcomp32(softx86_ctx* ctx,char *datz,int sz) { op_fcom32(ctx,datz,sz); softx86_popstack(ctx->ref_softx87_ctx); } /* FBLD [mem80] */ void op_fbld80(softx86_ctx* ctx,char *datz,int sz) { softx87_reg80 tmp; softx87_ctx* ctx87; int TOP,i; /* sanity check */ ctx87 = (softx87_ctx*)ctx->ref_softx87_ctx; if (sz != 10 || !ctx87) return; /* think of it as a string where each character is stored in one nibble representing one digit. UNFORTUNATELY it's also stored backwards... */ if (datz[9] & 0x80) tmp.sign_bit = 1; else tmp.sign_bit = 0; tmp.exponent = 16383 + 63; tmp.mantissa = (sx86_uldword)0; for (i=17;i >= 0;i--) { tmp.mantissa *= (sx86_uldword)10; tmp.mantissa += (sx86_uldword)((datz[i>>1] >> ((i&1)*4))&0xF); } /* normalize */ softx87_normalize(ctx87,&tmp); TOP = SX87_FPUSTAT_TOP(ctx87->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx87->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx87->state.status_word |= SX87_FPUSTAT_C1; else ctx87->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx87->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx87->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store */ ctx87->state.st[TOP].exponent = tmp.exponent; ctx87->state.st[TOP].mantissa = tmp.mantissa; ctx87->state.st[TOP].sign_bit = tmp.sign_bit; } /* general purpose FADD */ void op_fadd(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { softx87_reg80 major; softx87_reg80 minor; sx87_uldword waste,threshhold; int exb; /* TODO: check and perform cases as documented: -infinity + (anything) = -infinity -infinity + +infinity = #IA exception NaN + (anything) = NaN */ /* in doing this... how many extra bits will we need? */ exb = (int)(src->mantissa>>((sx87_uldword)63)); exb |= (int)(dst->mantissa>>((sx87_uldword)63)); if (src->sign_bit != dst->sign_bit) exb++; /* avoid addition if it wouldn't make any difference */ if (dst->exponent >= (src->exponent+(64-exb))) return; /* copy src => dst if the destination value is dwarfed by the source value */ else if (dst->exponent <= (src->exponent-(64-exb))) { memcpy(dst,src,sizeof(softx87_reg80)); return; } /* scale them up so their exponents match */ if (dst->exponent > src->exponent) { memcpy(&major,dst,sizeof(softx87_reg80)); memcpy(&minor,src,sizeof(softx87_reg80)); } else if (dst->exponent < src->exponent) { memcpy(&major,src,sizeof(softx87_reg80)); memcpy(&minor,dst,sizeof(softx87_reg80)); } else { memcpy(&major,dst,sizeof(softx87_reg80)); memcpy(&minor,src,sizeof(softx87_reg80)); } /* "major" should have the highest exponent */ if ((major.exponent+exb) > minor.exponent) { int b; b = (major.exponent - minor.exponent)+exb; threshhold = (sx87_uldword)-1; threshhold >>= (sx87_uldword)(64-b); waste = minor.mantissa & threshhold; threshhold = (threshhold+1)>>1; /* scale up the minor value */ minor.exponent += b; minor.mantissa >>= (sx87_uldword)b; /* round it */ switch (SX87_FPUCTRLW_RNDCTL(ctx->state.control_word)) { case SX87_FPUCTRLW_RNDCTL_NEAREST: if (waste >= threshhold) minor.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_DOWNINF: if (waste != 0L && minor.sign_bit) minor.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_UPINF: if (waste != 0L && !minor.sign_bit) minor.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_ZERO: /* nothing */ break; } } if (exb > 0) { /* scale up the major value */ threshhold = (sx87_uldword)-1; threshhold >>= (sx87_uldword)(64-exb); waste = major.mantissa & threshhold; threshhold = (threshhold+1)>>1; major.exponent += exb; major.mantissa >>= (sx87_uldword)exb; /* round it */ switch (SX87_FPUCTRLW_RNDCTL(ctx->state.control_word)) { case SX87_FPUCTRLW_RNDCTL_NEAREST: if (waste >= threshhold) major.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_DOWNINF: if (waste != 0L && major.sign_bit) major.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_UPINF: if (waste != 0L && !major.sign_bit) major.mantissa++; break; case SX87_FPUCTRLW_RNDCTL_ZERO: /* nothing */ break; } } if (src->sign_bit == dst->sign_bit) { /* simply add */ dst->exponent = major.exponent; dst->sign_bit = major.sign_bit; dst->mantissa = minor.mantissa + major.mantissa; } else { /* negate mantissa based on sign */ if (minor.sign_bit) minor.mantissa = -minor.mantissa; if (major.sign_bit) major.mantissa = -major.mantissa; /* now add, treating 63rd bit as sign */ dst->exponent = major.exponent; dst->mantissa = minor.mantissa + major.mantissa; dst->sign_bit = dst->mantissa>>((sx87_uldword)63); if (dst->sign_bit) dst->mantissa = -dst->mantissa; } softx87_normalize(ctx,dst); } /* FCOM */ void op_fcom(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { softx87_reg80 st0; memcpy(&st0,dst,sizeof(softx87_reg80)); softx87_normalize(ctx,&st0); op_fsub(ctx,&st0,src); // st0 -= src /* what is the result? */ op_fcom_compflags(ctx,&st0); } /* FCOM */ void op_fcomp(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { softx87_reg80 st0; memcpy(&st0,dst,sizeof(softx87_reg80)); softx87_normalize(ctx,&st0); op_fsub(ctx,&st0,src); // st0 -= src /* what is the result? */ op_fcom_compflags(ctx,&st0); softx86_popstack(ctx); } /* general purpose FSUB */ void op_fsub(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { softx87_reg80 stm; /* cheap trick for now ;) */ memcpy(&stm,src,sizeof(softx87_reg80)); stm.sign_bit=!stm.sign_bit; op_fadd(ctx,dst,&stm); } /* general purpose FDIV */ void op_fdiv(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { double x,y; // TODO: consideration for NaN, etc. // TODO: make own dividing implementation, this is a cheap hack. x = softx87_get_fpu_double(ctx,dst,NULL); y = softx87_get_fpu_double(ctx,src,NULL); x /= y; softx87_set_fpu_double(ctx,dst,x); } /* general purpose FDIVR */ void op_fdivr(softx87_ctx* ctx,softx87_reg80 *dst,softx87_reg80 *src) { double x,y; // TODO: consideration for NaN, etc. // TODO: make own dividing implementation, this is a cheap hack. x = softx87_get_fpu_double(ctx,dst,NULL); y = softx87_get_fpu_double(ctx,src,NULL); x = y / x; softx87_set_fpu_double(ctx,dst,x); } static int Sfx87OpcodeExec_group_D8(sx87_ubyte opcode,softx87_ctx* ctx) { /* FADD ST(0),ST(i) */ if (opcode >= 0xC0 && opcode < 0xC8) { int st0,i; i = (int)(opcode-0xC0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fadd(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* FCOM ST(0),ST(i) */ else if (opcode >= 0xD0 && opcode < 0xD8) { int st0,i; i = (int)(opcode-0xD0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fcom(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* FCOMP ST(0),ST(i) */ else if (opcode >= 0xD8 && opcode < 0xE0) { int st0,i; i = (int)(opcode-0xD8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fcomp(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* FSUB ST(0),ST(i) */ else if (opcode >= 0xE0 && opcode < 0xE8) { int st0,i; i = (int)(opcode-0xE0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fsub(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* FDIV ST(0),ST(i) */ else if (opcode >= 0xF0 && opcode < 0xF8) { int st0,i; i = (int)(opcode-0xF0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdiv(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* FDIVR ST(0),ST(i) */ else if (opcode >= 0xF8) { int st0,i; i = (int)(opcode-0xF8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdivr(ctx,&ctx->state.st[st0],&ctx->state.st[i]); /* done */ return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FADD mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fadd32); else if (reg == 2) /* FCOM mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fcom32); else if (reg == 3) /* FCOMP mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fcomp32); else if (reg == 4) /* FSUB mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fsub32); else if (reg == 6) /* FDIV mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fdiv32); else if (reg == 7) /* FDIVR mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fdivr32); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_D8(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* FADD ST(0),ST(i) */ if (opcode >= 0xC0 && opcode < 0xC8) { sprintf(buf,"FADD ST(0),ST(%d)",opcode-0xC0); return 1; } /* FCOM ST(0),ST(i) */ else if (opcode >= 0xD0 && opcode < 0xD8) { sprintf(buf,"FCOM ST(0),ST(%d)",opcode-0xD0); return 1; } /* FCOMP ST(0),ST(i) */ else if (opcode >= 0xD8 && opcode < 0xE0) { sprintf(buf,"FCOMP ST(0),ST(%d)",opcode-0xD8); return 1; } /* FSUB ST(0),ST(i) */ else if (opcode >= 0xE0 && opcode < 0xE8) { sprintf(buf,"FSUB ST(0),ST(%d)",opcode-0xE0); return 1; } /* FDIV ST(0),ST(i) */ else if (opcode >= 0xF0 && opcode < 0xF8) { sprintf(buf,"FDIV ST(0),ST(%d)",opcode-0xF0); return 1; } /* FDIVR ST(0),ST(i) */ else if (opcode >= 0xF8) { sprintf(buf,"FDIVR ST(0),ST(%d)",opcode-0xF8); return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FADD %s (mem32)",s87op1_tmp); else if (reg == 2) sprintf(buf,"FCOM %s (mem32)",s87op1_tmp); else if (reg == 3) sprintf(buf,"FCOMP %s (mem32)",s87op1_tmp); else if (reg == 4) sprintf(buf,"FSUB %s (mem32)",s87op1_tmp); else if (reg == 6) sprintf(buf,"FDIV %s (mem32)",s87op1_tmp); else if (reg == 7) sprintf(buf,"FDIVR %s (mem32)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } void sx87_rnd(softx87_reg80 *val) { /* TODO: rounding modes */ if (1) { /* round to nearest */ if (val->exponent < 16382) { /* value is too small that val must be < 0.5 */ val->mantissa = 0; val->exponent = 16383; val->sign_bit = 0; } else if (val->exponent > (16383+63)) { /* value is too large to round */ } else { sx87_uldword t,s,m,i; s = (sx87_uldword)(val->exponent-16382); m = ((sx87_uldword)-1) >> s; t = val->mantissa & m; i = val->mantissa & (~m); /* special case: when s == 0, m = 0xFFFFFFFFFFFFFFFF which can overflow to 0 if incremented and shifted */ if (s == 0) s = (sx87_uldword)0x8000000000000000L; else s = (m + ((sx87_uldword)1)) >> ((sx87_uldword)1); /* m = mask to obtain fractional part t = fractional part i = whole part s = fractional part / 2 */ if (t >= s) i++; val->mantissa = i; } } } static int Sfx87OpcodeExec_group_D9(sx87_ubyte opcode,softx87_ctx* ctx) { /* FSCALE */ if (opcode == 0xFD) { sx86_uldword e; int ST0,ST1; ST0 = SX87_FPUSTAT_TOP(ctx->state.status_word); ST1 = (ST0 + 1) & 7; // TODO: cases with infinity, NaN, etc e = sx87_getint(&ctx->state.st[ST1]); e = ctx->state.st[ST0].exponent + e; if (e < 0) { ctx->state.st[ST0].exponent = 16383; ctx->state.st[ST0].mantissa = 0; } else if (e > 0x7FFF) { ctx->state.st[ST0].exponent = 0x7FFF; ctx->state.st[ST0].mantissa = (sx86_uldword)(-1); } else { ctx->state.st[ST0].exponent = (sx86_uword)(e); } return 1; } /* FRNDINT */ else if (opcode == 0xFC) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); sx87_rnd(&ctx->state.st[TOP]); return 1; } /* FINCSTP */ else if (opcode == 0xF7) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement Top Of Stack. nothing is tagged empty. */ TOP = (TOP+1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); /* done */ return 1; } /* FDECSTP */ else if (opcode == 0xF6) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement Top Of Stack. nothing is tagged empty. */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); /* done */ return 1; } /* F2XM1 */ else if (opcode == 0xF0) { int TOP; double v; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); v = softx87_get_fpu_register_double(ctx,TOP,NULL); /* NOTE: Intel says that this instruction is limited to domain -1.0 <= x <= 1.0 and anything outside that is undefined..... so what? */ // TODO: Make own implementation of exponential function v = pow(2.0,v); softx87_set_fpu_register_double(ctx,TOP,v); return 1; } /* FLD1 */ else if (opcode == 0xE8) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store */ ctx->state.st[TOP].exponent = 16383 + 63; ctx->state.st[TOP].mantissa = 1; ctx->state.st[TOP].sign_bit = 0; return 1; } /* FLDL2T */ else if (opcode == 0xE9) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store log2(10) = 3.3219280948873623478703194294894 */ softx87_set_fpu_register_double(ctx,TOP,(double)(3.3219280948873623478703194294894)); return 1; } /* FLDL2E */ else if (opcode == 0xEA) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store log2(e) = 1.4426950408889634073599246810019 */ softx87_set_fpu_register_double(ctx,TOP,(double)(1.4426950408889634073599246810019)); return 1; } /* FLDPI */ else if (opcode == 0xEB) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store PI the way Intel documents it (IA-32 Intel Architecture SW dev vol 1, ch 8.3.8) */ ctx->state.st[TOP].exponent = 16383 + 1; ctx->state.st[TOP].mantissa = (sx86_uldword)(0xC90FDAA22168C234); // C90F DAA2 2168 C234 C ctx->state.st[TOP].sign_bit = 0; return 1; } /* FLDLG2 */ else if (opcode == 0xEC) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store log10(2) = 0.30102999566398119521373889472449 */ softx87_set_fpu_register_double(ctx,TOP,(double)(0.30102999566398119521373889472449)); return 1; } /* FLDLN2 */ else if (opcode == 0xED) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store ln(2) = 0.69314718055994530941723212145818 */ softx87_set_fpu_register_double(ctx,TOP,(double)(0.69314718055994530941723212145818)); return 1; } /* FLDZ */ else if (opcode == 0xEE) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement TOP, tag as valid */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* store */ ctx->state.st[TOP].exponent = 16383 + 63; ctx->state.st[TOP].mantissa = 0; ctx->state.st[TOP].sign_bit = 0; return 1; } /* FABS */ else if (opcode == 0xE1) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); ctx->state.st[TOP].sign_bit = 0; return 1; } /* FCHS */ else if (opcode == 0xE0) { int TOP; TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); ctx->state.st[TOP].sign_bit = !ctx->state.st[TOP].sign_bit; return 1; } /* FNOP */ else if (opcode == 0xD0) { /* no-op */ return 1; } /* FLD ST(i) */ else if (opcode >= 0xC0 && opcode < 0xC8) { int TOP,i; i = (int)(opcode-0xC0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); TOP = SX87_FPUSTAT_TOP(ctx->state.status_word); /* set C1 if stack overflow */ if (SX87_FPUTAGW_TAG(ctx->state.tag_word,TOP) != SX87_FPUTAGVAL_EMPTY) ctx->state.status_word |= SX87_FPUSTAT_C1; else ctx->state.status_word &= ~SX87_FPUSTAT_C1; /* decrement Top Of Stack, Tag as valid, and store */ TOP = (TOP-1)&7; SX87_FPUSTAT_TOP_SET(ctx->state.status_word,TOP); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,TOP,SX87_FPUTAGVAL_VALID); /* copy */ ctx->state.st[TOP].exponent = ctx->state.st[i].exponent; ctx->state.st[TOP].mantissa = ctx->state.st[i].mantissa; ctx->state.st[TOP].sign_bit = ctx->state.st[i].sign_bit; /* done */ return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FLD mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fld32); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_D9(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* FSCALE */ if (opcode == 0xFD) { strcpy(buf,"FSCALE"); return 1; } /* FRNDINT */ else if (opcode == 0xFC) { strcpy(buf,"FRNDINT"); return 1; } /* FINCSTP */ else if (opcode == 0xF7) { strcpy(buf,"FINCSTP"); return 1; } /* FDECSTP */ else if (opcode == 0xF6) { strcpy(buf,"FDECSTP"); return 1; } /* F2XM1 */ else if (opcode == 0xF0) { strcpy(buf,"F2XM1"); return 1; } /* FLD1 */ else if (opcode == 0xE8) { strcpy(buf,"FLD1"); return 1; } /* FLDL2T */ else if (opcode == 0xE9) { strcpy(buf,"FLDL2T"); return 1; } /* FLDL2E */ else if (opcode == 0xEA) { strcpy(buf,"FLDL2E"); return 1; } /* FLDPI */ else if (opcode == 0xEB) { strcpy(buf,"FLDPI"); return 1; } /* FLDLG2 */ else if (opcode == 0xEC) { strcpy(buf,"FLDLG2"); return 1; } /* FLDLN2 */ else if (opcode == 0xED) { strcpy(buf,"FLDLN2"); return 1; } /* FLDZ */ else if (opcode == 0xEE) { strcpy(buf,"FLDZ"); return 1; } /* FABS */ else if (opcode == 0xE1) { strcpy(buf,"FABS"); return 1; } /* FCHS */ else if (opcode == 0xE0) { strcpy(buf,"FABS"); return 1; } /* FNOP */ else if (opcode == 0xD0) { strcpy(buf,"FNOP"); return 1; } /* FLD ST(i) */ else if (opcode >= 0xC0 && opcode < 0xC8) { sprintf(buf,"FLD ST(%d)",opcode-0xC0); return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FLD %s (mem32)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DA(sx87_ubyte opcode,softx87_ctx* ctx) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FIADD mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fiadd32); else if (reg == 2) /* FICOM mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_ficom32); else if (reg == 3) /* FICOMP mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_ficomp32); else if (reg == 4) /* FISUB mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fisub32); else if (reg == 6) /* FIDIV mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fidiv32); else if (reg == 7) /* FIDIVR mem32 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,4,op_fidivr32); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_DA(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FIADD %s (mem32)",s87op1_tmp); else if (reg == 2) sprintf(buf,"FICOM %s (mem32)",s87op1_tmp); else if (reg == 3) sprintf(buf,"FICOMP %s (mem32)",s87op1_tmp); else if (reg == 4) sprintf(buf,"FISUB %s (mem32)",s87op1_tmp); else if (reg == 6) sprintf(buf,"FIDIV %s (mem32)",s87op1_tmp); else if (reg == 7) sprintf(buf,"FIDIVR %s (mem32)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DB(sx87_ubyte opcode,softx87_ctx* ctx) { /* FINIT a.k.a. FNINIT */ if (opcode == 0xE3) { softx87_finit_setup(ctx); return 1; } /* FCLEX a.k.a. FNCLEX */ else if (opcode == 0xE2) { ctx->state.status_word = 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_DB(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* FINIT a.k.a. FNINIT */ if (opcode == 0xE3) { strcpy(buf,"FINIT"); return 1; } /* FCLEX a.k.a. FNCLEX */ else if (opcode == 0xE2) { strcpy(buf,"FCLEX"); return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DC(sx87_ubyte opcode,softx87_ctx* ctx) { /* FADD ST(i),ST(0) */ if (opcode >= 0xC0 && opcode < 0xC8) { int st0,i; i = (int)(opcode-0xC0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fadd(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* done */ return 1; } /* FSUB ST(i),ST(0) */ else if (opcode >= 0xE8 && opcode < 0xF0) { int st0,i; i = (int)(opcode-0xE8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fsub(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* done */ return 1; } /* FDIVR ST(i),ST(0) */ else if (opcode >= 0xF0 && opcode < 0xF8) { int st0,i; i = (int)(opcode-0xF0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdivr(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* done */ return 1; } /* FDIV ST(i),ST(0) */ else if (opcode >= 0xF8) { int st0,i; i = (int)(opcode-0xF8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdiv(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* done */ return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FADD mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fadd64); else if (reg == 2) /* FCOM mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fcom64); else if (reg == 3) /* FCOMP mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fcomp64); else if (reg == 4) /* FSUB mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fsub64); else if (reg == 6) /* FDIV mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fdiv64); else if (reg == 7) /* FDIVR mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fdivr64); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_DC(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* FADD ST(i),ST(0) */ if (opcode >= 0xC0 && opcode < 0xC8) { sprintf(buf,"FADD ST(%d),ST(0)",opcode-0xC0); return 1; } /* FSUB ST(i),ST(0) */ else if (opcode >= 0xE8 && opcode < 0xF0) { sprintf(buf,"FSUB ST(%d),ST(0)",opcode-0xE8); return 1; } /* FDIVR ST(i),ST(0) */ else if (opcode >= 0xF0 && opcode < 0xF8) { sprintf(buf,"FDIVR ST(%d),ST(0)",opcode-0xF0); return 1; } /* FDIV ST(i),ST(0) */ else if (opcode >= 0xF8) { sprintf(buf,"FDIV ST(%d),ST(0)",opcode-0xF8); return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FADD %s (mem64)",s87op1_tmp); else if (reg == 2) sprintf(buf,"FCOM %s (mem64)",s87op1_tmp); else if (reg == 3) sprintf(buf,"FCOMP %s (mem64)",s87op1_tmp); else if (reg == 4) sprintf(buf,"FSUB %s (mem64)",s87op1_tmp); else if (reg == 6) sprintf(buf,"FDIV %s (mem64)",s87op1_tmp); else if (reg == 7) sprintf(buf,"FDIVR %s (mem64)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DD(sx87_ubyte opcode,softx87_ctx* ctx) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FLD mem64 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,8,op_fld64); else return 0; return 1; } /* FFREE ST(i) */ else if (opcode >= 0xC0 && opcode < 0xC8) { int i; i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),(int)(opcode-0xC0)); SX87_FPUTAGW_TAG_SET(ctx->state.tag_word,i,SX87_FPUTAGVAL_EMPTY); return 1; } return 0; } static int Sfx87OpcodeDec_group_DD(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FLD %s (mem64)",s87op1_tmp); else return 0; return 1; } /* FFREE ST(i) */ else if (opcode >= 0xC0 && opcode < 0xC8) { sprintf(buf,"FFREE ST(%d)",opcode-0xC0); return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DE(sx87_ubyte opcode,softx87_ctx* ctx) { /* FADDP ST(i),ST(0) */ if (opcode >= 0xC0 && opcode < 0xC8) { int st0,i; i = (int)(opcode-0xC0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fadd(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* pop */ softx86_popstack(ctx); /* done */ return 1; } /* FCOMPP ST(0),ST(1) */ else if (opcode == 0xD9) { int st0,i; i = (int)(opcode-0xD9); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fcom(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* pop */ softx86_popstack(ctx); softx86_popstack(ctx); /* done */ return 1; } /* FSUBP ST(i),ST(0) */ else if (opcode >= 0xE8 && opcode < 0xEF) { int st0,i; i = (int)(opcode-0xE8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fsub(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* pop */ softx86_popstack(ctx); /* done */ return 1; } /* FDIVRP ST(i),ST(0) */ else if (opcode >= 0xF0 && opcode < 0xF8) { int st0,i; i = (int)(opcode-0xF0); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdivr(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* pop */ softx86_popstack(ctx); /* done */ return 1; } /* FDIVP ST(i),ST(0) */ else if (opcode >= 0xF8) { int st0,i; i = (int)(opcode-0xF8); i = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),i); st0 = SX87_FPU_ST(SX87_FPUSTAT_TOP(ctx->state.status_word),0); /* add */ op_fdiv(ctx,&ctx->state.st[i],&ctx->state.st[st0]); /* pop */ softx86_popstack(ctx); /* done */ return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 0) /* FIADD mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_fiadd16); else if (reg == 2) /* FICOM mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_ficom16); else if (reg == 3) /* FICOMP mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_ficomp16); else if (reg == 4) /* FISUB mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_fisub16); else if (reg == 6) /* FIDIV mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_fidiv16); else if (reg == 7) /* FIDIVR mem16 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,2,op_fidivr16); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_DE(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* FADDP ST(i),ST(0) */ if (opcode >= 0xC0 && opcode < 0xC8) { sprintf(buf,"FADDP ST(%d),ST(0)",opcode-0xC0); return 1; } /* FCOMPP ST(0),ST(1) */ else if (opcode == 0xD9) { strcpy(buf,"FCOMPP"); return 1; } /* FSUBP ST(i),ST(0) */ else if (opcode >= 0xE8 && opcode < 0xEF) { sprintf(buf,"FSUBP ST(%d),ST(0)",opcode-0xE8); return 1; } /* FDIVP ST(i),ST(0) */ else if (opcode >= 0xF8) { sprintf(buf,"FDIVP ST(%d),ST(0)",opcode-0xF8); return 1; } /* combo */ else if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 0) sprintf(buf,"FIADD %s (mem16)",s87op1_tmp); else if (reg == 2) sprintf(buf,"FICOM %s (mem16)",s87op1_tmp); else if (reg == 3) sprintf(buf,"FICOMP %s (mem16)",s87op1_tmp); else if (reg == 4) sprintf(buf,"FISUB %s (mem16)",s87op1_tmp); else if (reg == 6) sprintf(buf,"FIDIV %s (mem16)",s87op1_tmp); else if (reg == 7) sprintf(buf,"FIDIVR %s (mem16)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } static int Sfx87OpcodeExec_group_DF(sx87_ubyte opcode,softx87_ctx* ctx) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); if (reg == 4) /* FBLD mem80 */ ctx->callbacks.on_sx86_exec_full_modrmonly_memx(ctx->ref_softx86,mod,rm,10,op_fbld80); else if (reg == 6) /* FBSTP mem80 */ ctx->callbacks.on_sx86_exec_full_modrw_memx(ctx->ref_softx86,mod,rm,10,op_fbstp80); else return 0; return 1; } return 0; } static int Sfx87OpcodeDec_group_DF(sx87_ubyte opcode,softx87_ctx* ctx,char buf[128]) { /* combo */ if (opcode < 0xC0) { sx86_ubyte mod,reg,rm; sx86_modregrm_unpack(opcode,mod,reg,rm); ctx->callbacks.on_sx86_dec_full_modrmonly(ctx->ref_softx86,1,0,mod,rm,s87op1_tmp); if (reg == 4) sprintf(buf,"FBLD %s (mem80)",s87op1_tmp); else if (reg == 6) sprintf(buf,"FBSTP %s (mem80)",s87op1_tmp); else return 0; return 1; } buf[0]=0; return 0; } Sfx87OpcodeTable optab8087 = { { {Sfx87OpcodeExec_group_D8, Sfx87OpcodeDec_group_D8}, /* 0xD8xx */ {Sfx87OpcodeExec_group_D9, Sfx87OpcodeDec_group_D9}, /* 0xD9xx */ {Sfx87OpcodeExec_group_DA, Sfx87OpcodeDec_group_DA}, /* 0xDAxx */ {Sfx87OpcodeExec_group_DB, Sfx87OpcodeDec_group_DB}, /* 0xDBxx */ {Sfx87OpcodeExec_group_DC, Sfx87OpcodeDec_group_DC}, /* 0xDCxx */ {Sfx87OpcodeExec_group_DD, Sfx87OpcodeDec_group_DD}, /* 0xDDxx */ {Sfx87OpcodeExec_group_DE, Sfx87OpcodeDec_group_DE}, /* 0xDExx */ {Sfx87OpcodeExec_group_DF, Sfx87OpcodeDec_group_DF}, /* 0xDFxx */ }, };