DOSBox-X
|
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