DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/fpu/fpu_instructions.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include <math.h> /* for isinf, etc */
00020 #include "cpu/lazyflags.h"
00021 static void FPU_FINIT(void) {
00022         unsigned int i;
00023 
00024         FPU_SetCW(0x37F);
00025         fpu.sw = 0;
00026         TOP=FPU_GET_TOP();
00027         fpu.tags[0] = TAG_Empty;
00028         fpu.tags[1] = TAG_Empty;
00029         fpu.tags[2] = TAG_Empty;
00030         fpu.tags[3] = TAG_Empty;
00031         fpu.tags[4] = TAG_Empty;
00032         fpu.tags[5] = TAG_Empty;
00033         fpu.tags[6] = TAG_Empty;
00034         fpu.tags[7] = TAG_Empty;
00035         fpu.tags[8] = TAG_Valid; // is only used by us (FIXME: why?)
00036         for (i=0;i < 9;i++) fpu.use80[i] = false;
00037 }
00038 
00039 static void FPU_FCLEX(void){
00040         fpu.sw &= 0x7f00;                       //should clear exceptions
00041 }
00042 
00043 static void FPU_FNOP(void){
00044         return;
00045 }
00046 
00047 static void FPU_PREP_PUSH(void){
00048         TOP = (TOP - 1) &7;
00049 //      if (GCC_UNLIKELY(fpu.tags[TOP] != TAG_Empty)) E_Exit("FPU stack overflow");
00050         fpu.tags[TOP] = TAG_Valid;
00051         fpu.use80[TOP] = false; // the value given is already 64-bit precision, it's useless to emulate 80-bit precision
00052 }
00053 
00054 static void FPU_PUSH(double in){
00055         FPU_PREP_PUSH();
00056         fpu.regs[TOP].d = in;
00057         fpu.use80[TOP] = false; // the value given is already 64-bit precision, it's useless to emulate 80-bit precision
00058 //      LOG(LOG_FPU,LOG_ERROR)("Pushed at %d  %g to the stack",newtop,in);
00059         return;
00060 }
00061 
00062 
00063 static void FPU_FPOP(void){
00064 //      if (GCC_UNLIKELY(fpu.tags[TOP] == TAG_Empty)) E_Exit("FPU stack underflow");
00065         fpu.tags[TOP]=TAG_Empty;
00066         fpu.use80[TOP] = false; // the value given is already 64-bit precision, it's useless to emulate 80-bit precision
00067         //maybe set zero in it as well
00068         TOP = ((TOP+1)&7);
00069 //      LOG(LOG_FPU,LOG_ERROR)("popped from %d  %g off the stack",top,fpu.regs[top].d);
00070         return;
00071 }
00072 
00073 static double FROUND(double in){
00074         switch(fpu.round){
00075         case ROUND_Nearest:     
00076                 if (in-floor(in)>0.5) return (floor(in)+1);
00077                 else if (in-floor(in)<0.5) return (floor(in));
00078                 else return (((static_cast<Bit64s>(floor(in)))&1)!=0)?(floor(in)+1):(floor(in));
00079                 break;
00080         case ROUND_Down:
00081                 return (floor(in));
00082                 break;
00083         case ROUND_Up:
00084                 return (ceil(in));
00085                 break;
00086         case ROUND_Chop:
00087                 return in; //the cast afterwards will do it right maybe cast here
00088                 break;
00089         default:
00090                 return in;
00091                 break;
00092         }
00093 }
00094 
00095 #define BIAS80 16383
00096 #define BIAS64 1023
00097 
00098 static Real64 FPU_FLD80(PhysPt addr,FPU_Reg_80 &raw) {
00099         struct {
00100                 Bit16s begin;
00101                 FPU_Reg eind;
00102         } test;
00103         test.eind.l.lower = mem_readd(addr);
00104         test.eind.l.upper = (Bit32s)mem_readd(addr+4);
00105         test.begin = (Bit16s)mem_readw(addr+8);
00106    
00107         Bit64s exp64 = (((test.begin&0x7fff) - (Bit64s)BIAS80));
00108         Bit64s blah = ((exp64 >0)?exp64:-exp64)&0x3ff;
00109         Bit64s exp64final = ((exp64 >0)?blah:-blah) +BIAS64;
00110 
00111         Bit64s mant64 = (test.eind.ll >> 11) & LONGTYPE(0xfffffffffffff);
00112         Bit64s sign = (test.begin&0x8000)?1:0;
00113         FPU_Reg result;
00114         result.ll = (sign <<63)|(exp64final << 52)| mant64;
00115 
00116         if(test.eind.l.lower == 0 && (Bit32u)test.eind.l.upper == (Bit32u)0x80000000UL && (test.begin&0x7fff) == 0x7fff) {
00117                 //Detect INF and -INF (score 3.11 when drawing a slur.)
00118                 result.d = sign?-HUGE_VAL:HUGE_VAL;
00119         }
00120 
00121         /* store the raw value. */
00122         raw.raw.l = (Bit64u)test.eind.ll;
00123         raw.raw.h = (Bit16u)test.begin;
00124 
00125         return result.d;
00126 
00127         //mant64= test.mant80/2***64    * 2 **53 
00128 }
00129 
00130 static void FPU_ST80(PhysPt addr,Bitu reg,FPU_Reg_80 &raw,bool use80) {
00131         if (use80) {
00132                 // we have the raw 80-bit IEEE float value. we can just store
00133                 mem_writed(addr,(Bit32u)raw.raw.l);
00134                 mem_writed(addr+4,(Bit32u)(raw.raw.l >> (Bit64u)32));
00135                 mem_writew(addr+8,(Bit16u)raw.raw.h);
00136         }
00137         else {
00138                 // convert the "double" type to 80-bit IEEE and store
00139                 struct {
00140                         Bit16s begin;
00141                         FPU_Reg eind;
00142                 } test;
00143                 Bit64s sign80 = ((Bit64u)fpu.regs[reg].ll&ULONGTYPE(0x8000000000000000))?1:0;
00144                 Bit64s exp80 =  fpu.regs[reg].ll&LONGTYPE(0x7ff0000000000000);
00145                 Bit64s exp80final = (exp80>>52);
00146                 Bit64s mant80 = fpu.regs[reg].ll&LONGTYPE(0x000fffffffffffff);
00147                 Bit64s mant80final = (mant80 << 11);
00148                 if(fpu.regs[reg].d != 0){ //Zero is a special case
00149                         // Elvira wants the 8 and tcalc doesn't
00150                         mant80final |= (Bit64s)ULONGTYPE(0x8000000000000000);
00151                         //Ca-cyber doesn't like this when result is zero.
00152                         exp80final += (BIAS80 - BIAS64);
00153                 }
00154                 test.begin = (static_cast<Bit16s>(sign80)<<15)| static_cast<Bit16s>(exp80final);
00155                 test.eind.ll = mant80final;
00156                 mem_writed(addr,test.eind.l.lower);
00157                 mem_writed(addr+4,(uint32_t)test.eind.l.upper);
00158                 mem_writew(addr+8,(uint16_t)test.begin);
00159         }
00160 }
00161 
00162 
00163 static void FPU_FLD_F32(PhysPt addr,Bitu store_to) {
00164         union {
00165                 float f;
00166                 Bit32u l;
00167         }       blah;
00168         blah.l = mem_readd(addr);
00169         fpu.regs[store_to].d = static_cast<Real64>(blah.f);
00170         fpu.use80[store_to] = false;
00171 }
00172 
00173 static void FPU_FLD_F64(PhysPt addr,Bitu store_to) {
00174         fpu.regs[store_to].l.lower = mem_readd(addr);
00175         fpu.regs[store_to].l.upper = (Bit32s)mem_readd(addr+4);
00176         fpu.use80[store_to] = false;
00177 }
00178 
00179 static void FPU_FLD_F80(PhysPt addr) {
00180         fpu.regs[TOP].d = FPU_FLD80(addr,/*&*/fpu.regs_80[TOP]);
00181         fpu.use80[TOP] = true;
00182 }
00183 
00184 static void FPU_FLD_I16(PhysPt addr,Bitu store_to) {
00185         Bit16s blah = (Bit16s)mem_readw(addr);
00186         fpu.regs[store_to].d = static_cast<Real64>(blah);
00187         fpu.use80[store_to] = false;
00188 }
00189 
00190 static void FPU_FLD_I32(PhysPt addr,Bitu store_to) {
00191         Bit32s blah = (Bit32s)mem_readd(addr);
00192         fpu.regs[store_to].d = static_cast<Real64>(blah);
00193         fpu.use80[store_to] = false;
00194 }
00195 
00196 static void FPU_FLD_I64(PhysPt addr,Bitu store_to) {
00197         FPU_Reg blah;
00198         blah.l.lower = mem_readd(addr);
00199         blah.l.upper = (Bit32s)mem_readd(addr+4);
00200         fpu.regs[store_to].d = static_cast<Real64>(blah.ll);
00201         // store the signed 64-bit integer in the 80-bit format mantissa with faked exponent.
00202         // this is needed for DOS and Windows games that use the Pentium fast memcpy trick, using FLD/FST to copy 64 bits at a time.
00203         // I wonder if that trick is what helped spur Intel to make the MMX extensions :)
00204         fpu.regs_80[store_to].raw.l = (Bit64u)blah.ll;
00205         fpu.regs_80[store_to].raw.h = ((blah.ll/*sign bit*/ >> (Bit64u)63) ? 0x8000u : 0x0000u) + FPU_Reg_80_exponent_bias + 63u; // FIXME: Verify this is correct!
00206         fpu.use80[store_to] = true;
00207 }
00208 
00209 static void FPU_FBLD(PhysPt addr,Bitu store_to) {
00210         Bit64u val = 0;
00211         Bit8u in = 0;
00212         Bit64u base = 1;
00213         for(Bit8u i = 0;i < 9;i++){
00214                 in = mem_readb(addr + i);
00215                 val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9
00216                 base *= 10;
00217                 val += ((( in>>4)&0xf) * base);
00218                 base *= 10;
00219         }
00220 
00221         //last number, only now convert to float in order to get
00222         //the best signification
00223         Real64 temp = static_cast<Real64>(val);
00224         in = mem_readb(addr + 9);
00225         temp += ( (in&0xf) * base );
00226         if(in&0x80) temp *= -1.0;
00227         fpu.regs[store_to].d = temp;
00228         fpu.use80[store_to] = false;
00229 }
00230 
00231 
00232 static INLINE void FPU_FLD_F32_EA(PhysPt addr) {
00233         FPU_FLD_F32(addr,8);
00234 }
00235 static INLINE void FPU_FLD_F64_EA(PhysPt addr) {
00236         FPU_FLD_F64(addr,8);
00237 }
00238 static INLINE void FPU_FLD_I32_EA(PhysPt addr) {
00239         FPU_FLD_I32(addr,8);
00240 }
00241 static INLINE void FPU_FLD_I16_EA(PhysPt addr) {
00242         FPU_FLD_I16(addr,8);
00243 }
00244 
00245 
00246 static void FPU_FST_F32(PhysPt addr) {
00247         union {
00248                 float f;
00249                 Bit32u l;
00250         }       blah;
00251         //should depend on rounding method
00252         blah.f = static_cast<float>(fpu.regs[TOP].d);
00253         mem_writed(addr,blah.l);
00254 }
00255 
00256 static void FPU_FST_F64(PhysPt addr) {
00257         mem_writed(addr,(uint32_t)fpu.regs[TOP].l.lower);
00258         mem_writed(addr+4,(uint32_t)fpu.regs[TOP].l.upper);
00259 }
00260 
00261 static void FPU_FST_F80(PhysPt addr) {
00262         FPU_ST80(addr,TOP,/*&*/fpu.regs_80[TOP],fpu.use80[TOP]);
00263 }
00264 
00265 static void FPU_FST_I16(PhysPt addr) {
00266         mem_writew(addr,(uint16_t)static_cast<Bit16s>(FROUND(fpu.regs[TOP].d)));
00267 }
00268 
00269 static void FPU_FST_I32(PhysPt addr) {
00270         mem_writed(addr,(uint32_t)static_cast<Bit32s>(FROUND(fpu.regs[TOP].d)));
00271 }
00272 
00273 static void FPU_FST_I64(PhysPt addr) {
00274         FPU_Reg blah;
00275         if (fpu.use80[TOP] && (fpu.regs_80[TOP].raw.h & 0x7FFFu) == (0x0000u + FPU_Reg_80_exponent_bias + 63u)) {
00276                 // FIXME: This works so far for DOS demos that use the "Pentium memcpy trick" to copy 64 bits at a time.
00277                 //        What this code needs to do is take the exponent into account and then clamp the 64-bit int within range.
00278                 //        This cheap hack is good enough for now.
00279                 mem_writed(addr,(Bit32u)(fpu.regs_80[TOP].raw.l));
00280                 mem_writed(addr+4,(Bit32u)(fpu.regs_80[TOP].raw.l >> (Bit64u)32));
00281         }
00282         else {
00283                 blah.ll = static_cast<Bit64s>(FROUND(fpu.regs[TOP].d));
00284                 mem_writed(addr,(uint32_t)blah.l.lower);
00285                 mem_writed(addr+4,(uint32_t)blah.l.upper);
00286         }
00287 }
00288 
00289 static void FPU_FBST(PhysPt addr) {
00290         FPU_Reg val = fpu.regs[TOP];
00291         bool sign = false;
00292         if((Bit64u)fpu.regs[TOP].ll & ULONGTYPE(0x8000000000000000)) { //sign
00293                 sign=true;
00294                 val.d=-val.d;
00295         }
00296         //numbers from back to front
00297         Real64 temp=val.d;
00298         Bitu p;
00299         for(Bit8u i=0;i<9;i++){
00300                 val.d=temp;
00301                 temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
00302                 p = static_cast<Bitu>(val.d - 10.0*temp);  
00303                 val.d=temp;
00304                 temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
00305                 p |= (static_cast<Bitu>(val.d - 10.0*temp)<<4);
00306 
00307                 mem_writeb(addr+i,(Bit8u)p);
00308         }
00309         val.d=temp;
00310         temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
00311         p = static_cast<Bitu>(val.d - 10.0*temp);
00312         if(sign)
00313                 p|=0x80;
00314         mem_writeb(addr+9,(Bit8u)p);
00315 }
00316 
00317 #if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1910)
00318 /* std::isinf is C99 standard how could you NOT have this VS2008??? */
00319 # include <math.h>
00320 /* the purpose of this macro is to test for -/+inf. NaN is not inf. If finite or NaN it's not infinity */
00321 # define isinf(x) (!(_finite(x) || _isnan(x)))
00322 # define isdenormal(x) (_fpclass(x) == _FPCLASS_ND || _fpclass(x) == _FPCLASS_PD)
00323 #else
00324 # include <math.h>
00325 # include <cmath>
00326 # define isdenormal(x) (!std::isnormal(x))
00327 #endif
00328 
00329 static void FPU_FADD(Bitu op1, Bitu op2){
00330         // HACK: Set the denormal flag according to whether the source or final result is a denormalized number.
00331         //       This is vital if we don't want certain DOS programs to mis-detect our FPU emulation as an IIT clone chip when cputype == 286
00332         bool was_not_normal = isdenormal(fpu.regs[op1].d);
00333         fpu.regs[op1].d+=fpu.regs[op2].d;
00334         FPU_SET_D(was_not_normal || isdenormal(fpu.regs[op1].d) || isdenormal(fpu.regs[op2].d));
00335         fpu.use80[op1] = false; // we used the less precise version, drop the 80-bit precision
00336         //flags and such :)
00337         return;
00338 }
00339 
00340 static void FPU_FSIN(void){
00341         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00342         fpu.regs[TOP].d = sin(fpu.regs[TOP].d);
00343         FPU_SET_C2(0);
00344         //flags and such :)
00345         return;
00346 }
00347 
00348 static void FPU_FSINCOS(void){
00349         Real64 temp = fpu.regs[TOP].d;
00350         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00351         fpu.regs[TOP].d = sin(temp);
00352         FPU_PUSH(cos(temp));
00353         FPU_SET_C2(0);
00354         //flags and such :)
00355         return;
00356 }
00357 
00358 static void FPU_FCOS(void){
00359         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00360         fpu.regs[TOP].d = cos(fpu.regs[TOP].d);
00361         FPU_SET_C2(0);
00362         //flags and such :)
00363         return;
00364 }
00365 
00366 static void FPU_FSQRT(void){
00367         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00368         fpu.regs[TOP].d = sqrt(fpu.regs[TOP].d);
00369         //flags and such :)
00370         return;
00371 }
00372 static void FPU_FPATAN(void){
00373         fpu.use80[STV(1)] = false; // we used the less precise version, drop the 80-bit precision
00374         fpu.regs[STV(1)].d = atan2(fpu.regs[STV(1)].d,fpu.regs[TOP].d);
00375         FPU_FPOP();
00376         //flags and such :)
00377         return;
00378 }
00379 static void FPU_FPTAN(void){
00380         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00381         fpu.regs[TOP].d = tan(fpu.regs[TOP].d);
00382         FPU_PUSH(1.0);
00383         FPU_SET_C2(0);
00384         //flags and such :)
00385         return;
00386 }
00387 static void FPU_FDIV(Bitu st, Bitu other){
00388         fpu.use80[st] = false; // we used the less precise version, drop the 80-bit precision
00389         fpu.regs[st].d= fpu.regs[st].d/fpu.regs[other].d;
00390         //flags and such :)
00391         return;
00392 }
00393 
00394 static void FPU_FDIVR(Bitu st, Bitu other){
00395         fpu.use80[st] = false; // we used the less precise version, drop the 80-bit precision
00396         fpu.regs[st].d= fpu.regs[other].d/fpu.regs[st].d;
00397         // flags and such :)
00398         return;
00399 }
00400 
00401 static void FPU_FMUL(Bitu st, Bitu other){
00402         fpu.use80[st] = false; // we used the less precise version, drop the 80-bit precision
00403         fpu.regs[st].d*=fpu.regs[other].d;
00404         //flags and such :)
00405         return;
00406 }
00407 
00408 static void FPU_FSUB(Bitu st, Bitu other){
00409         fpu.use80[st] = false; // we used the less precise version, drop the 80-bit precision
00410         fpu.regs[st].d = fpu.regs[st].d - fpu.regs[other].d;
00411         //flags and such :)
00412         return;
00413 }
00414 
00415 static void FPU_FSUBR(Bitu st, Bitu other){
00416         fpu.use80[st] = false; // we used the less precise version, drop the 80-bit precision
00417         fpu.regs[st].d= fpu.regs[other].d - fpu.regs[st].d;
00418         //flags and such :)
00419         return;
00420 }
00421 
00422 static void FPU_FXCH(Bitu st, Bitu other){
00423         FPU_Reg_80 reg80 = fpu.regs_80[other];
00424         FPU_Tag tag = fpu.tags[other];
00425         FPU_Reg reg = fpu.regs[other];
00426         bool use80 = fpu.use80[other];
00427 
00428         fpu.regs_80[other] = fpu.regs_80[st];
00429         fpu.use80[other] = fpu.use80[st];
00430         fpu.tags[other] = fpu.tags[st];
00431         fpu.regs[other] = fpu.regs[st];
00432 
00433         fpu.regs_80[st] = reg80;
00434         fpu.use80[st] = use80;
00435         fpu.tags[st] = tag;
00436         fpu.regs[st] = reg;
00437 }
00438 
00439 static void FPU_FST(Bitu st, Bitu other){
00440         fpu.regs_80[other] = fpu.regs_80[st];
00441         fpu.use80[other] = fpu.use80[st];
00442         fpu.tags[other] = fpu.tags[st];
00443         fpu.regs[other] = fpu.regs[st];
00444 }
00445 
00446 static inline void FPU_FCMOV(Bitu st, Bitu other){
00447         fpu.regs_80[st] = fpu.regs_80[other];
00448         fpu.use80[st] = fpu.use80[other];
00449         fpu.tags[st] = fpu.tags[other];
00450         fpu.regs[st] = fpu.regs[other];
00451 }
00452 
00453 static void FPU_FCOM(Bitu st, Bitu other){
00454         if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || 
00455                 ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){
00456                 FPU_SET_C3(1);FPU_SET_C2(1);FPU_SET_C0(1);return;
00457         }
00458 
00459         /* HACK: If emulating a 286 processor we want the guest to think it's talking to a 287.
00460          *       For more info, read [http://www.intel-assembler.it/portale/5/cpu-identification/asm-source-to-find-intel-cpu.asp]. */
00461         /* TODO: This should eventually become an option, say, a dosbox.conf option named fputype where the user can enter
00462          *       "none" for no FPU, 287 or 387 for cputype=286 and cputype=386, or "auto" to match the CPU (8086 => 8087).
00463          *       If the FPU type is 387 or auto, then skip this hack. Else for 8087 and 287, use this hack. */
00464         if (CPU_ArchitectureType<CPU_ARCHTYPE_386) {
00465                 if ((std::isinf)(fpu.regs[st].d) && (std::isinf)(fpu.regs[other].d)) {
00466                         /* 8087/287 consider -inf == +inf and that's what DOS programs test for to detect 287 vs 387 */
00467                         FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return;
00468                 }
00469         }
00470 
00471         if(fpu.regs[st].d == fpu.regs[other].d){
00472                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return;
00473         }
00474         if(fpu.regs[st].d < fpu.regs[other].d){
00475                 FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(1);return;
00476         }
00477         // st > other
00478         FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(0);return;
00479 }
00480 
00481 static void FPU_FUCOM(Bitu st, Bitu other){
00482         //does atm the same as fcom 
00483         FPU_FCOM(st,other);
00484 }
00485 
00486 static void FPU_FUCOMI(Bitu st, Bitu other){
00487         
00488         FillFlags();
00489         SETFLAGBIT(OF,false);
00490 
00491         if(fpu.regs[st].d == fpu.regs[other].d){
00492                 SETFLAGBIT(ZF,true);SETFLAGBIT(PF,false);SETFLAGBIT(CF,false);return;
00493         }
00494         if(fpu.regs[st].d < fpu.regs[other].d){
00495                 SETFLAGBIT(ZF,false);SETFLAGBIT(PF,false);SETFLAGBIT(CF,true);return;
00496         }
00497         // st > other
00498         SETFLAGBIT(ZF,false);SETFLAGBIT(PF,false);SETFLAGBIT(CF,false);return;
00499 }
00500 
00501 static inline void FPU_FCOMI(Bitu st, Bitu other){
00502         FPU_FUCOMI(st,other);
00503 
00504         if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || 
00505                 ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){
00506                 SETFLAGBIT(ZF,true);SETFLAGBIT(PF,true);SETFLAGBIT(CF,true);return;
00507         }
00508 
00509 }
00510 
00511 static void FPU_FRNDINT(void){
00512         Bit64s temp= static_cast<Bit64s>(FROUND(fpu.regs[TOP].d));
00513         fpu.regs[TOP].d=static_cast<double>(temp);
00514         fpu.use80[TOP] = false;
00515 }
00516 
00517 static void FPU_FPREM(void){
00518         Real64 valtop = fpu.regs[TOP].d;
00519         Real64 valdiv = fpu.regs[STV(1)].d;
00520         Bit64s ressaved = static_cast<Bit64s>( (valtop/valdiv) );
00521 // Some backups
00522 //      Real64 res=valtop - ressaved*valdiv; 
00523 //      res= fmod(valtop,valdiv);
00524         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00525         fpu.regs[TOP].d = valtop - ressaved*valdiv;
00526         FPU_SET_C0(static_cast<Bitu>(ressaved&4));
00527         FPU_SET_C3(static_cast<Bitu>(ressaved&2));
00528         FPU_SET_C1(static_cast<Bitu>(ressaved&1));
00529         FPU_SET_C2(0);
00530 }
00531 
00532 static void FPU_FPREM1(void){
00533         Real64 valtop = fpu.regs[TOP].d;
00534         Real64 valdiv = fpu.regs[STV(1)].d;
00535         double quot = valtop/valdiv;
00536         double quotf = floor(quot);
00537         Bit64s ressaved;
00538         if (quot-quotf>0.5) ressaved = static_cast<Bit64s>(quotf+1);
00539         else if (quot-quotf<0.5) ressaved = static_cast<Bit64s>(quotf);
00540         else ressaved = static_cast<Bit64s>((((static_cast<Bit64s>(quotf))&1)!=0)?(quotf+1):(quotf));
00541         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00542         fpu.regs[TOP].d = valtop - ressaved*valdiv;
00543         FPU_SET_C0(static_cast<Bitu>(ressaved&4));
00544         FPU_SET_C3(static_cast<Bitu>(ressaved&2));
00545         FPU_SET_C1(static_cast<Bitu>(ressaved&1));
00546         FPU_SET_C2(0);
00547 }
00548 
00549 static void FPU_FXAM(void){
00550         if((Bit64u)fpu.regs[TOP].ll & ULONGTYPE(0x8000000000000000))    //sign
00551         { 
00552                 FPU_SET_C1(1);
00553         } 
00554         else 
00555         {
00556                 FPU_SET_C1(0);
00557         }
00558         if(fpu.tags[TOP] == TAG_Empty)
00559         {
00560                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1);
00561                 return;
00562         }
00563         if(fpu.regs[TOP].d == 0.0)              //zero or normalized number.
00564         { 
00565                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);
00566         }
00567         else
00568         {
00569                 FPU_SET_C3(0);FPU_SET_C2(1);FPU_SET_C0(0);
00570         }
00571 }
00572 
00573 
00574 static void FPU_F2XM1(void){
00575         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00576         fpu.regs[TOP].d = pow(2.0,fpu.regs[TOP].d) - 1;
00577         return;
00578 }
00579 
00580 static void FPU_FYL2X(void){
00581         fpu.use80[STV(1)] = false; // we used the less precise version, drop the 80-bit precision
00582         fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d)/log(static_cast<Real64>(2.0));
00583         FPU_FPOP();
00584         return;
00585 }
00586 
00587 static void FPU_FYL2XP1(void){
00588         fpu.use80[STV(1)] = false; // we used the less precise version, drop the 80-bit precision
00589         fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d+1.0)/log(static_cast<Real64>(2.0));
00590         FPU_FPOP();
00591         return;
00592 }
00593 
00594 static void FPU_FSCALE(void){
00595         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00596         fpu.regs[TOP].d *= pow(2.0,static_cast<Real64>(static_cast<Bit64s>(fpu.regs[STV(1)].d)));
00597         return; //2^x where x is chopped.
00598 }
00599 
00600 static void FPU_FSTENV(PhysPt addr){
00601         FPU_SET_TOP(TOP);
00602         if(!cpu.code.big) {
00603                 mem_writew(addr+0,static_cast<Bit16u>(fpu.cw));
00604                 mem_writew(addr+2,static_cast<Bit16u>(fpu.sw));
00605                 mem_writew(addr+4,static_cast<Bit16u>(FPU_GetTag()));
00606         } else { 
00607                 mem_writed(addr+0,static_cast<Bit32u>(fpu.cw));
00608                 mem_writed(addr+4,static_cast<Bit32u>(fpu.sw));
00609                 mem_writed(addr+8,static_cast<Bit32u>(FPU_GetTag()));
00610         }
00611 }
00612 
00613 static void FPU_FLDENV(PhysPt addr){
00614         Bit16u tag;
00615         Bit32u tagbig;
00616         Bitu cw;
00617         if(!cpu.code.big) {
00618                 cw     = mem_readw(addr+0);
00619                 fpu.sw = mem_readw(addr+2);
00620                 tag    = mem_readw(addr+4);
00621         } else { 
00622                 cw     = mem_readd(addr+0);
00623                 fpu.sw = (Bit16u)mem_readd(addr+4);
00624                 tagbig = mem_readd(addr+8);
00625                 tag    = static_cast<Bit16u>(tagbig);
00626         }
00627         FPU_SetTag(tag);
00628         FPU_SetCW(cw);
00629         TOP = FPU_GET_TOP();
00630 }
00631 
00632 static void FPU_FSAVE(PhysPt addr){
00633         FPU_FSTENV(addr);
00634         Bit8u start = (cpu.code.big?28:14);
00635         for(Bit8u i = 0;i < 8;i++){
00636                 FPU_ST80(addr+start,STV(i),/*&*/fpu.regs_80[STV(i)],fpu.use80[STV(i)]);
00637                 start += 10;
00638         }
00639         FPU_FINIT();
00640 }
00641 
00642 static void FPU_FRSTOR(PhysPt addr){
00643         FPU_FLDENV(addr);
00644         Bit8u start = (cpu.code.big?28:14);
00645         for(Bit8u i = 0;i < 8;i++){
00646                 fpu.regs[STV(i)].d = FPU_FLD80(addr+start,/*&*/fpu.regs_80[STV(i)]);
00647                 fpu.use80[STV(i)] = true;
00648                 start += 10;
00649         }
00650 }
00651 
00652 static void FPU_FXTRACT(void) {
00653         // function stores real bias in st and 
00654         // pushes the significant number onto the stack
00655         // if double ever uses a different base please correct this function
00656 
00657         FPU_Reg test = fpu.regs[TOP];
00658         Bit64s exp80 =  test.ll&LONGTYPE(0x7ff0000000000000);
00659         Bit64s exp80final = (exp80>>52) - BIAS64;
00660         Real64 mant = test.d / (pow(2.0,static_cast<Real64>(exp80final)));
00661         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00662         fpu.regs[TOP].d = static_cast<Real64>(exp80final);
00663         FPU_PUSH(mant);
00664 }
00665 
00666 static void FPU_FCHS(void){
00667         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00668         fpu.regs[TOP].d = -1.0*(fpu.regs[TOP].d);
00669 }
00670 
00671 static void FPU_FABS(void){
00672         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00673         fpu.regs[TOP].d = fabs(fpu.regs[TOP].d);
00674 }
00675 
00676 static void FPU_FTST(void){
00677         fpu.use80[8] = false; // we used the less precise version, drop the 80-bit precision
00678         fpu.regs[8].d = 0.0;
00679         FPU_FCOM(TOP,8);
00680 }
00681 
00682 static void FPU_FLD1(void){
00683         FPU_PREP_PUSH();
00684         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00685         fpu.regs[TOP].d = 1.0;
00686 }
00687 
00688 static void FPU_FLDL2T(void){
00689         FPU_PREP_PUSH();
00690         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00691         fpu.regs[TOP].d = L2T;
00692 }
00693 
00694 static void FPU_FLDL2E(void){
00695         FPU_PREP_PUSH();
00696         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00697         fpu.regs[TOP].d = L2E;
00698 }
00699 
00700 static void FPU_FLDPI(void){
00701         FPU_PREP_PUSH();
00702         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00703         fpu.regs[TOP].d = PI;
00704 }
00705 
00706 static void FPU_FLDLG2(void){
00707         FPU_PREP_PUSH();
00708         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00709         fpu.regs[TOP].d = LG2;
00710 }
00711 
00712 static void FPU_FLDLN2(void){
00713         FPU_PREP_PUSH();
00714         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00715         fpu.regs[TOP].d = LN2;
00716 }
00717 
00718 static void FPU_FLDZ(void){
00719         FPU_PREP_PUSH();
00720         fpu.use80[TOP] = false; // we used the less precise version, drop the 80-bit precision
00721         fpu.regs[TOP].d = 0.0;
00722         fpu.tags[TOP] = TAG_Zero;
00723 }
00724 
00725 
00726 static INLINE void FPU_FADD_EA(Bitu op1){
00727         FPU_FADD(op1,8);
00728 }
00729 static INLINE void FPU_FMUL_EA(Bitu op1){
00730         FPU_FMUL(op1,8);
00731 }
00732 static INLINE void FPU_FSUB_EA(Bitu op1){
00733         FPU_FSUB(op1,8);
00734 }
00735 static INLINE void FPU_FSUBR_EA(Bitu op1){
00736         FPU_FSUBR(op1,8);
00737 }
00738 static INLINE void FPU_FDIV_EA(Bitu op1){
00739         FPU_FDIV(op1,8);
00740 }
00741 static INLINE void FPU_FDIVR_EA(Bitu op1){
00742         FPU_FDIVR(op1,8);
00743 }
00744 static INLINE void FPU_FCOM_EA(Bitu op1){
00745         FPU_FCOM(op1,8);
00746 }
00747