Previous 15994 Revisions Next

r13844 Tuesday 3rd January, 2012 at 21:23:42 UTC by Angelo Salese
Port from MAME
[src/emu/cpu/i386]x87ops.c

src/emu/cpu/i386/x87ops.c
r13843r13844
11// Intel x87 FPU opcodes
22
3// TODO:
4// - double check single precision opcodes;
5// - opcode cycles (every single CPU has different counting on it);
6// - clean-ups;
7
38#define ST(x)   (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7])
49#define FPU_INFINITY_DOUBLE      U64(0x7ff0000000000000)
510#define FPU_INFINITY_SINGLE      (0x7f800000)
611#define FPU_SIGN_BIT_DOUBLE      U64(0x8000000000000000)
712#define FPU_SIGN_BIT_SINGLE      (0x80000000)
13#define FPU_MANTISSA_DOUBLE      U64(0x000fffffffffffff)
814
15
916// FPU control word flags
1017#define FPU_MASK_INVALID_OP         0x0001
1118#define FPU_MASK_DENORMAL_OP      0x0002
r13843r13844
7986   return t;
8087}
8188
89INLINE X87_REG READ80(i386_state *cpustate,UINT32 ea)
90{
91   X87_REG t;
92   UINT16 begin;
93   INT64 exp;
94   INT64 mantissa;
95   UINT8 sign;
8296
97   t.i = READ64(cpustate,ea);
98   begin = READ16(cpustate,ea+8);
99
100   exp = (begin&0x7fff) - 16383;
101   exp = (exp > 0) ? (exp&0x3ff) : (-exp&0x3ff);
102   exp += 1023;
103
104   mantissa = (t.i >> 11) & (FPU_MANTISSA_DOUBLE);
105   sign = (begin&0x8000) >> 15;
106
107   if(t.i & 0x400)
108      mantissa++;
109
110   t.i = ((UINT64)sign << 63)|((UINT64)exp << 52)|((UINT64)mantissa);
111
112   return t;
113}
114
115INLINE void WRITE80(i386_state *cpustate,UINT32 ea, X87_REG t)
116{
117   UINT8 sign = (t.i & FPU_SIGN_BIT_DOUBLE) ? 1 : 0;
118   INT64 exp = (t.i & FPU_INFINITY_DOUBLE) >> 52;
119   INT64 mantissa = (t.i & FPU_MANTISSA_DOUBLE) << 11;
120   INT16 begin;
121
122   if(t.f != 0)
123   {
124      logerror("Check WRITE80 with t.f != 0\n");
125      //mantissa |= FPU_SIGN_BIT_DOUBLE;
126      //exp += (16383 - 1023);
127   }
128
129   begin = (sign<<15)|(INT16)(exp);
130   t.i = mantissa;
131   WRITE64(cpustate,ea,t.i);
132   WRITE16(cpustate,ea+8,begin);
133}
134
83135static void I386OP(fpu_group_d8)(i386_state *cpustate)      // Opcode 0xd8
84136{
85137   UINT8 modrm = FETCH(cpustate);
r13843r13844
402454
403455         case 0x21:      // FABS
404456         {
405            ST(0).i = abs(ST(0).i);
457            ST(0).f = fabs(ST(0).f);
406458            CYCLES(cpustate,3);
407459            break;
408460         }
r13843r13844
677729            break;
678730
679731         case 6:   // FIDIV
680            ST(0).i/=t.i;
732            if(t.i)
733               ST(0).i/=t.i;
734            else
735               fatalerror("Divide-by-zero on FIDIV 0xda 0x06 opcode");
681736            CYCLES(cpustate,84);
682737            break;
683738
684739         case 7:   // FIDIVR
685            ST(0).i = t.i / ST(0).i;
740            if(ST(0).i)
741               ST(0).i = t.i / ST(0).i;
742            else
743               fatalerror("Divide-by-zero on FIDIV 0xda 0x07 opcode");
686744            CYCLES(cpustate,84);
687745            break;
688746
r13843r13844
752810            break;
753811         }
754812
813         case 5:      // FLD extended
814         {
815            X87_REG t;
816
817            t = READ80(cpustate,ea);
818            FPU_PUSH(cpustate,t);
819            CYCLES(cpustate,6);
820            break;
821         }
822
823         case 7:      // FSTP extended
824         {
825            WRITE80(cpustate,ea,ST(0));
826            FPU_POP(cpustate);
827            CYCLES(cpustate,6);
828            break;
829         }
830
755831         default:
756832            fatalerror("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2);
757833      }
r13843r13844
800876   if (modrm < 0xc0)
801877   {
802878      UINT32 ea = GetEA(cpustate,modrm);
879      X87_REG t;
803880
881      t.i = READ64(cpustate,ea);
882
804883      switch ((modrm >> 3) & 0x7)
805884      {
806885         case 0: /* FADD double */
807886         {
808            X87_REG t;
809            t.i = READ64(cpustate,ea);
810887            ST(0).f += t.f;
811888            CYCLES(cpustate,8);
812889            break;
r13843r13844
814891
815892         case 1: /* FMUL double */
816893         {
817            X87_REG t;
818            t.i = READ64(cpustate,ea);
819894            ST(0).f *= t.f;
820895            CYCLES(cpustate,14);
821896            break;
r13843r13844
823898
824899         case 2: /* FCOM double */
825900         {
826            X87_REG t;
827            t.i = READ64(cpustate,ea);
828901            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
829902            if(ST(0).f == t.f)
830903               cpustate->fpu_status_word |= FPU_C3;
r13843r13844
837910
838911         case 3: /* FCOMP double */
839912         {
840            X87_REG t;
841            t.i = READ64(cpustate,ea);
842913            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
843914            if(ST(0).f == t.f)
844915               cpustate->fpu_status_word |= FPU_C3;
r13843r13844
852923
853924         case 4: /* FSUB double */
854925         {
855            X87_REG t;
856            t.i = READ64(cpustate,ea);
857926            ST(0).f -= t.f;
858927            CYCLES(cpustate,8);
859928            break;
r13843r13844
861930
862931         case 5: /* FSUBR double */
863932         {
864            X87_REG t;
865            t.i = READ64(cpustate,ea);
866933            ST(0).f = t.f - ST(0).f;
867934            CYCLES(cpustate,8);
868935            break;
r13843r13844
870937
871938         case 6: /* FDIV double */
872939         {
873            X87_REG t;
874            t.i = READ64(cpustate,ea);
875940            if(t.f)
876941               ST(0).f /= t.f;
877942            else
r13843r13844
883948
884949         case 7: /* FDIV double */
885950         {
886            X87_REG t;
887            t.i = READ64(cpustate,ea);
888951            if(ST(0).f)
889952               ST(0).f = t.f / ST(0).f;
890953            else
r13843r13844
916979            break;
917980         }
918981
982         case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // FSUBR
983         {
984            ST(modrm & 7).f = ST(0).f - ST(modrm & 7).f;
985            CYCLES(cpustate,8);
986            break;
987         }
988
989         case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // FSUB
990         {
991            ST(modrm & 7).f -= ST(0).f;
992            CYCLES(cpustate,8);
993            break;
994         }
995
919996         case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // FSUBR
920997         {
921998            ST(modrm & 7).f = ST(0).f - ST(modrm & 7).f;
r13843r13844
9301007            break;
9311008         }
9321009
1010         // FDIVR
9331011         case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
9341012         {
935            // FDIVR
9361013            if ((ST(modrm & 7).i & U64(0x7fffffffffffffff)) == 0)
9371014            {
9381015               // set result as infinity if zero divide is masked
r13843r13844
9451022            {
9461023               ST(modrm & 7).f = ST(0).f / ST(modrm & 7).f;
9471024            }
948            CYCLES(cpustate,1);      // TODO
1025            CYCLES(cpustate,73);
9491026            break;
9501027         }
9511028
1029          // FDIV
1030         case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
1031         {
1032            if ((ST(0).i & U64(0x7fffffffffffffff)) == 0)
1033            {
1034               // set result as infinity if zero divide is masked
1035               if (cpustate->fpu_control_word & FPU_MASK_ZERO_DIVIDE)
1036               {
1037                  ST(modrm & 7).i |= FPU_INFINITY_DOUBLE;
1038               }
1039            }
1040            else
1041            {
1042               ST(modrm & 7).f /= ST(0).f;
1043            }
1044            CYCLES(cpustate,73);
1045            break;
1046         }
1047
9521048         default:
9531049            fatalerror("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2);
9541050      }
r13843r13844
9951091            break;
9961092         }
9971093
1094         case 4:   // FRSTOR
1095         {
1096            int i;
1097            if( cpustate->operand_size )  // 32-bit real/protected mode
1098            {
1099               cpustate->fpu_control_word = READ16(cpustate,ea);
1100               cpustate->fpu_status_word = READ16(cpustate,ea+4);
1101               cpustate->fpu_tag_word = READ16(cpustate,ea+8);
1102               ea+=28;
1103            }
1104            else // 16-bit real/protected mode
1105            {
1106               cpustate->fpu_control_word = READ16(cpustate,ea);
1107               cpustate->fpu_status_word = READ16(cpustate,ea+2);
1108               cpustate->fpu_tag_word = READ16(cpustate,ea+4);
1109               ea+=14;
1110            }
1111
1112            cpustate->fpu_top = (cpustate->fpu_status_word>>11) & 7;
1113
1114            for(i=0;i<8;i++)
1115               ST(i) = READ80(cpustate,ea+i*10);
1116
1117            CYCLES(cpustate,(cpustate->cr[0] & 1) ? 34 : 44);
1118            break;
1119         }
1120
1121         case 6: // FSAVE
1122         {
1123            int i;
1124            logerror("x87 FSAVE triggered with mode = %d %02x %02x\n",(cpustate->cr[0] & 1)|(cpustate->operand_size & 1)<<1,cpustate->cr[0],cpustate->operand_size);
1125            switch((cpustate->cr[0] & 1)|(cpustate->operand_size & 1)<<1)
1126            {
1127               case 0:   // 16-bit real mode
1128                  WRITE16(cpustate,ea, cpustate->fpu_control_word);
1129                  WRITE16(cpustate,ea+2, cpustate->fpu_status_word);
1130                  WRITE16(cpustate,ea+4, cpustate->fpu_tag_word);
1131                  WRITE16(cpustate,ea+6, cpustate->fpu_inst_ptr & 0xffff);
1132                  //WRITE16(cpustate,ea+8, (cpustate->fpu_opcode & 0x07ff) | ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1133                  WRITE16(cpustate,ea+10, cpustate->fpu_data_ptr & 0xffff);
1134                  //WRITE16(cpustate,ea+12, ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1135                  ea+=14;
1136                  break;
1137               case 1: // 16-bit protected mode
1138                  WRITE16(cpustate,ea, cpustate->fpu_control_word);
1139                  WRITE16(cpustate,ea+2, cpustate->fpu_status_word);
1140                  WRITE16(cpustate,ea+4, cpustate->fpu_tag_word);
1141                  WRITE16(cpustate,ea+6, cpustate->fpu_inst_ptr & 0xffff);
1142                  WRITE16(cpustate,ea+8, (cpustate->fpu_opcode & 0x07ff) | ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1143                  WRITE16(cpustate,ea+10, cpustate->fpu_data_ptr & 0xffff);
1144                  WRITE16(cpustate,ea+12, ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1145                  ea+=14;
1146                  break;
1147               case 2: // 32-bit real mode
1148                  WRITE16(cpustate,ea, cpustate->fpu_control_word);
1149                  WRITE16(cpustate,ea+4, cpustate->fpu_status_word);
1150                  WRITE16(cpustate,ea+8, cpustate->fpu_tag_word);
1151                  WRITE16(cpustate,ea+12, cpustate->fpu_inst_ptr & 0xffff);
1152                  //WRITE16(cpustate,ea+8, (cpustate->fpu_opcode & 0x07ff) | ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1153                  WRITE16(cpustate,ea+20, cpustate->fpu_data_ptr & 0xffff);
1154                  //WRITE16(cpustate,ea+12, ((cpustate->fpu_inst_ptr & 0x0f0000) >> 4));
1155                  WRITE32(cpustate,ea+24, (cpustate->fpu_data_ptr>>16)<<12);
1156                  ea+=28;
1157                  break;
1158               case 3: // 32-bit protected mode
1159                  WRITE16(cpustate,ea, cpustate->fpu_control_word);
1160                  WRITE16(cpustate,ea+4, cpustate->fpu_status_word);
1161                  WRITE16(cpustate,ea+8, cpustate->fpu_tag_word);
1162                  WRITE32(cpustate,ea+12, cpustate->fpu_inst_ptr);
1163                  WRITE32(cpustate,ea+16, cpustate->fpu_opcode);
1164                  WRITE32(cpustate,ea+20, cpustate->fpu_data_ptr);
1165                  WRITE32(cpustate,ea+24, cpustate->fpu_inst_ptr);
1166                  ea+=28;
1167                  break;
1168            }
1169
1170            for(i=0;i<8;i++)
1171               ST(i) = READ80(cpustate,ea+i*10);
1172
1173            CYCLES(cpustate,(cpustate->cr[0] & 1) ? 56 : 67);
1174            break;
1175         }
1176
9981177         case 7:         // FSTSW
9991178         {
10001179            WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10));
r13843r13844
10101189   {
10111190      switch (modrm & 0x3f)
10121191      {
1013         case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
1192         case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // FFREE
10141193         {
1194            cpustate->fpu_tag_word |= (3<<((modrm & 7)<< 1));
1195            CYCLES(cpustate,3);
1196            break;
1197         }
1198
1199         case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // FST
1200         {
10151201            UINT16 tmp;
10161202            ST(modrm & 7) = ST(0);
10171203            tmp = (cpustate->fpu_tag_word>>((cpustate->fpu_top&7)<<1))&3;
10181204            cpustate->fpu_tag_word &= ~(3<<((modrm & 7)<< 1));
10191205            cpustate->fpu_tag_word |= (tmp<<((modrm & 7)<< 1));
1206            CYCLES(cpustate,3);
1207            break;
1208         }
1209
1210         case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: // FSTP
1211         {
1212            UINT16 tmp;
1213            ST(modrm & 7) = ST(0);
1214            tmp = (cpustate->fpu_tag_word>>((cpustate->fpu_top&7)<<1))&3;
1215            cpustate->fpu_tag_word &= ~(3<<((modrm & 7)<< 1));
1216            cpustate->fpu_tag_word |= (tmp<<((modrm & 7)<< 1));
10201217            FPU_POP(cpustate);
10211218            CYCLES(cpustate,3);
10221219            break;
10231220         }
1221
1222         case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // FUCOM
1223         {
1224            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
1225            if (ST(0).f > ST(modrm & 7).f)
1226            {
1227               // C3 = 0, C2 = 0, C0 = 0
1228            }
1229            else if (ST(0).f < ST(modrm & 7).f)
1230            {
1231               cpustate->fpu_status_word |= FPU_C0;
1232            }
1233            else if (ST(0).f == ST(modrm & 7).f)
1234            {
1235               cpustate->fpu_status_word |= FPU_C3;
1236            }
1237            else
1238            {
1239               // unordered
1240               cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
1241            }
1242
1243            //FPU_POP(cpustate);
1244            CYCLES(cpustate,4);
1245            break;
1246         }
1247
1248         case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f: // FUCOMP
1249         {
1250            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
1251            if (ST(0).f > ST(modrm & 7).f)
1252            {
1253               // C3 = 0, C2 = 0, C0 = 0
1254            }
1255            else if (ST(0).f < ST(modrm & 7).f)
1256            {
1257               cpustate->fpu_status_word |= FPU_C0;
1258            }
1259            else if (ST(0).f == ST(modrm & 7).f)
1260            {
1261               cpustate->fpu_status_word |= FPU_C3;
1262            }
1263            else
1264            {
1265               // unordered
1266               cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
1267            }
1268
1269            FPU_POP(cpustate);
1270            CYCLES(cpustate,4);
1271            break;
1272         }
1273
10241274         default:
10251275            fatalerror("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2);
10261276      }
r13843r13844
10331283
10341284   if (modrm < 0xc0)
10351285   {
1036   //  UINT32 ea = GetEA(cpustate,modrm);
1286      UINT32 ea = GetEA(cpustate,modrm);
1287      INT32 t;
10371288
1289      t = (INT32)READ16(cpustate,ea);
1290
10381291      switch ((modrm >> 3) & 0x7)
10391292      {
1293         case 0:   // FIADD single precision
1294         {
1295            ST(0).f+=(double)t;
1296            CYCLES(cpustate,20);
1297            break;
1298         }
1299
1300         case 1:   // FIMUL single precision
1301         {
1302            ST(0).f*=(double)t;
1303            CYCLES(cpustate,22);
1304            break;
1305         }
1306
1307         case 2: // FICOM
1308         {
1309            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
1310            if (ST(0).f > (double)t)
1311            {
1312               // C3 = 0, C2 = 0, C0 = 0
1313            }
1314            else if (ST(0).f < (double)t)
1315            {
1316               cpustate->fpu_status_word |= FPU_C0;
1317            }
1318            else if (ST(0).f == (double)t)
1319            {
1320               cpustate->fpu_status_word |= FPU_C3;
1321            }
1322            else
1323            {
1324               // unordered
1325               cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
1326            }
1327            CYCLES(cpustate,15);
1328         }
1329
1330         case 3: // FICOMP
1331         {
1332            cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0);
1333            if (ST(0).f > (double)t)
1334            {
1335               // C3 = 0, C2 = 0, C0 = 0
1336            }
1337            else if (ST(0).f < (double)t)
1338            {
1339               cpustate->fpu_status_word |= FPU_C0;
1340            }
1341            else if (ST(0).f == (double)t)
1342            {
1343               cpustate->fpu_status_word |= FPU_C3;
1344            }
1345            else
1346            {
1347               // unordered
1348               cpustate->fpu_status_word |= (FPU_C3 | FPU_C2 | FPU_C0);
1349            }
1350            FPU_POP(cpustate);
1351            CYCLES(cpustate,15);
1352         }
1353
1354         case 4:   // FISUB single precision
1355         {
1356            ST(0).f-=(double)t;
1357            CYCLES(cpustate,20);
1358            break;
1359         }
1360
1361         case 5:   // FISUBR single precision
1362         {
1363            ST(0).f = (double)t - ST(0).f;
1364            CYCLES(cpustate,20);
1365            break;
1366         }
1367
1368         case 6:   // FIDIV single precision
1369         {
1370            if((double)t == 0)
1371               fatalerror("Divide by zero on x87 opcode 0xde 0x06");
1372            else
1373               ST(0).f/=(double)t;
1374            CYCLES(cpustate,84);
1375            break;
1376         }
1377
1378         case 7:   // FIDIVR single precision
1379         {
1380            if(ST(0).f == 0)
1381               fatalerror("Divide by zero on x87 opcode 0xde 0x07");
1382            else
1383               ST(0).f = (double)t / ST(0).f;
1384            CYCLES(cpustate,84);
1385            break;
1386         }
1387
1388
10401389         default:
10411390            fatalerror("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2);
10421391      }
r13843r13844
10831432            }
10841433            FPU_POP(cpustate);
10851434            FPU_POP(cpustate);
1086            CYCLES(cpustate,1);      // TODO
1435            CYCLES(cpustate,5);
10871436            break;
10881437         }
10891438
r13843r13844
11901539            break;
11911540         }
11921541
1542         case 6:      // FBSTP
1543         {
1544            UINT8 res;
1545            double bcd_data;
1546            int i;
1547
1548            bcd_data = ST(0).f;
1549
1550            for(i=0;i<9;i++)
1551            {
1552               res = (UINT8)floor(fmod(bcd_data,10.0));
1553               bcd_data -= floor(fmod(bcd_data,10.0));
1554               bcd_data /= 10.0;
1555               res = (UINT8)floor(fmod(bcd_data,10.0))<<4;
1556               bcd_data -= floor(fmod(bcd_data,10.0));
1557               bcd_data /= 10.0;
1558               WRITE8(cpustate,ea+i,res);
1559            }
1560            res = (UINT8)floor(fmod(bcd_data,10.0));
1561            if(bcd_data < 0)
1562               res |= 0x80;
1563            WRITE8(cpustate,ea+9,res);
1564            FPU_POP(cpustate);
1565            CYCLES(cpustate,1); // TODO
1566            break;
1567         }
1568
11931569         case 7:      // FISTP long
11941570         {
11951571            X87_REG t;

Previous 15994 Revisions Next


© 1998-2018 The MESS Team