Commit 77f8dd5add8f02253dcea1454c9d2c76d7c788a7
1 parent
c5e9815d
float fixes - added bsr/bsf support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@23 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
285 additions
and
26 deletions
Makefile
@@ -83,6 +83,7 @@ cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ | @@ -83,6 +83,7 @@ cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\ | ||
83 | dis-asm.h gen-i386.h op-i386.h syscall.c\ | 83 | dis-asm.h gen-i386.h op-i386.h syscall.c\ |
84 | dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ | 84 | dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ |
85 | i386.ld ppc.ld\ | 85 | i386.ld ppc.ld\ |
86 | +tests/Makefile\ | ||
86 | tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ | 87 | tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ |
87 | tests/test-i386-muldiv.h\ | 88 | tests/test-i386-muldiv.h\ |
88 | tests/test2.c tests/hello.c tests/sha1.c tests/test1.c | 89 | tests/test2.c tests/hello.c tests/sha1.c tests/test1.c |
TODO
@@ -3,4 +3,4 @@ | @@ -3,4 +3,4 @@ | ||
3 | - threads | 3 | - threads |
4 | - fix printf for doubles (fp87.c bug ?) | 4 | - fix printf for doubles (fp87.c bug ?) |
5 | - make it self runnable (use same trick as ld.so : include its own relocator and libc) | 5 | - make it self runnable (use same trick as ld.so : include its own relocator and libc) |
6 | -- better FPU comparisons (ucom/com) | 6 | +- fix FPU exceptions (in particular: gen_op_fpush not before mem load) |
cpu-i386.h
@@ -114,7 +114,7 @@ enum { | @@ -114,7 +114,7 @@ enum { | ||
114 | }; | 114 | }; |
115 | 115 | ||
116 | #ifdef __i386__ | 116 | #ifdef __i386__ |
117 | -#define USE_X86LDOUBLE | 117 | +//#define USE_X86LDOUBLE |
118 | #endif | 118 | #endif |
119 | 119 | ||
120 | #ifdef USE_X86LDOUBLE | 120 | #ifdef USE_X86LDOUBLE |
@@ -201,7 +201,7 @@ static inline void stl(void *ptr, int v) | @@ -201,7 +201,7 @@ static inline void stl(void *ptr, int v) | ||
201 | *(uint32_t *)ptr = v; | 201 | *(uint32_t *)ptr = v; |
202 | } | 202 | } |
203 | 203 | ||
204 | -static inline void stq(void *ptr, int v) | 204 | +static inline void stq(void *ptr, uint64_t v) |
205 | { | 205 | { |
206 | *(uint64_t *)ptr = v; | 206 | *(uint64_t *)ptr = v; |
207 | } | 207 | } |
op-i386.c
@@ -1055,7 +1055,7 @@ typedef union { | @@ -1055,7 +1055,7 @@ typedef union { | ||
1055 | 1055 | ||
1056 | #else | 1056 | #else |
1057 | 1057 | ||
1058 | -typedef { | 1058 | +typedef union { |
1059 | double d; | 1059 | double d; |
1060 | #ifndef WORDS_BIGENDIAN | 1060 | #ifndef WORDS_BIGENDIAN |
1061 | struct { | 1061 | struct { |
@@ -1119,6 +1119,31 @@ void OPPROTO op_fldl_ST0_A0(void) | @@ -1119,6 +1119,31 @@ void OPPROTO op_fldl_ST0_A0(void) | ||
1119 | ST0 = ldfq((void *)A0); | 1119 | ST0 = ldfq((void *)A0); |
1120 | } | 1120 | } |
1121 | 1121 | ||
1122 | +#ifdef USE_X86LDOUBLE | ||
1123 | +void OPPROTO op_fldt_ST0_A0(void) | ||
1124 | +{ | ||
1125 | + ST0 = *(long double *)A0; | ||
1126 | +} | ||
1127 | +#else | ||
1128 | +void helper_fldt_ST0_A0(void) | ||
1129 | +{ | ||
1130 | + CPU86_LDoubleU temp; | ||
1131 | + int upper, e; | ||
1132 | + /* mantissa */ | ||
1133 | + upper = lduw((uint8_t *)A0 + 8); | ||
1134 | + /* XXX: handle overflow ? */ | ||
1135 | + e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ | ||
1136 | + e |= (upper >> 4) & 0x800; /* sign */ | ||
1137 | + temp.ll = ((ldq((void *)A0) >> 11) & ((1LL << 52) - 1)) | ((uint64_t)e << 52); | ||
1138 | + ST0 = temp.d; | ||
1139 | +} | ||
1140 | + | ||
1141 | +void OPPROTO op_fldt_ST0_A0(void) | ||
1142 | +{ | ||
1143 | + helper_fldt_ST0_A0(); | ||
1144 | +} | ||
1145 | +#endif | ||
1146 | + | ||
1122 | void OPPROTO op_fild_ST0_A0(void) | 1147 | void OPPROTO op_fild_ST0_A0(void) |
1123 | { | 1148 | { |
1124 | ST0 = (CPU86_LDouble)ldsw((void *)A0); | 1149 | ST0 = (CPU86_LDouble)ldsw((void *)A0); |
@@ -1143,9 +1168,34 @@ void OPPROTO op_fsts_ST0_A0(void) | @@ -1143,9 +1168,34 @@ void OPPROTO op_fsts_ST0_A0(void) | ||
1143 | 1168 | ||
1144 | void OPPROTO op_fstl_ST0_A0(void) | 1169 | void OPPROTO op_fstl_ST0_A0(void) |
1145 | { | 1170 | { |
1146 | - ST0 = ldfq((void *)A0); | 1171 | + stfq((void *)A0, (double)ST0); |
1147 | } | 1172 | } |
1148 | 1173 | ||
1174 | +#ifdef USE_X86LDOUBLE | ||
1175 | +void OPPROTO op_fstt_ST0_A0(void) | ||
1176 | +{ | ||
1177 | + *(long double *)A0 = ST0; | ||
1178 | +} | ||
1179 | +#else | ||
1180 | +void helper_fstt_ST0_A0(void) | ||
1181 | +{ | ||
1182 | + CPU86_LDoubleU temp; | ||
1183 | + int e; | ||
1184 | + temp.d = ST0; | ||
1185 | + /* mantissa */ | ||
1186 | + stq((void *)A0, (MANTD(temp) << 11) | (1LL << 63)); | ||
1187 | + /* exponent + sign */ | ||
1188 | + e = EXPD(temp) - EXPBIAS + 16383; | ||
1189 | + e |= SIGND(temp) >> 16; | ||
1190 | + stw((uint8_t *)A0 + 8, e); | ||
1191 | +} | ||
1192 | + | ||
1193 | +void OPPROTO op_fstt_ST0_A0(void) | ||
1194 | +{ | ||
1195 | + helper_fstt_ST0_A0(); | ||
1196 | +} | ||
1197 | +#endif | ||
1198 | + | ||
1149 | void OPPROTO op_fist_ST0_A0(void) | 1199 | void OPPROTO op_fist_ST0_A0(void) |
1150 | { | 1200 | { |
1151 | int val; | 1201 | int val; |
@@ -1167,6 +1217,103 @@ void OPPROTO op_fistll_ST0_A0(void) | @@ -1167,6 +1217,103 @@ void OPPROTO op_fistll_ST0_A0(void) | ||
1167 | stq((void *)A0, val); | 1217 | stq((void *)A0, val); |
1168 | } | 1218 | } |
1169 | 1219 | ||
1220 | +/* BCD ops */ | ||
1221 | + | ||
1222 | +#define MUL10(iv) ( iv + iv + (iv << 3) ) | ||
1223 | + | ||
1224 | +void helper_fbld_ST0_A0(void) | ||
1225 | +{ | ||
1226 | + uint8_t *seg; | ||
1227 | + CPU86_LDouble fpsrcop; | ||
1228 | + int m32i; | ||
1229 | + unsigned int v; | ||
1230 | + | ||
1231 | + /* in this code, seg/m32i will be used as temporary ptr/int */ | ||
1232 | + seg = (uint8_t *)A0 + 8; | ||
1233 | + v = ldub(seg--); | ||
1234 | + /* XXX: raise exception */ | ||
1235 | + if (v != 0) | ||
1236 | + return; | ||
1237 | + v = ldub(seg--); | ||
1238 | + /* XXX: raise exception */ | ||
1239 | + if ((v & 0xf0) != 0) | ||
1240 | + return; | ||
1241 | + m32i = v; /* <-- d14 */ | ||
1242 | + v = ldub(seg--); | ||
1243 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */ | ||
1244 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */ | ||
1245 | + v = ldub(seg--); | ||
1246 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */ | ||
1247 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */ | ||
1248 | + v = ldub(seg--); | ||
1249 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */ | ||
1250 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */ | ||
1251 | + fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0; | ||
1252 | + | ||
1253 | + v = ldub(seg--); | ||
1254 | + m32i = (v >> 4); /* <-- d7 */ | ||
1255 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */ | ||
1256 | + v = ldub(seg--); | ||
1257 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */ | ||
1258 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */ | ||
1259 | + v = ldub(seg--); | ||
1260 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */ | ||
1261 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */ | ||
1262 | + v = ldub(seg); | ||
1263 | + m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */ | ||
1264 | + m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */ | ||
1265 | + fpsrcop += ((CPU86_LDouble)m32i); | ||
1266 | + if ( ldub(seg+9) & 0x80 ) | ||
1267 | + fpsrcop = -fpsrcop; | ||
1268 | + ST0 = fpsrcop; | ||
1269 | +} | ||
1270 | + | ||
1271 | +void OPPROTO op_fbld_ST0_A0(void) | ||
1272 | +{ | ||
1273 | + helper_fbld_ST0_A0(); | ||
1274 | +} | ||
1275 | + | ||
1276 | +void helper_fbst_ST0_A0(void) | ||
1277 | +{ | ||
1278 | + CPU86_LDouble fptemp; | ||
1279 | + CPU86_LDouble fpsrcop; | ||
1280 | + int v; | ||
1281 | + uint8_t *mem_ref, *mem_end; | ||
1282 | + | ||
1283 | + fpsrcop = rint(ST0); | ||
1284 | + mem_ref = (uint8_t *)A0; | ||
1285 | + mem_end = mem_ref + 8; | ||
1286 | + if ( fpsrcop < 0.0 ) { | ||
1287 | + stw(mem_end, 0x8000); | ||
1288 | + fpsrcop = -fpsrcop; | ||
1289 | + } else { | ||
1290 | + stw(mem_end, 0x0000); | ||
1291 | + } | ||
1292 | + while (mem_ref < mem_end) { | ||
1293 | + if (fpsrcop == 0.0) | ||
1294 | + break; | ||
1295 | + fptemp = floor(fpsrcop/10.0); | ||
1296 | + v = ((int)(fpsrcop - fptemp*10.0)); | ||
1297 | + if (fptemp == 0.0) { | ||
1298 | + stb(mem_ref++, v); | ||
1299 | + break; | ||
1300 | + } | ||
1301 | + fpsrcop = fptemp; | ||
1302 | + fptemp = floor(fpsrcop/10.0); | ||
1303 | + v |= (((int)(fpsrcop - fptemp*10.0)) << 4); | ||
1304 | + stb(mem_ref++, v); | ||
1305 | + fpsrcop = fptemp; | ||
1306 | + } | ||
1307 | + while (mem_ref < mem_end) { | ||
1308 | + stb(mem_ref++, 0); | ||
1309 | + } | ||
1310 | +} | ||
1311 | + | ||
1312 | +void OPPROTO op_fbst_ST0_A0(void) | ||
1313 | +{ | ||
1314 | + helper_fbst_ST0_A0(); | ||
1315 | +} | ||
1316 | + | ||
1170 | /* FPU move */ | 1317 | /* FPU move */ |
1171 | 1318 | ||
1172 | static inline void fpush(void) | 1319 | static inline void fpush(void) |
@@ -1244,6 +1391,17 @@ void OPPROTO op_fcom_ST0_FT0(void) | @@ -1244,6 +1391,17 @@ void OPPROTO op_fcom_ST0_FT0(void) | ||
1244 | FORCE_RET(); | 1391 | FORCE_RET(); |
1245 | } | 1392 | } |
1246 | 1393 | ||
1394 | +/* XXX: handle nans */ | ||
1395 | +void OPPROTO op_fucom_ST0_FT0(void) | ||
1396 | +{ | ||
1397 | + env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */ | ||
1398 | + if (ST0 < FT0) | ||
1399 | + env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */ | ||
1400 | + else if (ST0 == FT0) | ||
1401 | + env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */ | ||
1402 | + FORCE_RET(); | ||
1403 | +} | ||
1404 | + | ||
1247 | void OPPROTO op_fadd_ST0_FT0(void) | 1405 | void OPPROTO op_fadd_ST0_FT0(void) |
1248 | { | 1406 | { |
1249 | ST0 += FT0; | 1407 | ST0 += FT0; |
@@ -1321,7 +1479,7 @@ void OPPROTO op_fabs_ST0(void) | @@ -1321,7 +1479,7 @@ void OPPROTO op_fabs_ST0(void) | ||
1321 | ST0 = fabs(ST0); | 1479 | ST0 = fabs(ST0); |
1322 | } | 1480 | } |
1323 | 1481 | ||
1324 | -void OPPROTO op_fxam_ST0(void) | 1482 | +void helper_fxam_ST0(void) |
1325 | { | 1483 | { |
1326 | CPU86_LDoubleU temp; | 1484 | CPU86_LDoubleU temp; |
1327 | int expdif; | 1485 | int expdif; |
@@ -1346,7 +1504,11 @@ void OPPROTO op_fxam_ST0(void) | @@ -1346,7 +1504,11 @@ void OPPROTO op_fxam_ST0(void) | ||
1346 | } else { | 1504 | } else { |
1347 | env->fpus |= 0x400; | 1505 | env->fpus |= 0x400; |
1348 | } | 1506 | } |
1349 | - FORCE_RET(); | 1507 | +} |
1508 | + | ||
1509 | +void OPPROTO op_fxam_ST0(void) | ||
1510 | +{ | ||
1511 | + helper_fxam_ST0(); | ||
1350 | } | 1512 | } |
1351 | 1513 | ||
1352 | void OPPROTO op_fld1_ST0(void) | 1514 | void OPPROTO op_fld1_ST0(void) |
@@ -1354,12 +1516,12 @@ void OPPROTO op_fld1_ST0(void) | @@ -1354,12 +1516,12 @@ void OPPROTO op_fld1_ST0(void) | ||
1354 | ST0 = *(CPU86_LDouble *)&f15rk[1]; | 1516 | ST0 = *(CPU86_LDouble *)&f15rk[1]; |
1355 | } | 1517 | } |
1356 | 1518 | ||
1357 | -void OPPROTO op_fld2t_ST0(void) | 1519 | +void OPPROTO op_fldl2t_ST0(void) |
1358 | { | 1520 | { |
1359 | ST0 = *(CPU86_LDouble *)&f15rk[6]; | 1521 | ST0 = *(CPU86_LDouble *)&f15rk[6]; |
1360 | } | 1522 | } |
1361 | 1523 | ||
1362 | -void OPPROTO op_fld2e_ST0(void) | 1524 | +void OPPROTO op_fldl2e_ST0(void) |
1363 | { | 1525 | { |
1364 | ST0 = *(CPU86_LDouble *)&f15rk[5]; | 1526 | ST0 = *(CPU86_LDouble *)&f15rk[5]; |
1365 | } | 1527 | } |
@@ -1681,6 +1843,13 @@ void OPPROTO op_fnstsw_A0(void) | @@ -1681,6 +1843,13 @@ void OPPROTO op_fnstsw_A0(void) | ||
1681 | stw((void *)A0, fpus); | 1843 | stw((void *)A0, fpus); |
1682 | } | 1844 | } |
1683 | 1845 | ||
1846 | +void OPPROTO op_fnstsw_EAX(void) | ||
1847 | +{ | ||
1848 | + int fpus; | ||
1849 | + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; | ||
1850 | + EAX = (EAX & 0xffff0000) | fpus; | ||
1851 | +} | ||
1852 | + | ||
1684 | void OPPROTO op_fnstcw_A0(void) | 1853 | void OPPROTO op_fnstcw_A0(void) |
1685 | { | 1854 | { |
1686 | stw((void *)A0, env->fpuc); | 1855 | stw((void *)A0, env->fpuc); |
@@ -1784,6 +1953,10 @@ int cpu_x86_exec(CPUX86State *env1) | @@ -1784,6 +1953,10 @@ int cpu_x86_exec(CPUX86State *env1) | ||
1784 | eflags & CC_P ? 'P' : '-', | 1953 | eflags & CC_P ? 'P' : '-', |
1785 | eflags & CC_C ? 'C' : '-' | 1954 | eflags & CC_C ? 'C' : '-' |
1786 | ); | 1955 | ); |
1956 | +#if 1 | ||
1957 | + fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n", | ||
1958 | + (double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); | ||
1959 | +#endif | ||
1787 | } | 1960 | } |
1788 | #endif | 1961 | #endif |
1789 | cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); | 1962 | cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); |
ops_template.h
@@ -633,6 +633,42 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) | @@ -633,6 +633,42 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) | ||
633 | T0 ^= (1 << count); | 633 | T0 ^= (1 << count); |
634 | } | 634 | } |
635 | 635 | ||
636 | +void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) | ||
637 | +{ | ||
638 | + int res, count; | ||
639 | + res = T0 & DATA_MASK; | ||
640 | + if (res != 0) { | ||
641 | + count = 0; | ||
642 | + while ((res & 1) == 0) { | ||
643 | + count++; | ||
644 | + res >>= 1; | ||
645 | + } | ||
646 | + T0 = count; | ||
647 | + CC_DST = 1; /* ZF = 1 */ | ||
648 | + } else { | ||
649 | + CC_DST = 0; /* ZF = 1 */ | ||
650 | + } | ||
651 | + FORCE_RET(); | ||
652 | +} | ||
653 | + | ||
654 | +void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) | ||
655 | +{ | ||
656 | + int res, count; | ||
657 | + res = T0 & DATA_MASK; | ||
658 | + if (res != 0) { | ||
659 | + count = DATA_BITS - 1; | ||
660 | + while ((res & SIGN_MASK) == 0) { | ||
661 | + count--; | ||
662 | + res <<= 1; | ||
663 | + } | ||
664 | + T0 = count; | ||
665 | + CC_DST = 1; /* ZF = 1 */ | ||
666 | + } else { | ||
667 | + CC_DST = 0; /* ZF = 1 */ | ||
668 | + } | ||
669 | + FORCE_RET(); | ||
670 | +} | ||
671 | + | ||
636 | #endif | 672 | #endif |
637 | 673 | ||
638 | /* string operations */ | 674 | /* string operations */ |
translate-i386.c
@@ -431,6 +431,17 @@ static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { | @@ -431,6 +431,17 @@ static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { | ||
431 | }, | 431 | }, |
432 | }; | 432 | }; |
433 | 433 | ||
434 | +static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { | ||
435 | + [0] = { | ||
436 | + gen_op_bsfw_T0_cc, | ||
437 | + gen_op_bsrw_T0_cc, | ||
438 | + }, | ||
439 | + [1] = { | ||
440 | + gen_op_bsfl_T0_cc, | ||
441 | + gen_op_bsrl_T0_cc, | ||
442 | + }, | ||
443 | +}; | ||
444 | + | ||
434 | static GenOpFunc *gen_op_lds_T0_A0[3] = { | 445 | static GenOpFunc *gen_op_lds_T0_A0[3] = { |
435 | gen_op_ldsb_T0_A0, | 446 | gen_op_ldsb_T0_A0, |
436 | gen_op_ldsw_T0_A0, | 447 | gen_op_ldsw_T0_A0, |
@@ -652,15 +663,16 @@ static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { | @@ -652,15 +663,16 @@ static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { | ||
652 | gen_op_fdivr_ST0_FT0, | 663 | gen_op_fdivr_ST0_FT0, |
653 | }; | 664 | }; |
654 | 665 | ||
666 | +/* NOTE the exception in "r" op ordering */ | ||
655 | static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { | 667 | static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { |
656 | gen_op_fadd_STN_ST0, | 668 | gen_op_fadd_STN_ST0, |
657 | gen_op_fmul_STN_ST0, | 669 | gen_op_fmul_STN_ST0, |
658 | NULL, | 670 | NULL, |
659 | NULL, | 671 | NULL, |
660 | - gen_op_fsub_STN_ST0, | ||
661 | gen_op_fsubr_STN_ST0, | 672 | gen_op_fsubr_STN_ST0, |
662 | - gen_op_fdiv_STN_ST0, | 673 | + gen_op_fsub_STN_ST0, |
663 | gen_op_fdivr_STN_ST0, | 674 | gen_op_fdivr_STN_ST0, |
675 | + gen_op_fdiv_STN_ST0, | ||
664 | }; | 676 | }; |
665 | 677 | ||
666 | static void gen_op(DisasContext *s1, int op, int ot, int d, int s) | 678 | static void gen_op(DisasContext *s1, int op, int ot, int d, int s) |
@@ -1866,13 +1878,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -1866,13 +1878,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1866 | case 0x0f: /* fnstcw mem */ | 1878 | case 0x0f: /* fnstcw mem */ |
1867 | gen_op_fnstcw_A0(); | 1879 | gen_op_fnstcw_A0(); |
1868 | break; | 1880 | break; |
1881 | + case 0x1d: /* fldt mem */ | ||
1882 | + gen_op_fpush(); | ||
1883 | + gen_op_fldt_ST0_A0(); | ||
1884 | + break; | ||
1885 | + case 0x1f: /* fstpt mem */ | ||
1886 | + gen_op_fstt_ST0_A0(); | ||
1887 | + gen_op_fpop(); | ||
1888 | + break; | ||
1869 | case 0x2f: /* fnstsw mem */ | 1889 | case 0x2f: /* fnstsw mem */ |
1870 | gen_op_fnstsw_A0(); | 1890 | gen_op_fnstsw_A0(); |
1871 | break; | 1891 | break; |
1872 | case 0x3c: /* fbld */ | 1892 | case 0x3c: /* fbld */ |
1893 | + gen_op_fpush(); | ||
1894 | + op_fbld_ST0_A0(); | ||
1895 | + break; | ||
1873 | case 0x3e: /* fbstp */ | 1896 | case 0x3e: /* fbstp */ |
1874 | - error("float BCD not hanlded"); | ||
1875 | - return -1; | 1897 | + gen_op_fbst_ST0_A0(); |
1898 | + gen_op_fpop(); | ||
1899 | + break; | ||
1876 | case 0x3d: /* fildll */ | 1900 | case 0x3d: /* fildll */ |
1877 | gen_op_fpush(); | 1901 | gen_op_fpush(); |
1878 | gen_op_fildll_ST0_A0(); | 1902 | gen_op_fildll_ST0_A0(); |
@@ -1882,7 +1906,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -1882,7 +1906,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1882 | gen_op_fpop(); | 1906 | gen_op_fpop(); |
1883 | break; | 1907 | break; |
1884 | default: | 1908 | default: |
1885 | - error("unhandled memory FP [op=0x%02x]\n", op); | 1909 | + error("unhandled FPm [op=0x%02x]\n", op); |
1886 | return -1; | 1910 | return -1; |
1887 | } | 1911 | } |
1888 | } else { | 1912 | } else { |
@@ -1895,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -1895,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1895 | gen_op_fmov_ST0_STN((opreg + 1) & 7); | 1919 | gen_op_fmov_ST0_STN((opreg + 1) & 7); |
1896 | break; | 1920 | break; |
1897 | case 0x09: /* fxchg sti */ | 1921 | case 0x09: /* fxchg sti */ |
1898 | - gen_op_fxchg_ST0_STN((opreg + 1) & 7); | 1922 | + gen_op_fxchg_ST0_STN(opreg); |
1899 | break; | 1923 | break; |
1900 | case 0x0a: /* grp d9/2 */ | 1924 | case 0x0a: /* grp d9/2 */ |
1901 | switch(rm) { | 1925 | switch(rm) { |
@@ -1929,24 +1953,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -1929,24 +1953,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
1929 | { | 1953 | { |
1930 | switch(rm) { | 1954 | switch(rm) { |
1931 | case 0: | 1955 | case 0: |
1956 | + gen_op_fpush(); | ||
1932 | gen_op_fld1_ST0(); | 1957 | gen_op_fld1_ST0(); |
1933 | break; | 1958 | break; |
1934 | case 1: | 1959 | case 1: |
1935 | - gen_op_fld2t_ST0(); | 1960 | + gen_op_fpush(); |
1961 | + gen_op_fldl2t_ST0(); | ||
1936 | break; | 1962 | break; |
1937 | case 2: | 1963 | case 2: |
1938 | - gen_op_fld2e_ST0(); | 1964 | + gen_op_fpush(); |
1965 | + gen_op_fldl2e_ST0(); | ||
1939 | break; | 1966 | break; |
1940 | case 3: | 1967 | case 3: |
1968 | + gen_op_fpush(); | ||
1941 | gen_op_fldpi_ST0(); | 1969 | gen_op_fldpi_ST0(); |
1942 | break; | 1970 | break; |
1943 | case 4: | 1971 | case 4: |
1972 | + gen_op_fpush(); | ||
1944 | gen_op_fldlg2_ST0(); | 1973 | gen_op_fldlg2_ST0(); |
1945 | break; | 1974 | break; |
1946 | case 5: | 1975 | case 5: |
1976 | + gen_op_fpush(); | ||
1947 | gen_op_fldln2_ST0(); | 1977 | gen_op_fldln2_ST0(); |
1948 | break; | 1978 | break; |
1949 | case 6: | 1979 | case 6: |
1980 | + gen_op_fpush(); | ||
1950 | gen_op_fldz_ST0(); | 1981 | gen_op_fldz_ST0(); |
1951 | break; | 1982 | break; |
1952 | default: | 1983 | default: |
@@ -2021,12 +2052,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2021,12 +2052,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2021 | op1 = op & 7; | 2052 | op1 = op & 7; |
2022 | if (op >= 0x20) { | 2053 | if (op >= 0x20) { |
2023 | gen_op_fp_arith_STN_ST0[op1](opreg); | 2054 | gen_op_fp_arith_STN_ST0[op1](opreg); |
2055 | + if (op >= 0x30) | ||
2056 | + gen_op_fpop(); | ||
2024 | } else { | 2057 | } else { |
2025 | gen_op_fmov_FT0_STN(opreg); | 2058 | gen_op_fmov_FT0_STN(opreg); |
2026 | gen_op_fp_arith_ST0_FT0[op1](); | 2059 | gen_op_fp_arith_ST0_FT0[op1](); |
2027 | } | 2060 | } |
2028 | - if (op >= 0x30) | ||
2029 | - gen_op_fpop(); | ||
2030 | } | 2061 | } |
2031 | break; | 2062 | break; |
2032 | case 0x02: /* fcom */ | 2063 | case 0x02: /* fcom */ |
@@ -2042,7 +2073,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2042,7 +2073,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2042 | switch(rm) { | 2073 | switch(rm) { |
2043 | case 1: /* fucompp */ | 2074 | case 1: /* fucompp */ |
2044 | gen_op_fmov_FT0_STN(1); | 2075 | gen_op_fmov_FT0_STN(1); |
2045 | - gen_op_fcom_ST0_FT0(); | 2076 | + gen_op_fucom_ST0_FT0(); |
2046 | gen_op_fpop(); | 2077 | gen_op_fpop(); |
2047 | gen_op_fpop(); | 2078 | gen_op_fpop(); |
2048 | break; | 2079 | break; |
@@ -2057,6 +2088,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2057,6 +2088,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2057 | gen_op_fmov_STN_ST0(opreg); | 2088 | gen_op_fmov_STN_ST0(opreg); |
2058 | gen_op_fpop(); | 2089 | gen_op_fpop(); |
2059 | break; | 2090 | break; |
2091 | + case 0x2c: /* fucom st(i) */ | ||
2092 | + gen_op_fmov_FT0_STN(opreg); | ||
2093 | + gen_op_fucom_ST0_FT0(); | ||
2094 | + break; | ||
2095 | + case 0x2d: /* fucomp st(i) */ | ||
2096 | + gen_op_fmov_FT0_STN(opreg); | ||
2097 | + gen_op_fucom_ST0_FT0(); | ||
2098 | + gen_op_fpop(); | ||
2099 | + break; | ||
2060 | case 0x33: /* de/3 */ | 2100 | case 0x33: /* de/3 */ |
2061 | switch(rm) { | 2101 | switch(rm) { |
2062 | case 1: /* fcompp */ | 2102 | case 1: /* fcompp */ |
@@ -2071,18 +2111,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2071,18 +2111,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2071 | break; | 2111 | break; |
2072 | case 0x3c: /* df/4 */ | 2112 | case 0x3c: /* df/4 */ |
2073 | switch(rm) { | 2113 | switch(rm) { |
2074 | -#if 0 | ||
2075 | case 0: | 2114 | case 0: |
2076 | - gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO); | 2115 | + gen_op_fnstsw_EAX(); |
2077 | break; | 2116 | break; |
2078 | -#endif | ||
2079 | default: | 2117 | default: |
2080 | - error("unhandled FP df/4\n"); | 2118 | + error("unhandled FP %x df/4\n", rm); |
2081 | return -1; | 2119 | return -1; |
2082 | } | 2120 | } |
2083 | break; | 2121 | break; |
2084 | default: | 2122 | default: |
2085 | - error("unhandled FP\n"); | 2123 | + error("unhandled FPr [op=0x%x]\n", op); |
2086 | return -1; | 2124 | return -1; |
2087 | } | 2125 | } |
2088 | } | 2126 | } |
@@ -2413,7 +2451,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | @@ -2413,7 +2451,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) | ||
2413 | gen_op_mov_reg_T0[ot][rm](); | 2451 | gen_op_mov_reg_T0[ot][rm](); |
2414 | } | 2452 | } |
2415 | break; | 2453 | break; |
2416 | - | 2454 | + case 0x1bc: /* bsf */ |
2455 | + case 0x1bd: /* bsr */ | ||
2456 | + ot = dflag ? OT_LONG : OT_WORD; | ||
2457 | + modrm = ldub(s->pc++); | ||
2458 | + reg = (modrm >> 3) & 7; | ||
2459 | + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); | ||
2460 | + gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); | ||
2461 | + /* NOTE: we always write back the result. Intel doc says it is | ||
2462 | + undefined if T0 == 0 */ | ||
2463 | + gen_op_mov_reg_T0[ot][reg](); | ||
2464 | + s->cc_op = CC_OP_LOGICB + ot; | ||
2465 | + break; | ||
2417 | /************************/ | 2466 | /************************/ |
2418 | /* misc */ | 2467 | /* misc */ |
2419 | case 0x90: /* nop */ | 2468 | case 0x90: /* nop */ |