src/emu/cpu/i386/x87ops.c
| r13843 | r13844 | |
| 1 | 1 | // Intel x87 FPU opcodes |
| 2 | 2 | |
| 3 | // TODO: |
| 4 | // - double check single precision opcodes; |
| 5 | // - opcode cycles (every single CPU has different counting on it); |
| 6 | // - clean-ups; |
| 7 | |
| 3 | 8 | #define ST(x) (cpustate->fpu_reg[(cpustate->fpu_top + (x)) & 7]) |
| 4 | 9 | #define FPU_INFINITY_DOUBLE U64(0x7ff0000000000000) |
| 5 | 10 | #define FPU_INFINITY_SINGLE (0x7f800000) |
| 6 | 11 | #define FPU_SIGN_BIT_DOUBLE U64(0x8000000000000000) |
| 7 | 12 | #define FPU_SIGN_BIT_SINGLE (0x80000000) |
| 13 | #define FPU_MANTISSA_DOUBLE U64(0x000fffffffffffff) |
| 8 | 14 | |
| 15 | |
| 9 | 16 | // FPU control word flags |
| 10 | 17 | #define FPU_MASK_INVALID_OP 0x0001 |
| 11 | 18 | #define FPU_MASK_DENORMAL_OP 0x0002 |
| r13843 | r13844 | |
| 79 | 86 | return t; |
| 80 | 87 | } |
| 81 | 88 | |
| 89 | INLINE 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; |
| 82 | 96 | |
| 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 | |
| 115 | INLINE 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 | |
| 83 | 135 | static void I386OP(fpu_group_d8)(i386_state *cpustate) // Opcode 0xd8 |
| 84 | 136 | { |
| 85 | 137 | UINT8 modrm = FETCH(cpustate); |
| r13843 | r13844 | |
| 402 | 454 | |
| 403 | 455 | case 0x21: // FABS |
| 404 | 456 | { |
| 405 | | ST(0).i = abs(ST(0).i); |
| 457 | ST(0).f = fabs(ST(0).f); |
| 406 | 458 | CYCLES(cpustate,3); |
| 407 | 459 | break; |
| 408 | 460 | } |
| r13843 | r13844 | |
| 677 | 729 | break; |
| 678 | 730 | |
| 679 | 731 | 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"); |
| 681 | 736 | CYCLES(cpustate,84); |
| 682 | 737 | break; |
| 683 | 738 | |
| 684 | 739 | 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"); |
| 686 | 744 | CYCLES(cpustate,84); |
| 687 | 745 | break; |
| 688 | 746 | |
| r13843 | r13844 | |
| 752 | 810 | break; |
| 753 | 811 | } |
| 754 | 812 | |
| 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 | |
| 755 | 831 | default: |
| 756 | 832 | fatalerror("I386: FPU Op DB %02X at %08X", modrm, cpustate->pc-2); |
| 757 | 833 | } |
| r13843 | r13844 | |
| 800 | 876 | if (modrm < 0xc0) |
| 801 | 877 | { |
| 802 | 878 | UINT32 ea = GetEA(cpustate,modrm); |
| 879 | X87_REG t; |
| 803 | 880 | |
| 881 | t.i = READ64(cpustate,ea); |
| 882 | |
| 804 | 883 | switch ((modrm >> 3) & 0x7) |
| 805 | 884 | { |
| 806 | 885 | case 0: /* FADD double */ |
| 807 | 886 | { |
| 808 | | X87_REG t; |
| 809 | | t.i = READ64(cpustate,ea); |
| 810 | 887 | ST(0).f += t.f; |
| 811 | 888 | CYCLES(cpustate,8); |
| 812 | 889 | break; |
| r13843 | r13844 | |
| 814 | 891 | |
| 815 | 892 | case 1: /* FMUL double */ |
| 816 | 893 | { |
| 817 | | X87_REG t; |
| 818 | | t.i = READ64(cpustate,ea); |
| 819 | 894 | ST(0).f *= t.f; |
| 820 | 895 | CYCLES(cpustate,14); |
| 821 | 896 | break; |
| r13843 | r13844 | |
| 823 | 898 | |
| 824 | 899 | case 2: /* FCOM double */ |
| 825 | 900 | { |
| 826 | | X87_REG t; |
| 827 | | t.i = READ64(cpustate,ea); |
| 828 | 901 | cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0); |
| 829 | 902 | if(ST(0).f == t.f) |
| 830 | 903 | cpustate->fpu_status_word |= FPU_C3; |
| r13843 | r13844 | |
| 837 | 910 | |
| 838 | 911 | case 3: /* FCOMP double */ |
| 839 | 912 | { |
| 840 | | X87_REG t; |
| 841 | | t.i = READ64(cpustate,ea); |
| 842 | 913 | cpustate->fpu_status_word &= ~(FPU_C3 | FPU_C2 | FPU_C0); |
| 843 | 914 | if(ST(0).f == t.f) |
| 844 | 915 | cpustate->fpu_status_word |= FPU_C3; |
| r13843 | r13844 | |
| 852 | 923 | |
| 853 | 924 | case 4: /* FSUB double */ |
| 854 | 925 | { |
| 855 | | X87_REG t; |
| 856 | | t.i = READ64(cpustate,ea); |
| 857 | 926 | ST(0).f -= t.f; |
| 858 | 927 | CYCLES(cpustate,8); |
| 859 | 928 | break; |
| r13843 | r13844 | |
| 861 | 930 | |
| 862 | 931 | case 5: /* FSUBR double */ |
| 863 | 932 | { |
| 864 | | X87_REG t; |
| 865 | | t.i = READ64(cpustate,ea); |
| 866 | 933 | ST(0).f = t.f - ST(0).f; |
| 867 | 934 | CYCLES(cpustate,8); |
| 868 | 935 | break; |
| r13843 | r13844 | |
| 870 | 937 | |
| 871 | 938 | case 6: /* FDIV double */ |
| 872 | 939 | { |
| 873 | | X87_REG t; |
| 874 | | t.i = READ64(cpustate,ea); |
| 875 | 940 | if(t.f) |
| 876 | 941 | ST(0).f /= t.f; |
| 877 | 942 | else |
| r13843 | r13844 | |
| 883 | 948 | |
| 884 | 949 | case 7: /* FDIV double */ |
| 885 | 950 | { |
| 886 | | X87_REG t; |
| 887 | | t.i = READ64(cpustate,ea); |
| 888 | 951 | if(ST(0).f) |
| 889 | 952 | ST(0).f = t.f / ST(0).f; |
| 890 | 953 | else |
| r13843 | r13844 | |
| 916 | 979 | break; |
| 917 | 980 | } |
| 918 | 981 | |
| 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 | |
| 919 | 996 | case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // FSUBR |
| 920 | 997 | { |
| 921 | 998 | ST(modrm & 7).f = ST(0).f - ST(modrm & 7).f; |
| r13843 | r13844 | |
| 930 | 1007 | break; |
| 931 | 1008 | } |
| 932 | 1009 | |
| 1010 | // FDIVR |
| 933 | 1011 | case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: |
| 934 | 1012 | { |
| 935 | | // FDIVR |
| 936 | 1013 | if ((ST(modrm & 7).i & U64(0x7fffffffffffffff)) == 0) |
| 937 | 1014 | { |
| 938 | 1015 | // set result as infinity if zero divide is masked |
| r13843 | r13844 | |
| 945 | 1022 | { |
| 946 | 1023 | ST(modrm & 7).f = ST(0).f / ST(modrm & 7).f; |
| 947 | 1024 | } |
| 948 | | CYCLES(cpustate,1); // TODO |
| 1025 | CYCLES(cpustate,73); |
| 949 | 1026 | break; |
| 950 | 1027 | } |
| 951 | 1028 | |
| 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 | |
| 952 | 1048 | default: |
| 953 | 1049 | fatalerror("I386: FPU Op DC %02X at %08X", modrm, cpustate->pc-2); |
| 954 | 1050 | } |
| r13843 | r13844 | |
| 995 | 1091 | break; |
| 996 | 1092 | } |
| 997 | 1093 | |
| 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 | |
| 998 | 1177 | case 7: // FSTSW |
| 999 | 1178 | { |
| 1000 | 1179 | WRITE16(cpustate,ea, (cpustate->fpu_status_word & ~FPU_STACK_TOP_MASK) | (cpustate->fpu_top << 10)); |
| r13843 | r13844 | |
| 1010 | 1189 | { |
| 1011 | 1190 | switch (modrm & 0x3f) |
| 1012 | 1191 | { |
| 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 |
| 1014 | 1193 | { |
| 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 | { |
| 1015 | 1201 | UINT16 tmp; |
| 1016 | 1202 | ST(modrm & 7) = ST(0); |
| 1017 | 1203 | tmp = (cpustate->fpu_tag_word>>((cpustate->fpu_top&7)<<1))&3; |
| 1018 | 1204 | cpustate->fpu_tag_word &= ~(3<<((modrm & 7)<< 1)); |
| 1019 | 1205 | 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)); |
| 1020 | 1217 | FPU_POP(cpustate); |
| 1021 | 1218 | CYCLES(cpustate,3); |
| 1022 | 1219 | break; |
| 1023 | 1220 | } |
| 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 | |
| 1024 | 1274 | default: |
| 1025 | 1275 | fatalerror("I386: FPU Op DD %02X at %08X", modrm, cpustate->pc-2); |
| 1026 | 1276 | } |
| r13843 | r13844 | |
| 1033 | 1283 | |
| 1034 | 1284 | if (modrm < 0xc0) |
| 1035 | 1285 | { |
| 1036 | | // UINT32 ea = GetEA(cpustate,modrm); |
| 1286 | UINT32 ea = GetEA(cpustate,modrm); |
| 1287 | INT32 t; |
| 1037 | 1288 | |
| 1289 | t = (INT32)READ16(cpustate,ea); |
| 1290 | |
| 1038 | 1291 | switch ((modrm >> 3) & 0x7) |
| 1039 | 1292 | { |
| 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 | |
| 1040 | 1389 | default: |
| 1041 | 1390 | fatalerror("I386: FPU Op DE %02X at %08X", modrm, cpustate->pc-2); |
| 1042 | 1391 | } |
| r13843 | r13844 | |
| 1083 | 1432 | } |
| 1084 | 1433 | FPU_POP(cpustate); |
| 1085 | 1434 | FPU_POP(cpustate); |
| 1086 | | CYCLES(cpustate,1); // TODO |
| 1435 | CYCLES(cpustate,5); |
| 1087 | 1436 | break; |
| 1088 | 1437 | } |
| 1089 | 1438 | |
| r13843 | r13844 | |
| 1190 | 1539 | break; |
| 1191 | 1540 | } |
| 1192 | 1541 | |
| 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 | |
| 1193 | 1569 | case 7: // FISTP long |
| 1194 | 1570 | { |
| 1195 | 1571 | X87_REG t; |