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 00020 #include "dosbox.h" 00021 #if C_FPU 00022 00023 #include <math.h> 00024 #include <float.h> 00025 #include "paging.h" 00026 #include "cross.h" 00027 #include "mem.h" 00028 #include "fpu.h" 00029 #include "cpu.h" 00030 #include "../cpu/lazyflags.h" 00031 00032 FPU_rec fpu; 00033 00034 void FPU_FLDCW(PhysPt addr){ 00035 Bit16u temp = mem_readw(addr); 00036 FPU_SetCW(temp); 00037 } 00038 00039 Bit16u FPU_GetTag(void){ 00040 Bit16u tag=0; 00041 00042 for (Bitu i=0;i<8;i++) 00043 tag |= (fpu.tags[i]&3) << (2*i); 00044 00045 return tag; 00046 } 00047 00048 #if C_FPU_X86 00049 #include "fpu_instructions_x86.h" 00050 #elif defined(HAS_LONG_DOUBLE) 00051 #include "fpu_instructions_longdouble.h" 00052 #else 00053 #include "fpu_instructions.h" 00054 #endif 00055 00056 /* WATCHIT : ALWAYS UPDATE REGISTERS BEFORE AND AFTER USING THEM 00057 STATUS WORD => FPU_SET_TOP(TOP) BEFORE a read 00058 TOP=FPU_GET_TOP() after a write; 00059 */ 00060 00061 static void EATREE(Bitu _rm){ 00062 Bitu group=(_rm >> 3) & 7; 00063 switch(group){ 00064 case 0x00: /* FADD */ 00065 FPU_FADD_EA(TOP); 00066 break; 00067 case 0x01: /* FMUL */ 00068 FPU_FMUL_EA(TOP); 00069 break; 00070 case 0x02: /* FCOM */ 00071 FPU_FCOM_EA(TOP); 00072 break; 00073 case 0x03: /* FCOMP */ 00074 FPU_FCOM_EA(TOP); 00075 FPU_FPOP(); 00076 break; 00077 case 0x04: /* FSUB */ 00078 FPU_FSUB_EA(TOP); 00079 break; 00080 case 0x05: /* FSUBR */ 00081 FPU_FSUBR_EA(TOP); 00082 break; 00083 case 0x06: /* FDIV */ 00084 FPU_FDIV_EA(TOP); 00085 break; 00086 case 0x07: /* FDIVR */ 00087 FPU_FDIVR_EA(TOP); 00088 break; 00089 default: 00090 break; 00091 } 00092 } 00093 00094 void FPU_ESC0_EA(Bitu rm,PhysPt addr) { 00095 /* REGULAR TREE WITH 32 BITS REALS */ 00096 FPU_FLD_F32_EA(addr); 00097 EATREE(rm); 00098 } 00099 00100 void FPU_ESC0_Normal(Bitu rm) { 00101 Bitu group=(rm >> 3) & 7; 00102 Bitu sub=(rm & 7); 00103 switch (group){ 00104 case 0x00: /* FADD ST,STi */ 00105 FPU_FADD(TOP,STV(sub)); 00106 break; 00107 case 0x01: /* FMUL ST,STi */ 00108 FPU_FMUL(TOP,STV(sub)); 00109 break; 00110 case 0x02: /* FCOM STi */ 00111 FPU_FCOM(TOP,STV(sub)); 00112 break; 00113 case 0x03: /* FCOMP STi */ 00114 FPU_FCOM(TOP,STV(sub)); 00115 FPU_FPOP(); 00116 break; 00117 case 0x04: /* FSUB ST,STi */ 00118 FPU_FSUB(TOP,STV(sub)); 00119 break; 00120 case 0x05: /* FSUBR ST,STi */ 00121 FPU_FSUBR(TOP,STV(sub)); 00122 break; 00123 case 0x06: /* FDIV ST,STi */ 00124 FPU_FDIV(TOP,STV(sub)); 00125 break; 00126 case 0x07: /* FDIVR ST,STi */ 00127 FPU_FDIVR(TOP,STV(sub)); 00128 break; 00129 default: 00130 break; 00131 } 00132 } 00133 00134 void FPU_ESC1_EA(Bitu rm,PhysPt addr) { 00135 // floats 00136 Bitu group=(rm >> 3) & 7; 00137 Bitu sub=(rm & 7); 00138 switch(group){ 00139 case 0x00: /* FLD float*/ 00140 { 00141 unsigned char old_TOP = TOP; 00142 00143 try { 00144 FPU_PREP_PUSH(); 00145 FPU_FLD_F32(addr,TOP); 00146 } 00147 catch (const GuestPageFaultException& pf) { 00148 (void)pf; 00149 TOP = old_TOP; 00150 throw; 00151 } 00152 } 00153 break; 00154 case 0x01: /* UNKNOWN */ 00155 LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",(int)group,(int)sub); 00156 break; 00157 case 0x02: /* FST float*/ 00158 FPU_FST_F32(addr); 00159 break; 00160 case 0x03: /* FSTP float*/ 00161 FPU_FST_F32(addr); 00162 FPU_FPOP(); 00163 break; 00164 case 0x04: /* FLDENV */ 00165 FPU_FLDENV(addr); 00166 break; 00167 case 0x05: /* FLDCW */ 00168 FPU_FLDCW(addr); 00169 break; 00170 case 0x06: /* FSTENV */ 00171 FPU_FSTENV(addr); 00172 break; 00173 case 0x07: /* FNSTCW*/ 00174 mem_writew(addr,fpu.cw); 00175 break; 00176 default: 00177 LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",(int)group,(int)sub); 00178 break; 00179 } 00180 } 00181 00182 void FPU_ESC1_Normal(Bitu rm) { 00183 Bitu group=(rm >> 3) & 7; 00184 Bitu sub=(rm & 7); 00185 switch (group){ 00186 case 0x00: /* FLD STi */ 00187 { 00188 Bitu reg_from=STV(sub); 00189 FPU_PREP_PUSH(); 00190 FPU_FST(reg_from, TOP); 00191 break; 00192 } 00193 case 0x01: /* FXCH STi */ 00194 FPU_FXCH(TOP,STV(sub)); 00195 break; 00196 case 0x02: /* FNOP */ 00197 FPU_FNOP(); 00198 break; 00199 case 0x03: /* FSTP STi */ 00200 FPU_FST(TOP,STV(sub)); 00201 FPU_FPOP(); 00202 break; 00203 case 0x04: 00204 switch(sub){ 00205 case 0x00: /* FCHS */ 00206 FPU_FCHS(); 00207 break; 00208 case 0x01: /* FABS */ 00209 FPU_FABS(); 00210 break; 00211 case 0x02: /* UNKNOWN */ 00212 case 0x03: /* ILLEGAL */ 00213 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00214 break; 00215 case 0x04: /* FTST */ 00216 FPU_FTST(); 00217 break; 00218 case 0x05: /* FXAM */ 00219 FPU_FXAM(); 00220 break; 00221 case 0x06: /* FTSTP (cyrix)*/ 00222 case 0x07: /* UNKNOWN */ 00223 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00224 break; 00225 } 00226 break; 00227 case 0x05: 00228 switch(sub){ 00229 case 0x00: /* FLD1 */ 00230 FPU_FLD1(); 00231 break; 00232 case 0x01: /* FLDL2T */ 00233 FPU_FLDL2T(); 00234 break; 00235 case 0x02: /* FLDL2E */ 00236 FPU_FLDL2E(); 00237 break; 00238 case 0x03: /* FLDPI */ 00239 FPU_FLDPI(); 00240 break; 00241 case 0x04: /* FLDLG2 */ 00242 FPU_FLDLG2(); 00243 break; 00244 case 0x05: /* FLDLN2 */ 00245 FPU_FLDLN2(); 00246 break; 00247 case 0x06: /* FLDZ*/ 00248 FPU_FLDZ(); 00249 break; 00250 case 0x07: /* ILLEGAL */ 00251 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00252 break; 00253 } 00254 break; 00255 case 0x06: 00256 switch(sub){ 00257 case 0x00: /* F2XM1 */ 00258 FPU_F2XM1(); 00259 break; 00260 case 0x01: /* FYL2X */ 00261 FPU_FYL2X(); 00262 break; 00263 case 0x02: /* FPTAN */ 00264 FPU_FPTAN(); 00265 break; 00266 case 0x03: /* FPATAN */ 00267 FPU_FPATAN(); 00268 break; 00269 case 0x04: /* FXTRACT */ 00270 FPU_FXTRACT(); 00271 break; 00272 case 0x05: /* FPREM1 */ 00273 FPU_FPREM1(); 00274 break; 00275 case 0x06: /* FDECSTP */ 00276 TOP = (TOP - 1) & 7; 00277 break; 00278 case 0x07: /* FINCSTP */ 00279 TOP = (TOP + 1) & 7; 00280 break; 00281 default: 00282 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00283 break; 00284 } 00285 break; 00286 case 0x07: 00287 switch(sub){ 00288 case 0x00: /* FPREM */ 00289 FPU_FPREM(); 00290 break; 00291 case 0x01: /* FYL2XP1 */ 00292 FPU_FYL2XP1(); 00293 break; 00294 case 0x02: /* FSQRT */ 00295 FPU_FSQRT(); 00296 break; 00297 case 0x03: /* FSINCOS */ 00298 FPU_FSINCOS(); 00299 break; 00300 case 0x04: /* FRNDINT */ 00301 FPU_FRNDINT(); 00302 break; 00303 case 0x05: /* FSCALE */ 00304 FPU_FSCALE(); 00305 break; 00306 case 0x06: /* FSIN */ 00307 FPU_FSIN(); 00308 break; 00309 case 0x07: /* FCOS */ 00310 FPU_FCOS(); 00311 break; 00312 default: 00313 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00314 break; 00315 } 00316 break; 00317 default: 00318 LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",(int)group,(int)sub); 00319 } 00320 } 00321 00322 00323 void FPU_ESC2_EA(Bitu rm,PhysPt addr) { 00324 /* 32 bits integer operants */ 00325 FPU_FLD_I32_EA(addr); 00326 EATREE(rm); 00327 } 00328 00329 void FPU_ESC2_Normal(Bitu rm) { 00330 Bitu group=(rm >> 3) & 7; 00331 Bitu sub=(rm & 7); 00332 switch(group){ 00333 case 0x00: /* FCMOVB STi */ 00334 if (TFLG_B) FPU_FCMOV(TOP,STV(sub)); 00335 break; 00336 case 0x01: /* FCMOVE STi */ 00337 if (TFLG_Z) FPU_FCMOV(TOP,STV(sub)); 00338 break; 00339 case 0x02: /* FCMOVBE STi */ 00340 if (TFLG_BE) FPU_FCMOV(TOP,STV(sub)); 00341 break; 00342 case 0x03: /* FCMOVU STi */ 00343 if (TFLG_P) FPU_FCMOV(TOP,STV(sub)); 00344 break; 00345 case 0x05: 00346 switch(sub){ 00347 case 0x01: /* FUCOMPP */ 00348 FPU_FUCOM(TOP,STV(1)); 00349 FPU_FPOP(); 00350 FPU_FPOP(); 00351 break; 00352 default: 00353 LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",(int)group,(int)sub); 00354 break; 00355 } 00356 break; 00357 default: 00358 LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",(int)group,(int)sub); 00359 break; 00360 } 00361 } 00362 00363 00364 void FPU_ESC3_EA(Bitu rm,PhysPt addr) { 00365 Bitu group=(rm >> 3) & 7; 00366 Bitu sub=(rm & 7); 00367 00368 switch(group){ 00369 case 0x00: /* FILD */ 00370 { 00371 unsigned char old_TOP = TOP; 00372 00373 try { 00374 FPU_PREP_PUSH(); 00375 FPU_FLD_I32(addr,TOP); 00376 } 00377 catch (const GuestPageFaultException& pf) { 00378 (void)pf; 00379 TOP = old_TOP; 00380 throw; 00381 } 00382 } 00383 break; 00384 case 0x01: /* FISTTP */ 00385 LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00386 break; 00387 case 0x02: /* FIST */ 00388 FPU_FST_I32(addr); 00389 break; 00390 case 0x03: /* FISTP */ 00391 FPU_FST_I32(addr); 00392 FPU_FPOP(); 00393 break; 00394 case 0x05: /* FLD 80 Bits Real */ 00395 { 00396 unsigned char old_TOP = TOP; 00397 00398 try { 00399 FPU_PREP_PUSH(); 00400 FPU_FLD_F80(addr); 00401 } 00402 catch (const GuestPageFaultException& pf) { 00403 (void)pf; 00404 TOP = old_TOP; 00405 throw; 00406 } 00407 } 00408 break; 00409 case 0x07: /* FSTP 80 Bits Real */ 00410 FPU_FST_F80(addr); 00411 FPU_FPOP(); 00412 break; 00413 default: 00414 LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00415 } 00416 } 00417 00418 void FPU_ESC3_Normal(Bitu rm) { 00419 Bitu group=(rm >> 3) & 7; 00420 Bitu sub=(rm & 7); 00421 switch (group) { 00422 case 0x00: /* FCMOVNB STi */ 00423 if (TFLG_NB) FPU_FCMOV(TOP,STV(sub)); 00424 break; 00425 case 0x01: /* FCMOVNE STi */ 00426 if (TFLG_NZ) FPU_FCMOV(TOP,STV(sub)); 00427 break; 00428 case 0x02: /* FCMOVNBE STi */ 00429 if (TFLG_NBE) FPU_FCMOV(TOP,STV(sub)); 00430 break; 00431 case 0x03: /* FCMOVNU STi */ 00432 if (TFLG_NP) FPU_FCMOV(TOP,STV(sub)); 00433 break; 00434 case 0x04: 00435 switch (sub) { 00436 case 0x00: //FNENI 00437 case 0x01: //FNDIS 00438 LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",(int)sub); 00439 break; 00440 case 0x02: //FNCLEX FCLEX 00441 FPU_FCLEX(); 00442 break; 00443 case 0x03: //FNINIT FINIT 00444 FPU_FINIT(); 00445 break; 00446 case 0x04: //FNSETPM 00447 case 0x05: //FRSTPM 00448 // LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); 00449 FPU_FNOP(); 00450 break; 00451 default: 00452 E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",(int)group,(int)sub); 00453 } 00454 break; 00455 case 0x05: /* FUCOMI STi */ 00456 FPU_FUCOMI(TOP,STV(sub)); 00457 break; 00458 case 0x06: /* FCOMI STi */ 00459 FPU_FCOMI(TOP,STV(sub)); 00460 break; 00461 default: 00462 LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",(int)group,(int)sub); 00463 break; 00464 } 00465 return; 00466 } 00467 00468 00469 void FPU_ESC4_EA(Bitu rm,PhysPt addr) { 00470 /* REGULAR TREE WITH 64 BITS REALS */ 00471 FPU_FLD_F64_EA(addr); 00472 EATREE(rm); 00473 } 00474 00475 void FPU_ESC4_Normal(Bitu rm) { 00476 /* LOOKS LIKE number 6 without popping */ 00477 Bitu group=(rm >> 3) & 7; 00478 Bitu sub=(rm & 7); 00479 switch(group){ 00480 case 0x00: /* FADD STi,ST*/ 00481 FPU_FADD(STV(sub),TOP); 00482 break; 00483 case 0x01: /* FMUL STi,ST*/ 00484 FPU_FMUL(STV(sub),TOP); 00485 break; 00486 case 0x02: /* FCOM*/ 00487 FPU_FCOM(TOP,STV(sub)); 00488 break; 00489 case 0x03: /* FCOMP*/ 00490 FPU_FCOM(TOP,STV(sub)); 00491 FPU_FPOP(); 00492 break; 00493 case 0x04: /* FSUBR STi,ST*/ 00494 FPU_FSUBR(STV(sub),TOP); 00495 break; 00496 case 0x05: /* FSUB STi,ST*/ 00497 FPU_FSUB(STV(sub),TOP); 00498 break; 00499 case 0x06: /* FDIVR STi,ST*/ 00500 FPU_FDIVR(STV(sub),TOP); 00501 break; 00502 case 0x07: /* FDIV STi,ST*/ 00503 FPU_FDIV(STV(sub),TOP); 00504 break; 00505 default: 00506 break; 00507 } 00508 } 00509 00510 void FPU_ESC5_EA(Bitu rm,PhysPt addr) { 00511 Bitu group=(rm >> 3) & 7; 00512 Bitu sub=(rm & 7); 00513 switch(group){ 00514 case 0x00: /* FLD double real*/ 00515 { 00516 unsigned char old_TOP = TOP; 00517 00518 try { 00519 FPU_PREP_PUSH(); 00520 FPU_FLD_F64(addr,TOP); 00521 } 00522 catch (const GuestPageFaultException& pf) { 00523 (void)pf; 00524 TOP = old_TOP; 00525 throw; 00526 } 00527 } 00528 break; 00529 case 0x01: /* FISTTP longint*/ 00530 LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00531 break; 00532 case 0x02: /* FST double real*/ 00533 FPU_FST_F64(addr); 00534 break; 00535 case 0x03: /* FSTP double real*/ 00536 FPU_FST_F64(addr); 00537 FPU_FPOP(); 00538 break; 00539 case 0x04: /* FRSTOR */ 00540 FPU_FRSTOR(addr); 00541 break; 00542 case 0x06: /* FSAVE */ 00543 FPU_FSAVE(addr); 00544 break; 00545 case 0x07: /*FNSTSW NG DISAGREES ON THIS*/ 00546 FPU_SET_TOP(TOP); 00547 mem_writew(addr,fpu.sw); 00548 //seems to break all dos4gw games :) 00549 break; 00550 default: 00551 LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00552 } 00553 } 00554 00555 void FPU_ESC5_Normal(Bitu rm) { 00556 Bitu group=(rm >> 3) & 7; 00557 Bitu sub=(rm & 7); 00558 switch(group){ 00559 case 0x00: /* FFREE STi */ 00560 fpu.tags[STV(sub)]=TAG_Empty; 00561 break; 00562 case 0x01: /* FXCH STi*/ 00563 FPU_FXCH(TOP,STV(sub)); 00564 break; 00565 case 0x02: /* FST STi */ 00566 FPU_FST(TOP,STV(sub)); 00567 break; 00568 case 0x03: /* FSTP STi*/ 00569 FPU_FST(TOP,STV(sub)); 00570 FPU_FPOP(); 00571 break; 00572 case 0x04: /* FUCOM STi */ 00573 FPU_FUCOM(TOP,STV(sub)); 00574 break; 00575 case 0x05: /*FUCOMP STi */ 00576 FPU_FUCOM(TOP,STV(sub)); 00577 FPU_FPOP(); 00578 break; 00579 default: 00580 LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",(int)group,(int)sub); 00581 break; 00582 } 00583 } 00584 00585 void FPU_ESC6_EA(Bitu rm,PhysPt addr) { 00586 /* 16 bit (word integer) operants */ 00587 FPU_FLD_I16_EA(addr); 00588 EATREE(rm); 00589 } 00590 00591 void FPU_ESC6_Normal(Bitu rm) { 00592 /* all P variants working only on registers */ 00593 /* get top before switch and pop afterwards */ 00594 Bitu group=(rm >> 3) & 7; 00595 Bitu sub=(rm & 7); 00596 switch(group){ 00597 case 0x00: /*FADDP STi,ST*/ 00598 FPU_FADD(STV(sub),TOP); 00599 break; 00600 case 0x01: /* FMULP STi,ST*/ 00601 FPU_FMUL(STV(sub),TOP); 00602 break; 00603 case 0x02: /* FCOMP5*/ 00604 FPU_FCOM(TOP,STV(sub)); 00605 break; /* TODO IS THIS ALLRIGHT ????????? */ 00606 case 0x03: /*FCOMPP*/ 00607 if(sub != 1) { 00608 LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",(int)group,(int)sub); 00609 return; 00610 } 00611 FPU_FCOM(TOP,STV(1)); 00612 FPU_FPOP(); /* extra pop at the bottom*/ 00613 break; 00614 case 0x04: /* FSUBRP STi,ST*/ 00615 FPU_FSUBR(STV(sub),TOP); 00616 break; 00617 case 0x05: /* FSUBP STi,ST*/ 00618 FPU_FSUB(STV(sub),TOP); 00619 break; 00620 case 0x06: /* FDIVRP STi,ST*/ 00621 FPU_FDIVR(STV(sub),TOP); 00622 break; 00623 case 0x07: /* FDIVP STi,ST*/ 00624 FPU_FDIV(STV(sub),TOP); 00625 break; 00626 default: 00627 break; 00628 } 00629 FPU_FPOP(); 00630 } 00631 00632 00633 void FPU_ESC7_EA(Bitu rm,PhysPt addr) { 00634 Bitu group=(rm >> 3) & 7; 00635 Bitu sub=(rm & 7); 00636 switch(group){ 00637 case 0x00: /* FILD Bit16s */ 00638 { 00639 unsigned char old_TOP = TOP; 00640 00641 try { 00642 FPU_PREP_PUSH(); 00643 FPU_FLD_I16(addr,TOP); 00644 } 00645 catch (const GuestPageFaultException& pf) { 00646 (void)pf; 00647 TOP = old_TOP; 00648 throw; 00649 } 00650 } 00651 break; 00652 case 0x01: 00653 LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00654 break; 00655 case 0x02: /* FIST Bit16s */ 00656 FPU_FST_I16(addr); 00657 break; 00658 case 0x03: /* FISTP Bit16s */ 00659 FPU_FST_I16(addr); 00660 FPU_FPOP(); 00661 break; 00662 case 0x04: /* FBLD packed BCD */ 00663 { 00664 unsigned char old_TOP = TOP; 00665 00666 try { 00667 FPU_PREP_PUSH(); 00668 FPU_FBLD(addr,TOP); 00669 } 00670 catch (const GuestPageFaultException& pf) { 00671 (void)pf; 00672 TOP = old_TOP; 00673 throw; 00674 } 00675 } 00676 break; 00677 case 0x05: /* FILD Bit64s */ 00678 { 00679 unsigned char old_TOP = TOP; 00680 00681 try { 00682 FPU_PREP_PUSH(); 00683 FPU_FLD_I64(addr,TOP); 00684 } 00685 catch (const GuestPageFaultException& pf) { 00686 (void)pf; 00687 TOP = old_TOP; 00688 throw; 00689 } 00690 } 00691 break; 00692 case 0x06: /* FBSTP packed BCD */ 00693 FPU_FBST(addr); 00694 FPU_FPOP(); 00695 break; 00696 case 0x07: /* FISTP Bit64s */ 00697 FPU_FST_I64(addr); 00698 FPU_FPOP(); 00699 break; 00700 default: 00701 LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",(int)group,(int)sub); 00702 break; 00703 } 00704 } 00705 00706 void FPU_ESC7_Normal(Bitu rm) { 00707 Bitu group=(rm >> 3) & 7; 00708 Bitu sub=(rm & 7); 00709 switch (group){ 00710 case 0x00: /* FFREEP STi*/ 00711 fpu.tags[STV(sub)]=TAG_Empty; 00712 FPU_FPOP(); 00713 break; 00714 case 0x01: /* FXCH STi*/ 00715 FPU_FXCH(TOP,STV(sub)); 00716 break; 00717 case 0x02: /* FSTP STi*/ 00718 case 0x03: /* FSTP STi*/ 00719 FPU_FST(TOP,STV(sub)); 00720 FPU_FPOP(); 00721 break; 00722 case 0x04: 00723 switch(sub){ 00724 case 0x00: /* FNSTSW AX*/ 00725 FPU_SET_TOP(TOP); 00726 reg_ax = fpu.sw; 00727 break; 00728 default: 00729 LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",(int)group,(int)sub); 00730 break; 00731 } 00732 break; 00733 case 0x05: /* FUCOMIP STi */ 00734 FPU_FUCOMI(TOP,STV(sub)); 00735 FPU_FPOP(); 00736 break; 00737 case 0x06: /* FCOMIP STi */ 00738 FPU_FCOMI(TOP,STV(sub)); 00739 FPU_FPOP(); 00740 break; 00741 default: 00742 LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",(int)group,(int)sub); 00743 break; 00744 } 00745 } 00746 00747 // test routine at startup to make sure our typedef struct bitfields 00748 // line up with the host's definition of a 32-bit single-precision 00749 // floating point value. 00750 void FPU_Selftest_32() { 00751 struct ftest { 00752 const char* name; 00753 float val; 00754 int exponent:15; 00755 unsigned int sign:1; 00756 uint32_t mantissa; 00757 }; 00758 static const struct ftest test[] = { 00759 // name // val // exponent (no bias) // sign // 23-bit mantissa without 23rd implied bit (max 2^23-1 = 0x7FFFFF) 00760 {"0.0f", 0.0f, -FPU_Reg_32_exponent_bias, 0, 0x000000}, // IEEE standard way to encode zero 00761 {"1.0f", 1.0f, 0, 0, 0x000000}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00762 {"2.0f", 2.0f, 1, 0, 0x000000}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00763 {"3.0f", 3.0f, 1, 0, 0x400000}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00764 {"4.0f", 4.0f, 2, 0, 0x000000}, // 1.0 x 2^2 = 1.0 x 4 = 4.0 00765 {"-1.0f", -1.0f, 0, 1, 0x000000}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00766 {"-2.0f", -2.0f, 1, 1, 0x000000}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00767 {"-3.0f", -3.0f, 1, 1, 0x400000}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00768 {"-4.0f", -4.0f, 2, 1, 0x000000} // 1.0 x 2^2 = 1.0 x 4 = 4.0 00769 }; 00770 static const size_t tests = sizeof(test) / sizeof(test[0]); 00771 FPU_Reg_32 ft; 00772 00773 if (sizeof(ft) < 4) { 00774 LOG(LOG_FPU,LOG_WARN)("FPU32 sizeof(reg32) < 4 bytes"); 00775 return; 00776 } 00777 if (sizeof(float) != 4) { 00778 LOG(LOG_FPU,LOG_WARN)("FPU32 sizeof(float) != 4 bytes your host is weird"); 00779 return; 00780 } 00781 00782 // make sure bitfields line up 00783 ft.raw = 1UL << 31UL; 00784 if (ft.f.sign != 1 || ft.f.exponent != 0 || ft.f.mantissa != 0) { 00785 LOG(LOG_FPU,LOG_WARN)("FPU32 bitfield test #1 failed"); 00786 return; 00787 } 00788 ft.raw = 1UL << 23UL; 00789 if (ft.f.sign != 0 || ft.f.exponent != 1 || ft.f.mantissa != 0) { 00790 LOG(LOG_FPU,LOG_WARN)("FPU32 bitfield test #2 failed"); 00791 return; 00792 } 00793 ft.raw = 1UL << 0UL; 00794 if (ft.f.sign != 0 || ft.f.exponent != 0 || ft.f.mantissa != 1) { 00795 LOG(LOG_FPU,LOG_WARN)("FPU32 bitfield test #3 failed"); 00796 return; 00797 } 00798 00799 // carry out tests 00800 for (size_t t=0;t < tests;t++) { 00801 ft.v = test[t].val; FPU_Reg_m_barrier(); 00802 if (((int)ft.f.exponent - FPU_Reg_32_exponent_bias) != test[t].exponent || 00803 ft.f.sign != test[t].sign || ft.f.mantissa != test[t].mantissa) { 00804 LOG(LOG_FPU,LOG_WARN)("FPU32 selftest fail stage %s",test[t].name); 00805 LOG(LOG_FPU,LOG_WARN)(" expected t.v = %.10f t.s=%u t.exp=%d t.mantissa=%u", 00806 test[t].val, 00807 test[t].sign, 00808 (int)test[t].exponent, 00809 (unsigned int)test[t].mantissa); 00810 goto dump; 00811 } 00812 } 00813 00814 LOG(LOG_FPU,LOG_DEBUG)("FPU32 selftest passed"); 00815 return; 00816 dump: 00817 LOG(LOG_FPU,LOG_WARN)("Result: t.v = %.10f t.s=%u t.exp=%d t.mantissa=%u", 00818 ft.v, 00819 ft.f.sign, 00820 (int)ft.f.exponent - FPU_Reg_32_exponent_bias, 00821 (unsigned int)ft.f.mantissa); 00822 } 00823 00824 // test routine at startup to make sure our typedef struct bitfields 00825 // line up with the host's definition of a 64-bit double-precision 00826 // floating point value. 00827 void FPU_Selftest_64() { 00828 struct ftest { 00829 const char* name; 00830 double val; 00831 int exponent:15; 00832 unsigned int sign:1; 00833 uint64_t mantissa; 00834 }; 00835 static const struct ftest test[] = { 00836 // name // val // exponent (no bias) // sign // 52-bit mantissa without 52rd implied bit (max 2^52-1 = 0x1FFFFFFFFFFFFF) 00837 {"0.0d", 0.0, -FPU_Reg_64_exponent_bias, 0, 0x0000000000000ULL}, // IEEE standard way to encode zero 00838 {"1.0d", 1.0, 0, 0, 0x0000000000000ULL}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00839 {"2.0d", 2.0, 1, 0, 0x0000000000000ULL}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00840 {"3.0d", 3.0, 1, 0, 0x8000000000000ULL}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00841 {"4.0d", 4.0, 2, 0, 0x0000000000000ULL}, // 1.0 x 2^2 = 1.0 x 4 = 4.0 00842 {"-1.0d", -1.0, 0, 1, 0x0000000000000ULL}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00843 {"-2.0d", -2.0, 1, 1, 0x0000000000000ULL}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00844 {"-3.0d", -3.0, 1, 1, 0x8000000000000ULL}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00845 {"-4.0d", -4.0, 2, 1, 0x0000000000000ULL} // 1.0 x 2^2 = 1.0 x 4 = 4.0 00846 }; 00847 static const size_t tests = sizeof(test) / sizeof(test[0]); 00848 FPU_Reg_64 ft; 00849 00850 if (sizeof(ft) < 8) { 00851 LOG(LOG_FPU,LOG_WARN)("FPU64 sizeof(reg64) < 8 bytes"); 00852 return; 00853 } 00854 if (sizeof(double) != 8) { 00855 LOG(LOG_FPU,LOG_WARN)("FPU64 sizeof(float) != 8 bytes your host is weird"); 00856 return; 00857 } 00858 00859 // make sure bitfields line up 00860 ft.raw = 1ULL << 63ULL; 00861 if (ft.f.sign != 1 || ft.f.exponent != 0 || ft.f.mantissa != 0) { 00862 LOG(LOG_FPU,LOG_WARN)("FPU64 bitfield test #1 failed"); 00863 return; 00864 } 00865 ft.raw = 1ULL << 52ULL; 00866 if (ft.f.sign != 0 || ft.f.exponent != 1 || ft.f.mantissa != 0) { 00867 LOG(LOG_FPU,LOG_WARN)("FPU64 bitfield test #2 failed"); 00868 return; 00869 } 00870 ft.raw = 1ULL << 0ULL; 00871 if (ft.f.sign != 0 || ft.f.exponent != 0 || ft.f.mantissa != 1) { 00872 LOG(LOG_FPU,LOG_WARN)("FPU64 bitfield test #3 failed"); 00873 return; 00874 } 00875 00876 for (size_t t=0;t < tests;t++) { 00877 ft.v = test[t].val; FPU_Reg_m_barrier(); 00878 if (((int)ft.f.exponent - FPU_Reg_64_exponent_bias) != test[t].exponent || 00879 ft.f.sign != test[t].sign || ft.f.mantissa != test[t].mantissa) { 00880 LOG(LOG_FPU,LOG_WARN)("FPU64 selftest fail stage %s",test[t].name); 00881 LOG(LOG_FPU,LOG_WARN)(" expected t.v = %.10f t.s=%u t.exp=%d t.mantissa=%llu (0x%llx)", 00882 test[t].val, 00883 test[t].sign, 00884 (int)test[t].exponent, 00885 (unsigned long long)test[t].mantissa, 00886 (unsigned long long)test[t].mantissa); 00887 goto dump; 00888 } 00889 } 00890 00891 LOG(LOG_FPU,LOG_DEBUG)("FPU64 selftest passed"); 00892 return; 00893 dump: 00894 LOG(LOG_FPU,LOG_WARN)("Result: t.v = %.10f t.s=%u t.exp=%d t.mantissa=%llu (0x%llx)", 00895 ft.v, 00896 (int)ft.f.sign, 00897 (int)ft.f.exponent - FPU_Reg_64_exponent_bias, 00898 (unsigned long long)ft.f.mantissa, 00899 (unsigned long long)ft.f.mantissa); 00900 } 00901 00902 // test routine at startup to make sure our typedef struct bitfields 00903 // line up with the host's definition of a 80-bit extended-precision 00904 // floating point value (if the host is i686, x86_64, or any other 00905 // host with the same definition of long double). 00906 void FPU_Selftest_80() { 00907 #if defined(HAS_LONG_DOUBLE) 00908 // we're assuming "long double" means the Intel 80x87 extended precision format, which is true when using 00909 // GCC on Linux i686 and x86_64 hosts. 00910 // 00911 // I understand that other platforms (PowerPC, Sparc, etc) might have other ideas on what makes "long double" 00912 // and I also understand Microsoft Visual C++ treats long double the same as double. We will disable this 00913 // test with #ifdefs when compiling for platforms where long double doesn't mean 80-bit extended precision. 00914 struct ftest { 00915 const char* name; 00916 long double val; 00917 int exponent:15; 00918 unsigned int sign:1; 00919 uint64_t mantissa; 00920 }; 00921 static const struct ftest test[] = { 00922 // name // val // exponent (no bias) // sign // 64-bit mantissa WITH whole integer bit #63 00923 {"0.0L", 0.0, -FPU_Reg_80_exponent_bias, 0, 0x0000000000000000ULL}, // IEEE standard way to encode zero 00924 {"1.0L", 1.0, 0, 0, 0x8000000000000000ULL}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00925 {"2.0L", 2.0, 1, 0, 0x8000000000000000ULL}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00926 {"3.0L", 3.0, 1, 0, 0xC000000000000000ULL}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00927 {"4.0L", 4.0, 2, 0, 0x8000000000000000ULL}, // 1.0 x 2^2 = 1.0 x 4 = 4.0 00928 {"-1.0L", -1.0, 0, 1, 0x8000000000000000ULL}, // 1.0 x 2^0 = 1.0 x 1 = 1.0 00929 {"-2.0L", -2.0, 1, 1, 0x8000000000000000ULL}, // 1.0 x 2^1 = 1.0 x 2 = 2.0 00930 {"-3.0L", -3.0, 1, 1, 0xC000000000000000ULL}, // 1.5 x 2^1 = 1.5 x 2 = 3.0 00931 {"-4.0L", -4.0, 2, 1, 0x8000000000000000ULL} // 1.0 x 2^2 = 1.0 x 4 = 4.0 00932 }; 00933 static const size_t tests = sizeof(test) / sizeof(test[0]); 00934 #endif 00935 FPU_Reg_80 ft; 00936 00937 if (sizeof(ft) < 10) { 00938 LOG(LOG_FPU,LOG_WARN)("FPU80 sizeof(reg80) < 10 bytes"); 00939 return; 00940 } 00941 #if defined(HAS_LONG_DOUBLE) 00942 if (sizeof(long double) == sizeof(double)) { 00943 LOG(LOG_FPU,LOG_WARN)("FPU80 sizeof(long double) == sizeof(double) so your compiler just makes it an alias. skipping tests. please recompile with proper config."); 00944 return; 00945 } 00946 else if (sizeof(long double) < 10 || sizeof(long double) > 16) { 00947 // NTS: We can't assume 10 bytes. GCC on i686 makes long double 12 or 16 bytes long for alignment 00948 // even though only 80 bits (10 bytes) are used. 00949 LOG(LOG_FPU,LOG_WARN)("FPU80 sizeof(float) < 10 bytes your host is weird"); 00950 return; 00951 } 00952 #endif 00953 00954 // make sure bitfields line up 00955 ft.raw.l = 0; 00956 ft.raw.h = 1U << 15U; 00957 if (ft.f.sign != 1 || ft.f.exponent != 0 || ft.f.mantissa != 0) { 00958 LOG(LOG_FPU,LOG_WARN)("FPU80 bitfield test #1 failed. h=%04x l=%016llx",(unsigned int)ft.raw.h,(unsigned long long)ft.raw.l); 00959 return; 00960 } 00961 ft.raw.l = 0; 00962 ft.raw.h = 1U << 0U; 00963 if (ft.f.sign != 0 || ft.f.exponent != 1 || ft.f.mantissa != 0) { 00964 LOG(LOG_FPU,LOG_WARN)("FPU80 bitfield test #2 failed. h=%04x l=%016llx",(unsigned int)ft.raw.h,(unsigned long long)ft.raw.l); 00965 return; 00966 } 00967 ft.raw.l = 1ULL << 0ULL; 00968 ft.raw.h = 0; 00969 if (ft.f.sign != 0 || ft.f.exponent != 0 || ft.f.mantissa != 1) { 00970 LOG(LOG_FPU,LOG_WARN)("FPU80 bitfield test #3 failed. h=%04x l=%016llx",(unsigned int)ft.raw.h,(unsigned long long)ft.raw.l); 00971 return; 00972 } 00973 00974 #if defined(HAS_LONG_DOUBLE) 00975 for (size_t t=0;t < tests;t++) { 00976 ft.v = test[t].val; FPU_Reg_m_barrier(); 00977 if (((int)ft.f.exponent - FPU_Reg_80_exponent_bias) != test[t].exponent || 00978 ft.f.sign != test[t].sign || ft.f.mantissa != test[t].mantissa) { 00979 LOG(LOG_FPU,LOG_WARN)("FPU80 selftest fail stage %s",test[t].name); 00980 LOG(LOG_FPU,LOG_WARN)(" expected t.v = %.10Lf t.s=%u t.exp=%d t.mantissa=%llu (0x%llx)", 00981 test[t].val, 00982 test[t].sign, 00983 (int)test[t].exponent, 00984 (unsigned long long)test[t].mantissa, 00985 (unsigned long long)test[t].mantissa); 00986 goto dump; 00987 } 00988 } 00989 00990 LOG(LOG_FPU,LOG_DEBUG)("FPU80 selftest passed"); 00991 return; 00992 dump: 00993 LOG(LOG_FPU,LOG_WARN)("Result: t.v = %.10Lf t.s=%u t.exp=%d t.mantissa=%llu (0x%llx)", 00994 ft.v, 00995 (int)ft.f.sign, 00996 (int)ft.f.exponent - FPU_Reg_64_exponent_bias, 00997 (unsigned long long)ft.f.mantissa, 00998 (unsigned long long)ft.f.mantissa); 00999 #else 01000 LOG(LOG_FPU,LOG_DEBUG)("FPU80 selftest skipped, compiler does not have long double as 80-bit IEEE"); 01001 #endif 01002 } 01003 01004 void FPU_Selftest() { 01005 FPU_Reg freg; 01006 01007 /* byte order test */ 01008 freg.ll = 0x0123456789ABCDEFULL; 01009 #ifndef WORDS_BIGENDIAN 01010 if (freg.l.lower != 0x89ABCDEFUL || freg.l.upper != 0x01234567UL) { 01011 LOG(LOG_FPU,LOG_WARN)("FPU_Reg field order is wrong. ll=0x%16llx l=0x%08lx h=0x%08lx", 01012 (unsigned long long)freg.ll, (unsigned long)freg.l.lower, (unsigned long)freg.l.upper); 01013 } 01014 #else 01015 if (freg.l.upper != 0x89ABCDEFUL || freg.l.lower != 0x01234567UL) { 01016 LOG(LOG_FPU,LOG_WARN)("FPU_Reg field order is wrong. ll=0x%16llx l=0x%08lx h=0x%08lx", 01017 (unsigned long long)freg.ll, (unsigned long)freg.l.lower, (unsigned long)freg.l.upper); 01018 } 01019 #endif 01020 01021 #if C_FPU_X86 01022 LOG(LOG_FPU,LOG_NORMAL)("FPU core: x86 FPU"); 01023 #elif defined(HAS_LONG_DOUBLE) 01024 LOG(LOG_FPU,LOG_NORMAL)("FPU core: long double FPU"); 01025 #else 01026 LOG(LOG_FPU,LOG_NORMAL)("FPU core: double FPU (caution: possible precision errors)"); 01027 #endif 01028 01029 FPU_Selftest_32(); 01030 FPU_Selftest_64(); 01031 FPU_Selftest_80(); 01032 } 01033 01034 void FPU_Init() { 01035 LOG(LOG_MISC,LOG_DEBUG)("Initializing FPU"); 01036 01037 FPU_Selftest(); 01038 FPU_FINIT(); 01039 } 01040 01041 #endif 01042 01043 //save state support 01044 namespace 01045 { 01046 class SerializeFpu : public SerializeGlobalPOD 01047 { 01048 public: 01049 SerializeFpu() : SerializeGlobalPOD("FPU") 01050 { 01051 registerPOD(fpu); 01052 } 01053 } dummy; 01054 }