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