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