DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/fpu/fpu_instructions_longdouble.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 
00022 #ifdef __GNUC__
00023 # if defined(__MINGW32__) || defined(MACOSX)
00024 #  include "fpu_control_x86.h"
00025 # else
00026 #  include <fpu_control.h>
00027 # endif
00028 static inline void FPU_SyncCW(void) {
00029     _FPU_SETCW(fpu.cw);
00030 }
00031 #else
00032 static inline void FPU_SyncCW(void) {
00033     /* nothing */
00034 }
00035 #endif
00036 
00037 static void FPU_FINIT(void) {
00038         FPU_SetCW(0x37F);
00039     FPU_SyncCW();
00040     fpu.sw = 0;
00041         TOP=FPU_GET_TOP();
00042         fpu.tags[0] = TAG_Empty;
00043         fpu.tags[1] = TAG_Empty;
00044         fpu.tags[2] = TAG_Empty;
00045         fpu.tags[3] = TAG_Empty;
00046         fpu.tags[4] = TAG_Empty;
00047         fpu.tags[5] = TAG_Empty;
00048         fpu.tags[6] = TAG_Empty;
00049         fpu.tags[7] = TAG_Empty;
00050         fpu.tags[8] = TAG_Valid; // is only used by us (FIXME: why?)
00051 }
00052 
00053 static void FPU_FCLEX(void){
00054         fpu.sw &= 0x7f00;                       //should clear exceptions
00055 }
00056 
00057 static void FPU_FNOP(void){
00058         return;
00059 }
00060 
00061 static void FPU_PUSH(long double in){
00062         TOP = (TOP - 1) &7;
00063         //actually check if empty
00064         fpu.tags[TOP] = TAG_Valid;
00065         fpu.regs_80[TOP].v = in;
00066 //      LOG(LOG_FPU,LOG_ERROR)("Pushed at %d  %g to the stack",newtop,in);
00067         return;
00068 }
00069 
00070 static void FPU_PREP_PUSH(void){
00071         TOP = (TOP - 1) &7;
00072         fpu.tags[TOP] = TAG_Valid;
00073 }
00074 
00075 static void FPU_FPOP(void){
00076         fpu.tags[TOP]=TAG_Empty;
00077         //maybe set zero in it as well
00078         TOP = ((TOP+1)&7);
00079 //      LOG(LOG_FPU,LOG_ERROR)("popped from %d  %g off the stack",top,fpu.regs[top].d);
00080         return;
00081 }
00082 
00083 static long double FROUND(long double in){
00084         switch(fpu.round){
00085         case ROUND_Nearest:     
00086                 if (in-floorl(in)>0.5) return (floorl(in)+1);
00087                 else if (in-floorl(in)<0.5) return (floorl(in));
00088                 else return (((static_cast<Bit64s>(floorl(in)))&1)!=0)?(floorl(in)+1):(floorl(in));
00089                 break;
00090         case ROUND_Down:
00091                 return (floorl(in));
00092                 break;
00093         case ROUND_Up:
00094                 return (ceill(in));
00095                 break;
00096         case ROUND_Chop:
00097                 return in; //the cast afterwards will do it right maybe cast here
00098                 break;
00099         default:
00100                 return in;
00101                 break;
00102         }
00103 }
00104 
00105 // TODO: Incorporate into paging.h
00106 static inline Bit64u mem_readq(PhysPt addr) {
00107     Bit64u tmp;
00108 
00109     tmp  = (Bit64u)mem_readd(addr);
00110     tmp |= (Bit64u)mem_readd(addr+4ul) << (Bit64u)32ul;
00111 
00112     return tmp;
00113 }
00114 
00115 static inline void mem_writeq(PhysPt addr,Bit64u v) {
00116     mem_writed(addr,    (Bit32u)v);
00117     mem_writed(addr+4ul,(Bit32u)(v >> (Bit64u)32ul));
00118 }
00119 
00120 #define BIAS80 16383
00121 #define BIAS64 1023
00122 
00123 static long double FPU_FLD80(PhysPt addr) {
00124     FPU_Reg_80 result;
00125     result.raw.l = mem_readq(addr);
00126     result.raw.h = mem_readw(addr+8ul);
00127         return result.v;
00128 }
00129 
00130 static void FPU_ST80(PhysPt addr,Bitu reg) {
00131     mem_writeq(addr    ,fpu.regs_80[reg].raw.l);
00132     mem_writew(addr+8ul,fpu.regs_80[reg].raw.h);
00133 }
00134 
00135 
00136 static void FPU_FLD_F32(PhysPt addr,Bitu store_to) {
00137     FPU_Reg_32 result;
00138     result.raw = mem_readd(addr);
00139         fpu.regs_80[store_to].v = static_cast<long double>(result.v);
00140 }
00141 
00142 static void FPU_FLD_F64(PhysPt addr,Bitu store_to) {
00143     FPU_Reg_64 result;
00144     result.raw = mem_readq(addr);
00145         fpu.regs_80[store_to].v = static_cast<long double>(result.v);
00146 }
00147 
00148 static void FPU_FLD_F80(PhysPt addr) {
00149         fpu.regs_80[TOP].v = FPU_FLD80(addr);
00150 }
00151 
00152 static void FPU_FLD_I16(PhysPt addr,Bitu store_to) {
00153         Bit16s blah = (Bit16s)mem_readw(addr);
00154         fpu.regs_80[store_to].v = static_cast<long double>(blah);
00155 }
00156 
00157 static void FPU_FLD_I32(PhysPt addr,Bitu store_to) {
00158         Bit32s blah = (Bit32s)mem_readd(addr);
00159         fpu.regs_80[store_to].v = static_cast<long double>(blah);
00160 }
00161 
00162 static void FPU_FLD_I64(PhysPt addr,Bitu store_to) {
00163     Bit64s blah = (Bit64s)mem_readq(addr);
00164         fpu.regs_80[store_to].v = static_cast<long double>(blah);
00165 }
00166 
00167 static void FPU_FBLD(PhysPt addr,Bitu store_to) {
00168         Bit64u val = 0;
00169         Bitu in = 0;
00170         Bit64u base = 1;
00171         for(Bitu i = 0;i < 9;i++){
00172                 in = mem_readb(addr + i);
00173                 val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9
00174                 base *= 10;
00175                 val += ((( in>>4)&0xf) * base);
00176                 base *= 10;
00177         }
00178 
00179         //last number, only now convert to float in order to get
00180         //the best signification
00181         long double temp = static_cast<long double>(val);
00182         in = mem_readb(addr + 9);
00183         temp += ( (in&0xf) * base );
00184         if(in&0x80) temp *= -1.0l;
00185         fpu.regs_80[store_to].v = temp;
00186 }
00187 
00188 
00189 static INLINE void FPU_FLD_F32_EA(PhysPt addr) {
00190         FPU_FLD_F32(addr,8);
00191 }
00192 static INLINE void FPU_FLD_F64_EA(PhysPt addr) {
00193         FPU_FLD_F64(addr,8);
00194 }
00195 static INLINE void FPU_FLD_I32_EA(PhysPt addr) {
00196         FPU_FLD_I32(addr,8);
00197 }
00198 static INLINE void FPU_FLD_I16_EA(PhysPt addr) {
00199         FPU_FLD_I16(addr,8);
00200 }
00201 
00202 
00203 static void FPU_FST_F32(PhysPt addr) {
00204     FPU_Reg_32 result;
00205     result.v = static_cast<float>(fpu.regs_80[TOP].v);
00206         mem_writed(addr,result.raw);
00207 }
00208 
00209 static void FPU_FST_F64(PhysPt addr) {
00210     FPU_Reg_64 result;
00211     result.v = static_cast<double>(fpu.regs_80[TOP].v);
00212         mem_writeq(addr,result.raw);
00213 }
00214 
00215 static void FPU_FST_F80(PhysPt addr) {
00216         FPU_ST80(addr,TOP);
00217 }
00218 
00219 static void FPU_FST_I16(PhysPt addr) {
00220         mem_writew(addr,(uint16_t)static_cast<Bit16s>(FROUND(fpu.regs_80[TOP].v)));
00221 }
00222 
00223 static void FPU_FST_I32(PhysPt addr) {
00224         mem_writed(addr,(uint32_t)static_cast<Bit32s>(FROUND(fpu.regs_80[TOP].v)));
00225 }
00226 
00227 static void FPU_FST_I64(PhysPt addr) {
00228         mem_writeq(addr,(uint64_t)static_cast<Bit64s>(FROUND(fpu.regs_80[TOP].v)));
00229 }
00230 
00231 static void FPU_FBST(PhysPt addr) {
00232         FPU_Reg_80 val = fpu.regs_80[TOP];
00233         bool sign = false;
00234         if(fpu.regs_80[TOP].raw.h & 0x8000u) { //sign
00235                 sign=true;
00236                 val.v=-val.v;
00237         }
00238         //numbers from back to front
00239         long double temp=val.v;
00240         Bitu p;
00241         for(Bitu i=0;i<9;i++){
00242                 val.v=temp;
00243                 temp = static_cast<long double>(static_cast<Bit64s>(floor(val.v/10.0l)));
00244                 p = static_cast<Bitu>(val.v - 10.0l*temp);  
00245                 val.v=temp;
00246                 temp = static_cast<long double>(static_cast<Bit64s>(floor(val.v/10.0l)));
00247                 p |= (static_cast<Bitu>(val.v - 10.0l*temp)<<4);
00248 
00249                 mem_writeb(addr+i,p);
00250         }
00251         val.v=temp;
00252         temp = static_cast<long double>(static_cast<Bit64s>(floor(val.v/10.0)));
00253         p = static_cast<Bitu>(val.v - 10.0l*temp);
00254         if(sign)
00255                 p|=0x80;
00256         mem_writeb(addr+9,p);
00257 }
00258 
00259 #if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1910)
00260 /* std::isinf is C99 standard how could you NOT have this VS2008??? */
00261 # include <math.h>
00262 /* the purpose of this macro is to test for -/+inf. NaN is not inf. If finite or NaN it's not infinity */
00263 # define isinf(x) (!(_finite(x) || _isnan(x)))
00264 # define isdenormal(x) (_fpclass(x) == _FPCLASS_ND || _fpclass(x) == _FPCLASS_PD)
00265 #else
00266 # include <math.h>
00267 # include <cmath>
00268 # define isdenormal(x) (!std::isnormal(x))
00269 #endif
00270 
00271 static void FPU_FADD(Bitu op1, Bitu op2){
00272     FPU_SyncCW();
00273         // HACK: Set the denormal flag according to whether the source or final result is a denormalized number.
00274         //       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
00275         bool was_not_normal = isdenormal(fpu.regs_80[op1].v);
00276         fpu.regs_80[op1].v+=fpu.regs_80[op2].v;
00277         FPU_SET_D(was_not_normal || isdenormal(fpu.regs_80[op1].v) || isdenormal(fpu.regs_80[op2].v));
00278         //flags and such :)
00279         return;
00280 }
00281 
00282 static void FPU_FSIN(void){
00283         fpu.regs_80[TOP].v = sinl(fpu.regs_80[TOP].v);
00284         FPU_SET_C2(0);
00285         //flags and such :)
00286         return;
00287 }
00288 
00289 static void FPU_FSINCOS(void){
00290         long double temp = fpu.regs_80[TOP].v;
00291         fpu.regs_80[TOP].v = sinl(temp);
00292         FPU_PUSH(cosl(temp));
00293         FPU_SET_C2(0);
00294         //flags and such :)
00295         return;
00296 }
00297 
00298 static void FPU_FCOS(void){
00299         fpu.regs_80[TOP].v = cosl(fpu.regs_80[TOP].v);
00300         FPU_SET_C2(0);
00301         //flags and such :)
00302         return;
00303 }
00304 
00305 static void FPU_FSQRT(void){
00306     FPU_SyncCW();
00307         fpu.regs_80[TOP].v = sqrtl(fpu.regs_80[TOP].v);
00308         //flags and such :)
00309         return;
00310 }
00311 static void FPU_FPATAN(void){
00312         fpu.regs_80[STV(1)].v = atan2l(fpu.regs_80[STV(1)].v,fpu.regs_80[TOP].v);
00313         FPU_FPOP();
00314         //flags and such :)
00315         return;
00316 }
00317 static void FPU_FPTAN(void){
00318         fpu.regs_80[TOP].v = tanl(fpu.regs_80[TOP].v);
00319         FPU_PUSH(1.0);
00320         FPU_SET_C2(0);
00321         //flags and such :)
00322         return;
00323 }
00324 static void FPU_FDIV(Bitu st, Bitu other){
00325     FPU_SyncCW();
00326         fpu.regs_80[st].v = fpu.regs_80[st].v/fpu.regs_80[other].v;
00327         //flags and such :)
00328         return;
00329 }
00330 
00331 static void FPU_FDIVR(Bitu st, Bitu other){
00332     FPU_SyncCW();
00333         fpu.regs_80[st].v = fpu.regs_80[other].v/fpu.regs_80[st].v;
00334         // flags and such :)
00335         return;
00336 }
00337 
00338 static void FPU_FMUL(Bitu st, Bitu other){
00339     FPU_SyncCW();
00340         fpu.regs_80[st].v *= fpu.regs_80[other].v;
00341         //flags and such :)
00342         return;
00343 }
00344 
00345 static void FPU_FSUB(Bitu st, Bitu other){
00346     FPU_SyncCW();
00347         fpu.regs_80[st].v = fpu.regs_80[st].v - fpu.regs_80[other].v;
00348         //flags and such :)
00349         return;
00350 }
00351 
00352 static void FPU_FSUBR(Bitu st, Bitu other){
00353     FPU_SyncCW();
00354         fpu.regs_80[st].v = fpu.regs_80[other].v - fpu.regs_80[st].v;
00355         //flags and such :)
00356         return;
00357 }
00358 
00359 static void FPU_FXCH(Bitu st, Bitu other){
00360         FPU_Reg_80 reg80 = fpu.regs_80[other];
00361         FPU_Tag tag = fpu.tags[other];
00362 
00363         fpu.regs_80[other] = fpu.regs_80[st];
00364         fpu.tags[other] = fpu.tags[st];
00365 
00366         fpu.regs_80[st] = reg80;
00367         fpu.tags[st] = tag;
00368 }
00369 
00370 static void FPU_FST(Bitu st, Bitu other){
00371         fpu.regs_80[other] = fpu.regs_80[st];
00372         fpu.tags[other] = fpu.tags[st];
00373 }
00374 
00375 static inline void FPU_FCMOV(Bitu st, Bitu other){
00376         fpu.regs_80[st] = fpu.regs_80[other];
00377         fpu.tags[st] = fpu.tags[other];
00378 }
00379 
00380 static void FPU_FCOM(Bitu st, Bitu other){
00381         if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || 
00382                 ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){
00383                 FPU_SET_C3(1);FPU_SET_C2(1);FPU_SET_C0(1);return;
00384         }
00385 
00386         /* HACK: If emulating a 286 processor we want the guest to think it's talking to a 287.
00387          *       For more info, read [http://www.intel-assembler.it/portale/5/cpu-identification/asm-source-to-find-intel-cpu.asp]. */
00388         /* TODO: This should eventually become an option, say, a dosbox.conf option named fputype where the user can enter
00389          *       "none" for no FPU, 287 or 387 for cputype=286 and cputype=386, or "auto" to match the CPU (8086 => 8087).
00390          *       If the FPU type is 387 or auto, then skip this hack. Else for 8087 and 287, use this hack. */
00391         if (CPU_ArchitectureType<CPU_ARCHTYPE_386) {
00392                 if ((std::isinf)(fpu.regs_80[st].v) && (std::isinf)(fpu.regs_80[other].v)) {
00393                         /* 8087/287 consider -inf == +inf and that's what DOS programs test for to detect 287 vs 387 */
00394                         FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return;
00395                 }
00396         }
00397 
00398         if(fpu.regs_80[st].v == fpu.regs_80[other].v){
00399                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return;
00400         }
00401         if(fpu.regs_80[st].v < fpu.regs_80[other].v){
00402                 FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(1);return;
00403         }
00404         // st > other
00405         FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(0);return;
00406 }
00407 
00408 static void FPU_FUCOM(Bitu st, Bitu other){
00409         //does atm the same as fcom 
00410         FPU_FCOM(st,other);
00411 }
00412 
00413 static void FPU_FUCOMI(Bitu st, Bitu other){
00414         
00415         FillFlags();
00416         SETFLAGBIT(OF,false);
00417 
00418         if(fpu.regs_80[st].v == fpu.regs_80[other].v){
00419                 SETFLAGBIT(ZF,true);SETFLAGBIT(PF,false);SETFLAGBIT(CF,false);return;
00420         }
00421         if(fpu.regs_80[st].v < fpu.regs_80[other].v){
00422                 SETFLAGBIT(ZF,false);SETFLAGBIT(PF,false);SETFLAGBIT(CF,true);return;
00423         }
00424         // st > other
00425         SETFLAGBIT(ZF,false);SETFLAGBIT(PF,false);SETFLAGBIT(CF,false);return;
00426 }
00427 
00428 static inline void FPU_FCOMI(Bitu st, Bitu other){
00429         FPU_FUCOMI(st,other);
00430 
00431         if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || 
00432                 ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){
00433                 SETFLAGBIT(ZF,true);SETFLAGBIT(PF,true);SETFLAGBIT(CF,true);return;
00434         }
00435 
00436 }
00437 
00438 static void FPU_FRNDINT(void){
00439         Bit64s temp= static_cast<Bit64s>(FROUND(fpu.regs_80[TOP].v));
00440         fpu.regs_80[TOP].v=static_cast<long double>(temp);
00441 }
00442 
00443 static void FPU_FPREM(void){
00444         long double valtop = fpu.regs_80[TOP].v;
00445         long double valdiv = fpu.regs_80[STV(1)].v;
00446         Bit64s ressaved = static_cast<Bit64s>( (valtop/valdiv) );
00447 // Some backups
00448 //      long double res=valtop - ressaved*valdiv; 
00449 //      res= fmod(valtop,valdiv);
00450         fpu.regs_80[TOP].v = valtop - ressaved*valdiv;
00451         FPU_SET_C0(static_cast<Bitu>(ressaved&4));
00452         FPU_SET_C3(static_cast<Bitu>(ressaved&2));
00453         FPU_SET_C1(static_cast<Bitu>(ressaved&1));
00454         FPU_SET_C2(0);
00455 }
00456 
00457 static void FPU_FPREM1(void){
00458         long double valtop = fpu.regs_80[TOP].v;
00459         long double valdiv = fpu.regs_80[STV(1)].v;
00460         long double quot = valtop/valdiv;
00461         long double quotf = floorl(quot);
00462         Bit64s ressaved;
00463         if (quot-quotf>0.5) ressaved = static_cast<Bit64s>(quotf+1);
00464         else if (quot-quotf<0.5) ressaved = static_cast<Bit64s>(quotf);
00465         else ressaved = static_cast<Bit64s>((((static_cast<Bit64s>(quotf))&1)!=0)?(quotf+1):(quotf));
00466         fpu.regs_80[TOP].v = valtop - ressaved*valdiv;
00467         FPU_SET_C0(static_cast<Bitu>(ressaved&4));
00468         FPU_SET_C3(static_cast<Bitu>(ressaved&2));
00469         FPU_SET_C1(static_cast<Bitu>(ressaved&1));
00470         FPU_SET_C2(0);
00471 }
00472 
00473 static void FPU_FXAM(void){
00474         if(fpu.regs_80[TOP].raw.h & 0x8000u)    //sign
00475         { 
00476                 FPU_SET_C1(1);
00477         } 
00478         else 
00479         {
00480                 FPU_SET_C1(0);
00481         }
00482         if(fpu.tags[TOP] == TAG_Empty)
00483         {
00484                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1);
00485                 return;
00486         }
00487         if(fpu.regs_80[TOP].v == 0.0l)          //zero or normalized number.
00488         { 
00489                 FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);
00490         }
00491         else
00492         {
00493                 FPU_SET_C3(0);FPU_SET_C2(1);FPU_SET_C0(0);
00494         }
00495 }
00496 
00497 
00498 static void FPU_F2XM1(void){
00499         fpu.regs_80[TOP].v = powl(2.0l,fpu.regs_80[TOP].v) - 1;
00500         return;
00501 }
00502 
00503 static void FPU_FYL2X(void){
00504         fpu.regs_80[STV(1)].v *= logl(fpu.regs_80[TOP].v)/logl(static_cast<long double>(2.0));
00505         FPU_FPOP();
00506         return;
00507 }
00508 
00509 static void FPU_FYL2XP1(void){
00510         fpu.regs_80[STV(1)].v *= logl(fpu.regs_80[TOP].v+1.0l)/logl(static_cast<long double>(2.0));
00511         FPU_FPOP();
00512         return;
00513 }
00514 
00515 static void FPU_FSCALE(void){
00516         fpu.regs_80[TOP].v *= powl(2.0,static_cast<long double>(static_cast<Bit64s>(fpu.regs_80[STV(1)].v)));
00517         return; //2^x where x is chopped.
00518 }
00519 
00520 static void FPU_FSTENV(PhysPt addr){
00521         FPU_SET_TOP(TOP);
00522         if(!cpu.code.big) {
00523                 mem_writew(addr+0,static_cast<Bit16u>(fpu.cw));
00524                 mem_writew(addr+2,static_cast<Bit16u>(fpu.sw));
00525                 mem_writew(addr+4,static_cast<Bit16u>(FPU_GetTag()));
00526         } else { 
00527                 mem_writed(addr+0,static_cast<Bit32u>(fpu.cw));
00528                 mem_writed(addr+4,static_cast<Bit32u>(fpu.sw));
00529                 mem_writed(addr+8,static_cast<Bit32u>(FPU_GetTag()));
00530         }
00531 }
00532 
00533 static void FPU_FLDENV(PhysPt addr){
00534         Bit16u tag;
00535         Bit32u tagbig;
00536         Bitu cw;
00537         if(!cpu.code.big) {
00538                 cw     = mem_readw(addr+0);
00539                 fpu.sw = mem_readw(addr+2);
00540                 tag    = mem_readw(addr+4);
00541         } else { 
00542                 cw     = mem_readd(addr+0);
00543                 fpu.sw = (Bit16u)mem_readd(addr+4);
00544                 tagbig = mem_readd(addr+8);
00545                 tag    = static_cast<Bit16u>(tagbig);
00546         }
00547         FPU_SetTag(tag);
00548         FPU_SetCW(cw);
00549     FPU_SyncCW();
00550         TOP = FPU_GET_TOP();
00551 }
00552 
00553 static void FPU_FSAVE(PhysPt addr){
00554         FPU_FSTENV(addr);
00555         Bitu start = (cpu.code.big?28:14);
00556         for(Bitu i = 0;i < 8;i++){
00557                 FPU_ST80(addr+start,STV(i));
00558                 start += 10;
00559         }
00560         FPU_FINIT();
00561 }
00562 
00563 static void FPU_FRSTOR(PhysPt addr){
00564         FPU_FLDENV(addr);
00565         Bitu start = (cpu.code.big?28:14);
00566         for(Bitu i = 0;i < 8;i++){
00567                 fpu.regs_80[STV(i)].v = FPU_FLD80(addr+start);
00568                 start += 10;
00569         }
00570 }
00571 
00572 static void FPU_FXTRACT(void) {
00573         // function stores real bias in st and 
00574         // pushes the significant number onto the stack
00575         // if double ever uses a different base please correct this function
00576 
00577         FPU_Reg_80 test = fpu.regs_80[TOP];
00578         Bit64s exp80 = test.raw.h & 0x7FFFu;
00579         Bit64s exp80final = exp80 - FPU_Reg_80_exponent_bias;
00580         long double mant = test.v / (powl(2.0,static_cast<long double>(exp80final)));
00581         fpu.regs_80[TOP].v = static_cast<long double>(exp80final);
00582         FPU_PUSH(mant);
00583 }
00584 
00585 static void FPU_FCHS(void){
00586         fpu.regs_80[TOP].v = -1.0l*(fpu.regs_80[TOP].v);
00587 }
00588 
00589 static void FPU_FABS(void){
00590         fpu.regs_80[TOP].v = fabsl(fpu.regs_80[TOP].v);
00591 }
00592 
00593 static void FPU_FTST(void){
00594         fpu.regs_80[8].v = 0.0;
00595         FPU_FCOM(TOP,8);
00596 }
00597 
00598 static void FPU_FLD1(void){
00599         FPU_PREP_PUSH();
00600         fpu.regs_80[TOP].v = 1.0;
00601 }
00602 
00603 static void FPU_FLDL2T(void){
00604         FPU_PREP_PUSH();
00605         fpu.regs_80[TOP].v = L2T;
00606 }
00607 
00608 static void FPU_FLDL2E(void){
00609         FPU_PREP_PUSH();
00610         fpu.regs_80[TOP].v = L2E;
00611 }
00612 
00613 static void FPU_FLDPI(void){
00614         FPU_PREP_PUSH();
00615         fpu.regs_80[TOP].v = PI;
00616 }
00617 
00618 static void FPU_FLDLG2(void){
00619         FPU_PREP_PUSH();
00620         fpu.regs_80[TOP].v = LG2;
00621 }
00622 
00623 static void FPU_FLDLN2(void){
00624         FPU_PREP_PUSH();
00625         fpu.regs_80[TOP].v = LN2;
00626 }
00627 
00628 static void FPU_FLDZ(void){
00629         FPU_PREP_PUSH();
00630         fpu.regs_80[TOP].v = 0.0;
00631         fpu.tags[TOP] = TAG_Zero;
00632 }
00633 
00634 
00635 static INLINE void FPU_FADD_EA(Bitu op1){
00636         FPU_FADD(op1,8);
00637 }
00638 static INLINE void FPU_FMUL_EA(Bitu op1){
00639         FPU_FMUL(op1,8);
00640 }
00641 static INLINE void FPU_FSUB_EA(Bitu op1){
00642         FPU_FSUB(op1,8);
00643 }
00644 static INLINE void FPU_FSUBR_EA(Bitu op1){
00645         FPU_FSUBR(op1,8);
00646 }
00647 static INLINE void FPU_FDIV_EA(Bitu op1){
00648         FPU_FDIV(op1,8);
00649 }
00650 static INLINE void FPU_FDIVR_EA(Bitu op1){
00651         FPU_FDIVR(op1,8);
00652 }
00653 static INLINE void FPU_FCOM_EA(Bitu op1){
00654         FPU_FCOM(op1,8);
00655 }
00656