Commit 77f8dd5add8f02253dcea1454c9d2c76d7c788a7

Authored by bellard
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
Makefile
... ... @@ -83,6 +83,7 @@ cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\
83 83 dis-asm.h gen-i386.h op-i386.h syscall.c\
84 84 dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
85 85 i386.ld ppc.ld\
  86 +tests/Makefile\
86 87 tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
87 88 tests/test-i386-muldiv.h\
88 89 tests/test2.c tests/hello.c tests/sha1.c tests/test1.c
... ...
... ... @@ -3,4 +3,4 @@
3 3 - threads
4 4 - fix printf for doubles (fp87.c bug ?)
5 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 114 };
115 115  
116 116 #ifdef __i386__
117   -#define USE_X86LDOUBLE
  117 +//#define USE_X86LDOUBLE
118 118 #endif
119 119  
120 120 #ifdef USE_X86LDOUBLE
... ... @@ -201,7 +201,7 @@ static inline void stl(void *ptr, int v)
201 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 206 *(uint64_t *)ptr = v;
207 207 }
... ...
op-i386.c
... ... @@ -1055,7 +1055,7 @@ typedef union {
1055 1055  
1056 1056 #else
1057 1057  
1058   -typedef {
  1058 +typedef union {
1059 1059 double d;
1060 1060 #ifndef WORDS_BIGENDIAN
1061 1061 struct {
... ... @@ -1119,6 +1119,31 @@ void OPPROTO op_fldl_ST0_A0(void)
1119 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 1147 void OPPROTO op_fild_ST0_A0(void)
1123 1148 {
1124 1149 ST0 = (CPU86_LDouble)ldsw((void *)A0);
... ... @@ -1143,9 +1168,34 @@ void OPPROTO op_fsts_ST0_A0(void)
1143 1168  
1144 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 1199 void OPPROTO op_fist_ST0_A0(void)
1150 1200 {
1151 1201 int val;
... ... @@ -1167,6 +1217,103 @@ void OPPROTO op_fistll_ST0_A0(void)
1167 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 1317 /* FPU move */
1171 1318  
1172 1319 static inline void fpush(void)
... ... @@ -1244,6 +1391,17 @@ void OPPROTO op_fcom_ST0_FT0(void)
1244 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 1405 void OPPROTO op_fadd_ST0_FT0(void)
1248 1406 {
1249 1407 ST0 += FT0;
... ... @@ -1321,7 +1479,7 @@ void OPPROTO op_fabs_ST0(void)
1321 1479 ST0 = fabs(ST0);
1322 1480 }
1323 1481  
1324   -void OPPROTO op_fxam_ST0(void)
  1482 +void helper_fxam_ST0(void)
1325 1483 {
1326 1484 CPU86_LDoubleU temp;
1327 1485 int expdif;
... ... @@ -1346,7 +1504,11 @@ void OPPROTO op_fxam_ST0(void)
1346 1504 } else {
1347 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 1514 void OPPROTO op_fld1_ST0(void)
... ... @@ -1354,12 +1516,12 @@ void OPPROTO op_fld1_ST0(void)
1354 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 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 1526 ST0 = *(CPU86_LDouble *)&f15rk[5];
1365 1527 }
... ... @@ -1681,6 +1843,13 @@ void OPPROTO op_fnstsw_A0(void)
1681 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 1853 void OPPROTO op_fnstcw_A0(void)
1685 1854 {
1686 1855 stw((void *)A0, env->fpuc);
... ... @@ -1784,6 +1953,10 @@ int cpu_x86_exec(CPUX86State *env1)
1784 1953 eflags & CC_P ? 'P' : '-',
1785 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 1961 #endif
1789 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 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 672 #endif
637 673  
638 674 /* string operations */
... ...
translate-i386.c
... ... @@ -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 445 static GenOpFunc *gen_op_lds_T0_A0[3] = {
435 446 gen_op_ldsb_T0_A0,
436 447 gen_op_ldsw_T0_A0,
... ... @@ -652,15 +663,16 @@ static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = {
652 663 gen_op_fdivr_ST0_FT0,
653 664 };
654 665  
  666 +/* NOTE the exception in "r" op ordering */
655 667 static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
656 668 gen_op_fadd_STN_ST0,
657 669 gen_op_fmul_STN_ST0,
658 670 NULL,
659 671 NULL,
660   - gen_op_fsub_STN_ST0,
661 672 gen_op_fsubr_STN_ST0,
662   - gen_op_fdiv_STN_ST0,
  673 + gen_op_fsub_STN_ST0,
663 674 gen_op_fdivr_STN_ST0,
  675 + gen_op_fdiv_STN_ST0,
664 676 };
665 677  
666 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 1878 case 0x0f: /* fnstcw mem */
1867 1879 gen_op_fnstcw_A0();
1868 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 1889 case 0x2f: /* fnstsw mem */
1870 1890 gen_op_fnstsw_A0();
1871 1891 break;
1872 1892 case 0x3c: /* fbld */
  1893 + gen_op_fpush();
  1894 + op_fbld_ST0_A0();
  1895 + break;
1873 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 1900 case 0x3d: /* fildll */
1877 1901 gen_op_fpush();
1878 1902 gen_op_fildll_ST0_A0();
... ... @@ -1882,7 +1906,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1882 1906 gen_op_fpop();
1883 1907 break;
1884 1908 default:
1885   - error("unhandled memory FP [op=0x%02x]\n", op);
  1909 + error("unhandled FPm [op=0x%02x]\n", op);
1886 1910 return -1;
1887 1911 }
1888 1912 } else {
... ... @@ -1895,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1895 1919 gen_op_fmov_ST0_STN((opreg + 1) & 7);
1896 1920 break;
1897 1921 case 0x09: /* fxchg sti */
1898   - gen_op_fxchg_ST0_STN((opreg + 1) & 7);
  1922 + gen_op_fxchg_ST0_STN(opreg);
1899 1923 break;
1900 1924 case 0x0a: /* grp d9/2 */
1901 1925 switch(rm) {
... ... @@ -1929,24 +1953,31 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
1929 1953 {
1930 1954 switch(rm) {
1931 1955 case 0:
  1956 + gen_op_fpush();
1932 1957 gen_op_fld1_ST0();
1933 1958 break;
1934 1959 case 1:
1935   - gen_op_fld2t_ST0();
  1960 + gen_op_fpush();
  1961 + gen_op_fldl2t_ST0();
1936 1962 break;
1937 1963 case 2:
1938   - gen_op_fld2e_ST0();
  1964 + gen_op_fpush();
  1965 + gen_op_fldl2e_ST0();
1939 1966 break;
1940 1967 case 3:
  1968 + gen_op_fpush();
1941 1969 gen_op_fldpi_ST0();
1942 1970 break;
1943 1971 case 4:
  1972 + gen_op_fpush();
1944 1973 gen_op_fldlg2_ST0();
1945 1974 break;
1946 1975 case 5:
  1976 + gen_op_fpush();
1947 1977 gen_op_fldln2_ST0();
1948 1978 break;
1949 1979 case 6:
  1980 + gen_op_fpush();
1950 1981 gen_op_fldz_ST0();
1951 1982 break;
1952 1983 default:
... ... @@ -2021,12 +2052,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2021 2052 op1 = op & 7;
2022 2053 if (op >= 0x20) {
2023 2054 gen_op_fp_arith_STN_ST0[op1](opreg);
  2055 + if (op >= 0x30)
  2056 + gen_op_fpop();
2024 2057 } else {
2025 2058 gen_op_fmov_FT0_STN(opreg);
2026 2059 gen_op_fp_arith_ST0_FT0[op1]();
2027 2060 }
2028   - if (op >= 0x30)
2029   - gen_op_fpop();
2030 2061 }
2031 2062 break;
2032 2063 case 0x02: /* fcom */
... ... @@ -2042,7 +2073,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2042 2073 switch(rm) {
2043 2074 case 1: /* fucompp */
2044 2075 gen_op_fmov_FT0_STN(1);
2045   - gen_op_fcom_ST0_FT0();
  2076 + gen_op_fucom_ST0_FT0();
2046 2077 gen_op_fpop();
2047 2078 gen_op_fpop();
2048 2079 break;
... ... @@ -2057,6 +2088,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2057 2088 gen_op_fmov_STN_ST0(opreg);
2058 2089 gen_op_fpop();
2059 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 2100 case 0x33: /* de/3 */
2061 2101 switch(rm) {
2062 2102 case 1: /* fcompp */
... ... @@ -2071,18 +2111,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
2071 2111 break;
2072 2112 case 0x3c: /* df/4 */
2073 2113 switch(rm) {
2074   -#if 0
2075 2114 case 0:
2076   - gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO);
  2115 + gen_op_fnstsw_EAX();
2077 2116 break;
2078   -#endif
2079 2117 default:
2080   - error("unhandled FP df/4\n");
  2118 + error("unhandled FP %x df/4\n", rm);
2081 2119 return -1;
2082 2120 }
2083 2121 break;
2084 2122 default:
2085   - error("unhandled FP\n");
  2123 + error("unhandled FPr [op=0x%x]\n", op);
2086 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 2451 gen_op_mov_reg_T0[ot][rm]();
2414 2452 }
2415 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 2467 /* misc */
2419 2468 case 0x90: /* nop */
... ...