1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144
|
; DEBUG.ASM NASM assembler source for a clone of DEBUG.COM
; Version 0.98, 10/27/2003.
; To assemble, use:
; nasm debug.asm -O 2 -o debug.com
; ============================================================================
;
; Copyright (c) 1995-2003 Paul Vojta
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to
; deal in the Software without restriction, including without limitation the
; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
; sell copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in
; all copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
; PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
; IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
;
; ============================================================================
; Revision history:
; 0.95e [11 January 2003] Fixed a bug in the assember.
; 0.95f [10 September 2003] Converted to NASM; fixed some syntax
; incompatibilities.
; 0.98 [27 October 2003] Added EMS commands and copyright conditions.
; To do:
; *.HEX files
; < and > and >>
; MMX instructions
BS equ 8
TAB equ 9
LF equ 10
CR equ 13
TOLOWER equ 20h
TOUPPER equ 0dfh
TOUPPER_W equ 0dfdfh
LINE_IN_LEN equ 257 ;length of line_in (including header stuff)
; PSP offsets
ALASAP equ 02h ;Address of Last segment allocated to program
TPIVOFS equ 0ah ;Terminate Program Interrupt Vector offset
TPIVSEG equ 0ch ;Terminate program Interrupt Vector segment
CCIV equ 0eh ;Control C Interrupt Vector
CEIV equ 12h ;Critical Error Interrupt Vector
SPSAV equ 2eh ;Save the stack pointer here
DTA equ 80h ;Program arguments; also used to store file name (N cmd)
org 100h
cpu 8086
jmp initcode
cmdlist dw aa,error,cc,ddd,ee,ff,gg,hh,ii,error,error,ll,mm,nn,oo
dw pp,qq,rr,sss,tt,uu,error,ww,xx
savesp dw 0 ;save stack pointer
errret dw 0 ;return here if error
run_sp dw 0 ;stack pointer when running
spadjust dw 0 ;adjust sp by this amount for save
psp dw 0 ;program segment prefix
running db 0 ;if there is a running child process
run2324 dw 0,0,0,0 ;interrupt vectors 23 and 24 (when running)
sav2324 dw 0,0,0,0 ;interrupt vectors 23 and 24 (ours)
hakstat db 0 ;whether we have hacked the vectors or not
psp22 dw 0,0 ;original terminate address in the PSP
parent dw 0 ;original PSP of process parent (must be next)
newmem dw 0 ;size of DEBUG if it hasn't shrunk yet
machine db 0 ;type of this processor
has_87 db 0 ;if there is a math coprocessor present
mach_87 db 0 ;type of coprocessor present
notatty db LF ;if standard input is from a file
switchar db 0 ;switch character
swch1 db ' ' ;switch character if it's a slash
promptlen dw 0 ;length of prompt
bufnext dw line_in+2 ;address of next available character
bufend dw line_in+2 ;address + 1 of last valid character
a_addr dw 0,0 ;address for next 'a' command
d_addr dw 0,0 ;address of last `d' command; must follow a_addr
u_addr dw 0,0 ;address of last `u' command; must follow d_addr
eqflag db 0 ;flag indicating presence of `=' operand
eqladdr dw 0,0 ;address of `=' operand in G or T command
run_cs dw 0 ;save original CS when running
run_int dw 0 ;interrupt type that stopped the running
prg_trm db 0 ;if program has terminated
fileext db 0 ;file extension (0 if no file name)
EXT_OTHER equ 1
EXT_COM equ 2
EXT_EXE equ 4
EXT_HEX equ 8
intsave dw 0,0 ;save area for interrupt vectors 0, 1, and 3
dw 0,0
dw 0,0
; Parameter block for exec call.
execblk dw 0 ;(0) copy the parent's environment
dw 0,0 ;(2) address of command tail to copy
dw 5ch,0 ;(6) address of first FCB to copy
dw 6ch,0 ;(10) address of second FCB to copy
dw 0,0 ;(14) initial SS:SP
dw 0,0 ;(18) initial CS:IP
; Register save area.
regs:
reg_ax dw 0 ;ax
reg_bx dw 0 ;bx
reg_cx dw 0 ;cx
reg_dx dw 0 ;dx
reg_sp dw 0 ;sp
reg_bp dw 0 ;bp
reg_si dw 0 ;si
reg_di dw 0 ;di
reg_ds dw 0 ;ds
reg_es dw 0 ;es
reg_ss dw 0 ;ss
reg_cs dw 0 ;cs
reg_ip dw 100h ;ip
flags dw 200h ;flags (interrupts enabled)
regnames dw 'AX','BX','CX','DX','SP','BP','SI','DI','DS','ES'
dw 'SS','CS','IP'
segletrs db 'd','e','s','c'
; Instruction set information needed for the 'p' command.
ppbytes db 66h,67h,26h,2eh,36h,3eh,64h,65h,0f2h,0f3h ;prefixes
db 0ach,0adh,0aah,0abh,0a4h,0a5h ;lods,stos,movs
db 0a6h,0a7h,0aeh,0afh ;cmps,scas
db 6ch,6dh,6eh,6fh ;ins,outs
db 0cch,0cdh ;int instructions
db 0e0h,0e1h,0e2h ;loop instructions
db 0e8h ;call rel16/32
db 09ah ;call far seg16:16/32
; (This last one is done explicitly by the code.)
; db 0ffh ;ff/2 or ff/3: indirect call
; Info for the above, respectively.
; 80h = prefix; 82h = operand size prefix; 81h = address size prefix.
; If the high bit is not set, the next highest bit (40h) indicates that
; the instruction size depends on whether there is an address size prefix,
; and the remaining bits tell the number of additional bytes in the
; instruction.
ppinfo db 82h,81h,80h,80h,80h,80h,80h,80h,80h,80h
db 0,0,0,0,0,0
db 0,0,0,0
db 0,0,0,0
db 0,1
db 1,1,1
db 42h
db 44h
PPLEN equ 31 ;size of the above table
; Strings.
prompt1 db '-' ;main prompt
prompt2 db ':' ;prompt for register value
helpmsg db 'FreeDOS Debug v 0.98 help screen',CR,LF
db 'Altering memory:',CR,LF
db 'compare C range address '
db 'hex add/sub H value1 value2',CR,LF
db 'dump D [range] '
db 'move M range address',CR,LF
db 'enter E address [list] '
db 'search S range list',CR,LF
db 'fill F range list '
db 'expanded mem XA/XD/XM/XS (X? for help)',CR,LF,CR,LF
db 'Assemble/Disassemble:',CR,LF
db 'assemble A [address] '
db 'unassemble U [range]',CR,LF
db '80x86 mode M x (0..6, ? for query) '
db 'set FPU mode MC 387, MNC none, MC2 287',CR,LF,CR,LF
db 'Program execution:',CR,LF
db 'go G [=address] [breakpts] '
db 'quit Q',CR,LF
db 'proceed P [=address] [count] '
db 'trace T [=address] [count]',CR,LF
db 'register R register [value] '
db 'all regs R',CR,LF
db 'input I port '
db 'output O port byte',CR,LF,CR,LF
db 'Disk access:',CR,LF
db 'set name N [[drive:][path]progname [arglist]]',CR,LF
db 'load program L [address]',CR,LF
db 'load L address drive sector number',CR,LF
db 'write prog. W [address]',CR,LF
db 'write W address drive sector number'
crlf db CR,LF,'$'
xhelpmsg db 'Expanded memory (EMS) commands:',CR,LF
db ' Allocate XA count',CR,LF
db ' Deallocate XD handle',CR,LF
db ' Map memory XM logical-page physical-page handle',CR,LF
db ' Show status XS',CR,LF,'$'
errcarat db '^ Error',CR,LF,'$'
dskerrs dw dskerr0,dskerr1,dskerr2,dskerr3,dskerr4,dskerr9,dskerr6,dskerr7
dw dskerr8,dskerr9,dskerra,dskerrb,dskerrc
dskerr0 db 'Write protect error',0
dskerr1 db 'Unknown unit error',0
dskerr2 db 'Drive not ready',0
dskerr3 db 'Unknown command',0
dskerr4 db 'Data error (CRC)',0
dskerr6 db 'Seek error',0
dskerr7 db 'Unknown media type',0
dskerr8 db 'Sector not found',0
dskerr9 db 'Unknown error',0
dskerra db 'Write fault',0
dskerrb db 'Read fault',0
dskerrc db 'General failure',0
reading db ' read',0
writing db ' writ',0
drive db 'ing drive '
driveno db '_',0
msg8088 db '8086/88',0
msgx86 db 'x86',0
no_copr db ' without coprocessor',0
has_copr db ' with coprocessor',0
has_287 db ' with 287',0
unused db ' (unused)',0
needsmsg db '[needs x86]'
needsmsg_L equ 11
needsmath db '[needs math coprocessor]'
needsmath_L equ 24
obsolete db '[obsolete]'
obsolete_L equ 10
int0msg db 'Divide error.',CR,LF,'$'
int1msg db 'Unexpected single-step interrupt.',CR,LF,'$'
int3msg db 'Unexpected breakpoint interrupt.',CR,LF,'$'
progtrm db 'Program terminated normally.',CR,LF,'$'
trmerr db 'Program has terminated.',CR,LF,'$'
nowhexe db 'EXE and HEX files cannot be written.',CR,LF,'$'
nownull db 'Cannot write: no file name given.',CR,LF,'$'
wwmsg1 db 'Writing $'
wwmsg2 db ' bytes.',CR,LF,'$'
diskful db 'Disk full.',CR,LF,'$'
wwerr db 'Error '
wwerr1 db '____ opening file.',CR,LF,'$'
doserr2 db 'File not found.',CR,LF,'$'
doserr3 db 'Path not found.',CR,LF,'$'
doserr5 db 'Access denied.',CR,LF,'$'
doserr8 db 'Insufficient memory.',CR,LF,'$'
emmname db 'EMMXXXX0'
emsnot db 'EMS not installed',CR,LF,'$'
emserr1 db 'EMS internal error',CR,LF,'$'
emserr3 db 'Handle not found',CR,LF,'$'
emserr5 db 'No free handles',CR,LF,'$'
emserr7 db 'Total pages exceeded',CR,LF,'$'
emserr8 db 'Free pages exceeded',CR,LF,'$'
emserr9 db 'Parameter error',CR,LF,'$'
emserra db 'Logical page out of range',CR,LF,'$'
emserrb db 'Physical page out of range',CR,LF,'$'
emserrs dw emserr1,emserr1,0,emserr3,0,emserr5,0,emserr7,emserr8,emserr9
dw emserra,emserrb
emserrx db 'EMS error '
emserrxa db '__',CR,LF,'$'
xaans db 'Handle created = '
xaans1 db '____',CR,LF,'$'
xdans db 'Handle '
xdans1 db '____ deallocated',CR,LF,'$'
xmans db 'Logical page '
xmans1 db '__ mapped to physical page '
xmans2 db '__',CR,LF,'$'
xsstr1 db 'Handle '
xsstr1a db '____ has '
xsstr1b db '____ pages allocated',CR,LF,'$'
xsstr2 db 'Physical page '
xsstr2a db '__ = Frame segment '
xsstr2b db '____',CR,LF,'$'
xsstr3 db '____ of a total '
xsstr3a db '____ EMS $'
xsstr4 db 'es have been allocated',CR,LF,'$'
xsstrpg db 'pag$'
xsstrhd db 'handl$'
; Equates for instruction operands.
; First the sizes.
OP_ALL equ 40h ;byte/word/dword operand (could be 30h but ...)
OP_1632 equ 50h ;word or dword operand
OP_8 equ 60h ;byte operand
OP_16 equ 70h ;word operand
OP_32 equ 80h ;dword operand
OP_SIZE equ OP_ALL ;the lowest of these
; These operand types need to be combined with a size.
OP_IMM equ 0 ;immediate
OP_RM equ 2 ;reg/mem
OP_M equ 4 ;mem (but not reg)
OP_R_MOD equ 6 ;register, determined from MOD R/M part
OP_MOFFS equ 8 ;memory offset; e.g., [1234]
OP_R equ 10 ;reg part of reg/mem byte
OP_R_ADD equ 12 ;register, determined from instruction byte
OP_AX equ 14 ;al or ax or eax
; These don't need a size.
OP_M64 equ 2 ;qword memory
OP_MFLOAT equ 4 ;float memory
OP_MDOUBLE equ 6 ;double-precision floating memory
OP_M80 equ 8 ;tbyte memory
OP_MXX equ 10 ;memory (size unknown)
OP_FARMEM equ 12 ;far memory
OP_FARP equ 14 ;far pointer
OP_REL8 equ 16 ;byte address relative to IP
OP_REL1632 equ 18 ;word or dword address relative to IP
OP_1CHK equ 20 ;check for ST(1)
OP_STI equ 22 ;ST(I)
OP_CR equ 24 ;CRx
OP_DR equ 26 ;DRx
OP_TR equ 28 ;TRx
OP_SEGREG equ 30 ;segment register
OP_IMMS8 equ 32 ;sign extended immediate byte
OP_IMM8 equ 34 ;immediate byte (other args may be (d)word)
OP_ECX equ 36 ;ECX if 32-bit operands; otherwise nothing
OP_SHOSIZ equ 38 ;set flag to always show the size
OP_1 equ 40 ;1 (string ops from here on)
OP_3 equ 42 ;3
OP_DX equ 44 ;DX
OP_CL equ 46 ;CL
OP_ST equ 48 ;ST (top of coprocessor stack)
OP_CS equ 50 ;CS
OP_DS equ 52 ;DS
OP_ES equ 54 ;ES
OP_FS equ 56 ;FS
OP_GS equ 58 ;GS
OP_SS equ 60 ;SS
; Instructions that have an implicit operand subject to a segment override
; (outs, movs, cmps, lods, xlat).
prfxtab db 06eh,06fh,0a4h,0a5h,0a6h,0a7h,0ach,0adh,0d7h
P_LEN equ 9
; Instructions that can be used with REP/REPE/REPNE.
replist db 06ch,06eh,0a4h,0aah,0ach ;REP
db 0a6h,0aeh ;REPE/REPNE
;-@@-@@-@@-Do not edit these tables! They have been automatically generated.
; Main data table for the assembler.
asmtab db 16,139,255,248,64,55,255,248,63,234,255,18,243,255,6,5
db 245,173,221,245,176,68,245,4,212,5,111,255,1,53,245,173
db 67,245,175,170,245,0,4,0,159,255,10,213,245,174,119,245
db 176,222,245,9,164,10,63,255,240,29,205,255,239,29,129,255
db 241,133,148,255,241,133,225,255,249,242,137,49,255,241,126,17
db 241,179,79,255,245,241,133,73,245,241,180,54,255,245,241,130
db 225,245,241,179,233,255,245,241,128,121,245,241,179,156,255,69
db 212,181,59,181,109,46,95,255,249,45,184,255,74,152,255,75
db 204,255,75,50,255,240,78,206,255,73,177,255,244,98,99,255
db 244,97,47,255,244,96,226,255,244,98,22,255,244,96,226,255
db 244,97,124,255,244,100,203,255,244,100,49,255,244,99,228,255
db 244,100,126,255,244,98,22,255,244,96,226,255,244,97,47,255
db 244,98,99,255,244,97,47,255,244,97,201,255,244,100,126,255
db 244,99,228,255,244,100,49,255,244,100,203,255,244,96,149,255
db 244,99,151,255,244,98,253,255,244,97,201,255,244,96,72,255
db 244,99,74,255,244,99,74,255,244,99,151,255,244,98,176,255
db 244,97,124,255,18,13,175,94,177,197,16,220,17,119,255,49
db 238,255,249,50,59,255,245,242,129,244,255,243,183,60,255,243
db 125,186,255,249,46,5,255,11,187,255,14,35,255,254,255,252
db 255,21,185,245,185,165,245,189,142,255,253,255,239,60,58,255
db 65,69,240,255,65,69,225,255,154,19,155,72,65,13,192,66
db 66,192,255,66,221,192,66,198,193,255,154,178,155,231,255,165
db 213,255,170,165,255,65,69,224,255,250,65,223,226,255,244,65
db 244,208,255,244,65,244,192,255,244,65,167,192,255,244,65,167
db 208,255,244,65,167,200,255,244,65,167,208,255,244,65,167,192
db 255,244,65,244,192,255,244,65,244,208,255,244,65,244,200,255
db 244,65,244,216,255,244,65,244,200,255,244,65,167,216,255,244
db 65,167,200,255,158,227,160,24,65,20,208,64,248,209,255,244
db 65,251,240,244,65,223,241,255,244,67,47,240,244,67,19,241
db 255,161,75,162,128,65,20,216,64,248,217,255,66,198,217,255
db 241,65,69,255,255,65,69,246,255,250,65,223,225,255,168,131
db 169,184,65,13,240,66,66,248,255,66,221,248,66,198,249,255
db 169,34,170,87,255,170,235,172,32,65,13,248,66,66,240,255
db 66,221,240,66,198,241,255,171,138,172,191,255,250,65,223,224
db 255,66,148,192,255,159,130,160,183,255,161,234,163,31,255,154
db 255,156,52,168,50,255,65,69,247,255,250,65,223,227,255,159
db 207,161,4,255,162,55,163,108,173,2,255,154,96,155,149,167
db 9,65,96,192,255,65,69,232,255,65,69,233,255,65,69,234
db 255,65,69,235,255,65,69,236,255,65,69,237,255,65,69,238
db 255,250,166,110,255,164,10,255,156,123,157,176,65,13,200,66
db 66,200,255,66,221,200,66,198,201,255,157,26,158,79,255,65
db 69,208,255,65,69,243,255,65,69,248,255,241,65,69,245,255
db 65,69,242,255,65,69,252,255,165,62,255,250,170,14,255,65
db 69,253,255,250,240,65,223,228,255,241,65,69,254,255,241,65
db 69,251,255,65,69,250,255,159,48,160,101,66,148,208,255,161
db 152,162,205,171,217,66,148,216,255,250,171,62,255,250,168,218
db 255,250,67,49,224,172,114,255,163,179,164,232,65,13,224,66
db 66,232,255,66,221,232,66,198,233,255,164,82,165,135,255,166
db 27,167,80,65,13,232,66,66,224,255,66,221,224,66,198,225
db 255,166,186,167,239,255,65,69,228,255,241,66,149,224,241,66
db 121,225,255,244,65,251,232,244,65,223,233,255,244,67,47,232
db 244,67,19,233,255,241,66,149,232,241,66,121,233,255,241,65
db 146,233,255,46,159,255,65,69,229,255,65,97,200,65,69,201
db 255,65,69,244,255,65,69,241,255,65,69,249,255,73,100,255
db 189,219,255,189,65,241,129,171,239,32,78,239,32,79,239,31
db 182,239,31,183,255,68,183,71,32,255,19,81,245,185,88,245
db 239,32,124,255,249,239,32,201,255,61,129,61,207,255,61,246
db 255,242,79,104,255,242,192,80,255,249,62,67,255,35,242,241
db 117,167,255,34,190,241,116,115,255,34,113,241,116,38,255,35
db 165,241,117,90,255,34,113,241,116,38,255,249,68,110,255,35
db 11,241,116,192,255,38,90,241,120,15,255,37,192,241,119,117
db 255,37,115,241,119,40,255,38,13,241,119,194,255,35,165,241
db 117,90,255,34,113,241,116,38,255,34,190,241,116,115,255,35
db 242,241,117,167,255,34,190,241,116,115,255,35,88,241,117,13
db 255,38,13,241,119,194,255,37,115,241,119,40,255,37,192,241
db 119,117,255,38,90,241,120,15,255,34,36,241,115,217,255,37
db 38,241,118,219,255,36,140,241,118,65,255,35,88,241,117,13
db 255,33,215,241,115,140,255,36,217,241,118,142,255,36,217,241
db 118,142,255,37,38,241,118,219,255,36,63,241,117,244,255,35
db 11,241,116,192,255,70,214,70,33,181,213,182,7,70,111,255
db 47,211,255,240,77,162,255,59,72,255,241,130,145,255,58,251
db 255,241,131,43,255,241,131,120,255,42,112,255,239,60,117,255
db 240,190,207,255,240,191,28,255,240,193,68,255,240,192,16,255
db 246,240,51,188,255,249,52,9,255,68,34,68,33,255,67,213
db 67,212,255,67,213,67,212,255,67,136,67,135,255,67,136,67
db 135,255,240,77,239,255,240,193,145,255,48,77,48,232,40,236
db 41,135,42,71,42,226,53,31,55,136,194,234,241,86,231,241
db 87,130,241,87,54,241,87,209,241,88,31,241,88,186,255,49
db 84,255,249,49,161,255,241,134,87,241,134,165,255,241,131,239
db 241,132,61,255,188,244,255,245,188,167,255,43,80,255,245,188
db 90,255,3,157,245,173,144,245,175,247,245,2,108,3,7,255
db 251,255,69,97,71,202,255,239,33,22,255,249,239,33,99,255
db 197,133,26,137,9,140,2,81,7,35,241,125,167,241,128,16
db 255,249,239,29,45,255,249,47,57,255,24,33,182,111,239,32
db 31,239,31,132,4,109,6,214,9,63,2,4,241,125,90,241
db 127,195,255,249,239,28,224,255,249,46,236,255,200,144,202,249
db 239,205,98,255,200,221,203,70,239,205,175,255,199,246,202,95
db 239,204,200,255,200,67,202,172,239,205,21,255,243,92,10,255
db 246,243,246,243,246,242,58,167,58,155,255,61,15,61,3,255
db 243,128,34,255,47,134,255,201,42,203,147,239,205,252,255,202
db 17,204,122,239,206,227,255,11,164,14,13,16,118,18,223,30
db 78,30,156,255,247,38,247,46,247,54,247,62,247,100,247,101
db 201,42,203,147,239,205,252,255,201,119,203,224,239,206,73,255
db 8,109,245,174,42,245,176,145,245,7,60,7,215,255,52,86
db 255,249,52,163,255,241,122,173,255,241,121,121,255,241,121,44
db 255,241,122,96,255,241,121,44,255,241,121,198,255,241,125,21
db 255,241,124,123,255,241,124,46,255,241,124,200,255,241,122,96
db 255,241,121,44,255,241,121,121,255,241,122,173,255,241,121,121
db 255,241,122,19,255,241,124,200,255,241,124,46,255,241,124,123
db 255,241,125,21,255,241,120,223,255,241,123,225,255,241,123,71
db 255,241,122,19,255,241,120,146,255,241,123,148,255,241,123,148
db 255,241,123,225,255,241,122,250,255,241,121,198,255,240,190,53
db 255,240,190,130,255,241,126,151,241,126,229,255,241,128,255,241
db 129,77,255,240,192,169,255,240,191,118,255,74,229,255,76,25
db 255,75,127,255,51,34,255,249,51,111,255,240,192,247,255,13
db 61,245,174,196,245,177,43,245,12,12,12,167,255,50,137,187
db 178,39,184,39,185,255,240,193,222,255,240,194,43,255,46,159
db 255,242,79,181,255,243,91,112,255,245,242,134,196,255,43,149
db 43,150,245,40,82,245,40,83,255,64,171,255,64,171,255,15
db 165,245,175,17,245,177,120,245,14,116,15,15,255
; Data on groups (for the assembler).
agroups dw 131,128,442,255,455,254,246,257,256,198,143,208,210,192
; This is the list of assembler mnemonics.
mnlist db 1,1,"AAA",0,1,4,"AAD",0,1,8,"AAM",0,1,12,"AAS",0
db 1,15,"ADC",0,1,29,"ADD",0,1,43,"AND",0,1,57,"ARPL",0
db 1,61,"BOUND",0,1,65,"BSF",0,1,69,"BSR",0
db 1,73,"BSWAP",0,1,78,"BT",0,1,85,"BTC",0,1,94,"BTR",0
db 1,103,"BTS",0,1,112,"CALL",0,1,122,"CBW",0,2,37,"CDQ",0
db 1,125,"CLC",0,1,128,"CLD",0,1,131,"CLI",0,1,134,"CLTS",0
db 1,138,"CMC",0,1,141,"CMOVA",0,1,145,"CMOVAE",0
db 1,149,"CMOVB",0,1,153,"CMOVBE",0,1,157,"CMOVC",0
db 1,161,"CMOVE",0,1,165,"CMOVG",0,1,169,"CMOVGE",0
db 1,173,"CMOVL",0,1,177,"CMOVLE",0,1,181,"CMOVNA",0
db 1,185,"CMOVNAE",0,1,189,"CMOVNB",0,1,193,"CMOVNBE",0
db 1,197,"CMOVNC",0,1,201,"CMOVNE",0,1,205,"CMOVNG",0
db 1,209,"CMOVNGE",0,1,213,"CMOVNL",0,1,217,"CMOVNLE",0
db 1,221,"CMOVNO",0,1,225,"CMOVNP",0,1,229,"CMOVNS",0
db 1,233,"CMOVNZ",0,1,237,"CMOVO",0,1,241,"CMOVP",0
db 1,245,"CMOVPE",0,1,249,"CMOVPO",0,1,253,"CMOVS",0
db 2,2,"CMOVZ",0,2,6,"CMP",0,2,17,"CMPSB",0
db 2,20,"CMPSD",0,2,21,"CMPSW",0,2,24,"CMPXCHG",0
db 2,29,"CMPXCHG8B",0,2,33,"CPUID",0,6,188,"CS",0
db 2,38,"CWD",0,1,121,"CWDE",0,2,41,"DAA",0,2,44,"DAS",0
db 2,47,"DB",0,2,49,"DD",0,2,51,"DEC",0,2,57,"DIV",0
db 6,192,"DS",0,2,60,"DW",0,2,62,"ENTER",0,6,186,"ES",0
db 2,66,"F2XM1",0,2,70,"FABS",0,2,74,"FADD",0
db 2,85,"FADDP",0,2,97,"FBLD",0,2,100,"FBSTP",0
db 2,103,"FCHS",0,2,107,"FCLEX",0,2,112,"FCMOVA",0
db 2,117,"FCMOVAE",0,2,122,"FCMOVB",0,2,127,"FCMOVBE",0
db 2,132,"FCMOVE",0,2,137,"FCMOVNA",0,2,142,"FCMOVNAE",0
db 2,147,"FCMOVNB",0,2,152,"FCMOVNBE",0,2,157,"FCMOVNE",0
db 2,162,"FCMOVNU",0,2,167,"FCMOVNZ",0,2,172,"FCMOVU",0
db 2,177,"FCMOVZ",0,2,182,"FCOM",0,2,193,"FCOMI",0
db 2,202,"FCOMIP",0,2,211,"FCOMP",0,2,222,"FCOMPP",0
db 2,226,"FCOS",0,2,231,"FDECSTP",0,2,235,"FDISI",0
db 2,240,"FDIV",0,2,251,"FDIVP",0,3,8,"FDIVR",0
db 3,19,"FDIVRP",0,3,31,"FENI",0,3,36,"FFREE",0
db 2,92,"FIADD",0,3,40,"FICOM",0,3,45,"FICOMP",0
db 3,3,"FIDIV",0,3,26,"FIDIVR",0,3,50,"FILD",0
db 3,141,"FIMUL",0,3,57,"FINCSTP",0,3,61,"FINIT",0
db 3,66,"FIST",0,3,71,"FISTP",0,3,253,"FISUB",0
db 4,21,"FISUBR",0,3,78,"FLD",0,3,88,"FLD1",0
db 3,116,"FLDCW",0,3,120,"FLDENV",0,3,96,"FLDL2E",0
db 3,92,"FLDL2T",0,3,104,"FLDLG2",0,3,108,"FLDLN2",0
db 3,100,"FLDPI",0,3,112,"FLDZ",0,3,123,"FMUL",0
db 3,134,"FMULP",0,2,108,"FNCLEX",0,2,236,"FNDISI",0
db 3,32,"FNENI",0,3,62,"FNINIT",0,3,117,"FNLDCW",0
db 3,146,"FNOP",0,3,175,"FNSAVE",0,3,183,"FNSETPM",0
db 3,221,"FNSTCW",0,3,225,"FNSTENV",0,3,229,"FNSTSW",0
db 3,150,"FPATAN",0,3,154,"FPREM",0,3,158,"FPREM1",0
db 3,163,"FPTAN",0,3,167,"FRNDINT",0,3,171,"FRSTOR",0
db 6,194,"FS",0,3,174,"FSAVE",0,3,178,"FSCALE",0
db 3,182,"FSETPM",0,3,188,"FSIN",0,3,193,"FSINCOS",0
db 3,198,"FSQRT",0,3,202,"FST",0,3,220,"FSTCW",0
db 3,224,"FSTENV",0,3,210,"FSTP",0,3,228,"FSTSW",0
db 3,235,"FSUB",0,3,246,"FSUBP",0,4,3,"FSUBR",0
db 4,14,"FSUBRP",0,4,26,"FTST",0,4,30,"FUCOM",0
db 4,39,"FUCOMI",0,4,48,"FUCOMIP",0,4,57,"FUCOMP",0
db 4,66,"FUCOMPP",0,4,71,"FWAIT",0,4,74,"FXAM",0
db 4,78,"FXCH",0,4,85,"FXTRACT",0,4,89,"FYL2X",0
db 4,93,"FYL2XP1",0,6,196,"GS",0,4,97,"HLT",0
db 4,100,"IDIV",0,4,103,"IMUL",0,4,121,"IN",0,4,126,"INC",0
db 4,132,"INSB",0,4,136,"INSD",0,4,137,"INSW",0
db 4,141,"INT",0,4,146,"INTO",0,4,149,"INVD",0
db 4,153,"INVLPG",0,4,158,"IRET",0,4,157,"IRETD",0
db 4,161,"JA",0,4,167,"JAE",0,4,173,"JB",0,4,179,"JBE",0
db 4,185,"JC",0,4,192,"JCXZ",0,4,195,"JE",0,4,191,"JECXZ",0
db 4,201,"JG",0,4,207,"JGE",0,4,213,"JL",0,4,219,"JLE",0
db 5,90,"JMP",0,4,225,"JNA",0,4,231,"JNAE",0,4,237,"JNB",0
db 4,243,"JNBE",0,4,249,"JNC",0,4,255,"JNE",0,5,6,"JNG",0
db 5,12,"JNGE",0,5,18,"JNL",0,5,24,"JNLE",0
db 5,30,"JNO",0,5,36,"JNP",0,5,42,"JNS",0,5,48,"JNZ",0
db 5,54,"JO",0,5,60,"JP",0,5,66,"JPE",0,5,72,"JPO",0
db 5,78,"JS",0,5,84,"JZ",0,5,101,"LAHF",0,5,104,"LAR",0
db 5,108,"LDS",0,5,126,"LEA",0,5,129,"LEAVE",0
db 5,115,"LES",0,5,118,"LFS",0,5,133,"LGDT",0,5,122,"LGS",0
db 5,137,"LIDT",0,5,141,"LLDT",0,5,145,"LMSW",0
db 5,149,"LOCK",0,5,151,"LODSB",0,5,154,"LODSD",0
db 5,155,"LODSW",0,5,158,"LOOP",0,5,163,"LOOPE",0
db 5,173,"LOOPNE",0,5,178,"LOOPNZ",0,5,168,"LOOPZ",0
db 5,183,"LSL",0,5,111,"LSS",0,5,187,"LTR",0,5,191,"MOV",0
db 5,228,"MOVSB",0,5,231,"MOVSD",0,5,232,"MOVSW",0
db 5,235,"MOVSX",0,5,242,"MOVZX",0,5,249,"MUL",0
db 5,252,"NEG",0,6,1,"NOP",0,6,4,"NOT",0,6,8,"OR",0
db 6,22,"ORG",0,6,24,"OUT",0,6,29,"OUTSB",0
db 6,33,"OUTSD",0,6,34,"OUTSW",0,6,38,"POP",0
db 6,56,"POPA",0,6,55,"POPAD",0,6,61,"POPF",0
db 6,60,"POPFD",0,6,64,"PUSH",0,6,90,"PUSHA",0
db 6,89,"PUSHAD",0,6,95,"PUSHF",0,6,94,"PUSHFD",0
db 6,98,"RCL",0,6,106,"RCR",0,6,130,"RDMSR",0
db 6,134,"REP",0,6,136,"REPE",0,6,138,"REPNE",0
db 6,140,"RET",0,6,145,"RETF",0,6,114,"ROL",0,6,122,"ROR",0
db 6,150,"RSM",0,6,154,"SAHF",0,6,157,"SAL",0,6,165,"SAR",0
db 6,214,"SBB",0,6,228,"SCASB",0,6,231,"SCASD",0
db 6,232,"SCASW",0,6,173,"SEG",0,6,235,"SETA",0
db 6,239,"SETAE",0,6,243,"SETB",0,6,247,"SETBE",0
db 6,251,"SETC",0,6,255,"SETE",0,7,4,"SETG",0
db 7,8,"SETGE",0,7,12,"SETL",0,7,16,"SETLE",0
db 7,20,"SETNA",0,7,24,"SETNAE",0,7,28,"SETNB",0
db 7,32,"SETNBE",0,7,36,"SETNC",0,7,40,"SETNE",0
db 7,44,"SETNG",0,7,48,"SETNGE",0,7,52,"SETNL",0
db 7,56,"SETNLE",0,7,60,"SETNO",0,7,64,"SETNP",0
db 7,68,"SETNS",0,7,72,"SETNZ",0,7,76,"SETO",0
db 7,80,"SETP",0,7,84,"SETPE",0,7,88,"SETPO",0
db 7,92,"SETS",0,7,96,"SETZ",0,7,100,"SGDT",0
db 6,198,"SHL",0,7,108,"SHLD",0,6,206,"SHR",0
db 7,115,"SHRD",0,7,104,"SIDT",0,7,122,"SLDT",0
db 7,126,"SMSW",0,6,190,"SS",0,7,130,"STC",0,7,133,"STD",0
db 7,136,"STI",0,7,139,"STOSB",0,7,142,"STOSD",0
db 7,143,"STOSW",0,7,146,"STR",0,7,150,"SUB",0
db 7,164,"TEST",0,7,173,"VERR",0,7,177,"VERW",0
db 7,181,"WAIT",0,7,184,"WBINVD",0,7,188,"WRMSR",0
db 7,192,"XADD",0,7,197,"XCHG",0,7,208,"XLAT",0
db 7,211,"XLATB",0,7,214,"XOR",0
end_mnlist:
; These are equates to refer to the above mnemonics.
MNEM_BSWAP EQU 71
MNEM_DB EQU 506
MNEM_LOCK EQU 1819
MNEM_REP EQU 2117
MNEM_REPE EQU 2123
MNEM_REPNE EQU 2130
MNEM_SEG EQU 2218
MNEM_WAIT EQU 2592
; Number of entries in the following array.
ASMMOD EQU 77
; This is an array of indices into the oplists array (below).
; It is used by the assembler to save space.
opindex db 0,1,4,7,10,13,16,19,22,25,27,30,33,35,37,39,41
db 43,45,48,50,52,55,58,62,64,66,68,70,73,75,77,81
db 85,89,93,96,99,101,103,105,108,110,112,115,118,121,124,127
db 130,134,138,141,144,146,148,150,152,154,156,158,161,164,167,170
db 173,175,177,181,185,188,191,194,197,200,203,206
; These are the lists of operands for the various instruction types.
oplists db 0 ;simple instruction
db OP_ALL+OP_AX, OP_ALL+OP_IMM, 0
db OP_ALL+OP_RM, OP_ALL+OP_IMM, 0
db OP_1632+OP_RM, OP_IMMS8, 0
db OP_ALL+OP_RM, OP_ALL+OP_R, 0
db OP_ALL+OP_R, OP_ALL+OP_RM, 0
db OP_16+OP_RM, OP_16+OP_R, 0
db OP_1632+OP_R, OP_1632+OP_M, 0
db OP_1632+OP_R, OP_1632+OP_RM, 0
db OP_32+OP_R_ADD, 0
db OP_1632+OP_RM, OP_1632+OP_R, 0
db OP_1632+OP_RM, OP_IMM8, 0
db OP_REL1632, 0
db OP_FARP, 0
db OP_FARMEM, 0
db OP_M64, 0
db OP_ALL+OP_RM, 0
db OP_1632+OP_R_ADD, 0
db OP_16+OP_IMM, OP_IMM8, 0
db OP_MFLOAT, 0
db OP_MDOUBLE, 0
db OP_ST, OP_STI, 0
db OP_STI, OP_ST, 0
db OP_1CHK, OP_STI, OP_ST, 0
db OP_32+OP_M, 0
db OP_16+OP_M, 0
db OP_M80, 0
db OP_STI, 0
db OP_1CHK, OP_STI, 0
db OP_MXX, 0
db OP_16+OP_AX, 0
db OP_1632+OP_R, OP_1632+OP_RM, OP_IMMS8, 0
db OP_1632+OP_R_MOD, OP_1632+OP_R, OP_IMMS8, 0
db OP_1632+OP_R, OP_1632+OP_RM, OP_1632+OP_IMM, 0
db OP_1632+OP_R_MOD, OP_1632+OP_R, OP_1632+OP_IMM, 0
db OP_ALL+OP_AX, OP_IMM8, 0
db OP_ALL+OP_AX, OP_DX, 0
db OP_3, 0
db OP_IMM8, 0
db OP_REL8, 0
db OP_ECX, OP_REL8, 0
db OP_1632+OP_RM, 0
db OP_16+OP_RM, 0
db OP_16+OP_RM, OP_SEGREG, 0
db OP_SEGREG, OP_16+OP_RM, 0
db OP_ALL+OP_AX, OP_ALL+OP_MOFFS, 0
db OP_ALL+OP_MOFFS, OP_ALL+OP_AX, 0
db OP_8+OP_R_ADD, OP_8+OP_IMM, 0
db OP_1632+OP_R_ADD, OP_1632+OP_IMM, 0
db OP_1632+OP_R, OP_SHOSIZ, OP_8+OP_RM, 0
db OP_1632+OP_R, OP_SHOSIZ, OP_16+OP_RM, 0
db OP_IMM8, OP_ALL+OP_AX, 0
db OP_DX, OP_ALL+OP_AX, 0
db OP_1632+OP_M, 0
db OP_ES, 0
db OP_CS, 0
db OP_SS, 0
db OP_DS, 0
db OP_FS, 0
db OP_GS, 0
db OP_SHOSIZ, OP_1632+OP_IMM, 0
db OP_SHOSIZ, OP_IMM8, 0
db OP_ALL+OP_RM, OP_1, 0
db OP_ALL+OP_RM, OP_CL, 0
db OP_ALL+OP_RM, OP_IMM8, 0
db OP_16+OP_IMM, 0
db OP_8+OP_RM, 0
db OP_1632+OP_RM, OP_1632+OP_R, OP_IMM8, 0
db OP_1632+OP_RM, OP_1632+OP_R, OP_CL, 0
db OP_1632+OP_AX, OP_1632+OP_R_ADD, 0
db OP_1632+OP_R_ADD, OP_1632+OP_AX, 0
db OP_32+OP_R_MOD, OP_CR, 0
db OP_CR, OP_32+OP_R_MOD, 0
db OP_32+OP_R_MOD, OP_DR, 0
db OP_DR, OP_32+OP_R_MOD, 0
db OP_32+OP_R_MOD, OP_TR, 0
db OP_TR, OP_32+OP_R_MOD, 0
OPTYPES_BASE EQU 12
OPLIST_Z EQU 113
OPLIST_ES EQU 158
; Here is the compressed table of the opcode types.
optypes db 22, 22, 25, 25, 13, 13,158,158 ; 00 - 07 (main opcode part)
db 22, 22, 25, 25, 13, 13,160, 2 ; 08 - 0f
db 22, 22, 25, 25, 13, 13,162,162 ; 10 - 17
db 22, 22, 25, 25, 13, 13,164,164 ; 18 - 1f
db 22, 22, 25, 25, 13, 13, 10, 12 ; 20 - 27
db 22, 22, 25, 25, 13, 13, 10, 12 ; 28 - 2f
db 22, 22, 25, 25, 13, 13, 10, 12 ; 30 - 37
db 22, 22, 25, 25, 13, 13, 10, 12 ; 38 - 3f
db 55, 55, 55, 55, 55, 55, 55, 55 ; 40 - 47
db 55, 55, 55, 55, 55, 55, 55, 55 ; 48 - 4f
db 55, 55, 55, 55, 55, 55, 55, 55 ; 50 - 57
db 55, 55, 55, 55, 55, 55, 55, 55 ; 58 - 5f
db 12, 12, 31, 28, 10, 10, 10, 10 ; 60 - 67
db 170, 97,173, 89, 12, 12, 12, 12 ; 68 - 6f
db 115,115,115,115,115,115,115,115 ; 70 - 77
db 115,115,115,115,115,115,115,115 ; 78 - 7f
db 4, 4, 0, 4, 22, 22, 25, 25 ; 80 - 87
db 22, 22, 25, 25,124, 31,127, 4 ; 88 - 8f
db 12,197,197,197,197,197,197,197 ; 90 - 97
db 12, 12, 47, 12, 12, 12, 12, 12 ; 98 - 9f
db 130,130,133,133, 12, 12, 12, 12 ; a0 - a7
db 13, 13, 12, 12, 12, 12, 12, 12 ; a8 - af
db 136,136,136,136,136,136,136,136 ; b0 - b7
db 139,139,139,139,139,139,139,139 ; b8 - bf
db 4, 4,185, 12, 31, 31, 4, 4 ; c0 - c7
db 57, 12,185, 12,111,113, 12, 12 ; c8 - cf
db 4, 4, 4, 4,113,113, 0, 12 ; d0 - d7
db 6, 6, 6, 6, 6, 6, 6, 6 ; d8 - df
db 117,117,117,115,105,105,150,150 ; e0 - e7
db 45, 45, 47,115,108,108,153,153 ; e8 - ef
db 10, 0, 10, 10, 12, 12, 4, 4 ; f0 - f7
db 12, 12, 12, 12, 12, 12, 4, 4 ; f8 - ff
db 16, 16, 16, 16, 16, 16, 16, 16 ; 100 - 107 (Intel group 1)
db 19, 19, 19, 19, 19, 19, 19, 19 ; 108 - 10f
db 176,176,176,176,176,176, 0,176 ; 110 - 117 (Intel group 2)
db 179,179,179,179,179,179, 0,179 ; 118 - 11f
db 182,182,182,182,182,182, 0,182 ; 120 - 127 (Intel group 2a)
db 16, 0, 53, 53, 53, 53, 53, 53 ; 128 - 12f (Intel group 3)
db 53, 53,120, 49,120, 49,120, 0 ; 130 - 137 (Intel group 5)
db 120,122,122,122,122,122, 0, 0 ; 138 - 13f (Intel group 6)
db 85, 85, 85, 85,122, 0,122, 85 ; 140 - 147 (Intel group 7)
db 60, 60, 60, 60, 60, 60, 60, 60 ; 148 - 14f (Coprocessor d8)
db 64, 64, 82, 82, 64, 64, 64, 64 ; 150 - 157
db 60, 0, 60, 60, 85, 76, 85, 76 ; 158 - 15f (Coprocessor d9)
db 80, 82, 8, 0, 8, 8, 8, 8 ; 160 - 167
db 74, 74, 74, 74, 74, 74, 74, 74 ; 168 - 16f (Coprocessor da)
db 64, 64, 64, 64, 0, 8, 0, 0 ; 170 - 177
db 74, 0, 74, 74, 0, 78, 0, 78 ; 178 - 17f (Coprocessor db)
db 64, 64, 64, 64, 8, 82, 82, 0 ; 180 - 187
db 62, 62, 62, 62, 62, 62, 62, 62 ; 188 - 18f (Coprocessor dc)
db 67, 67, 0, 0, 67, 67, 67, 67 ; 190 - 197
db 62, 0, 62, 62, 85, 0, 85, 76 ; 198 - 19f (Coprocessor dd)
db 80, 0, 80, 80, 82, 82, 0, 0 ; 1a0 - 1a7
db 76, 76, 76, 76, 76, 76, 76, 76 ; 1a8 - 1af (Coprocessor de)
db 70, 70, 0, 8, 70, 70, 70, 70 ; 1b0 - 1b7
db 76, 0, 76, 76, 78, 51, 78, 51 ; 1b8 - 1bf (Coprocessor df)
db 0, 0, 0, 0, 8, 82, 82, 0 ; 1c0 - 1c7
db 12, 12, 12, 12, 12, 12, 12, 0 ; 1c8 - 1cf (Coprocessor groups)
db 12, 12, 12, 12, 12, 12, 12, 12 ; 1d0 - 1d7
db 12, 12, 12, 12, 12, 12, 12, 12 ; 1d8 - 1df
; The rest of these are squeezed.
db 0, 4, 4, 34, 34, 12, 12, 12
db 203,209,206,212,215,218, 12, 12
db 34, 34, 34, 34, 34, 34, 34, 34
db 34, 34, 34, 34, 34, 34, 34, 34
db 45, 45, 45, 45, 45, 45, 45, 45
db 45, 45, 45, 45, 45, 45, 45, 45
db 187,187,187,187,187,187,187,187
db 187,187,187,187,187,187,187,187
db 166,166, 12, 39,189,193,168,168
db 12, 39,189,193, 34, 22, 22, 31
db 39, 31, 31,142,146, 4, 39, 34
db 34,142,146, 22, 22, 4, 37, 37
db 37, 37, 37, 37, 37, 37, 53, 53
db 42, 42, 42, 42, 51,156, 16, 12
db 12, 12, 12, 12, 12, 12, 12, 12
db 12, 12, 12, 87
; And here is the compressed table of additional information.
opinfo dw 00020h,00020h,00020h,00020h,00020h,00020h,00808h,007e4h ; 00
dw 007bbh,007bbh,007bbh,007bbh,007bbh,007bbh,00808h,001e0h ; 08
dw 0001ah,0001ah,0001ah,0001ah,0001ah,0001ah,00808h,007e4h ; 10
dw 0088ch,0088ch,0088ch,0088ch,0088ch,0088ch,00808h,007e4h ; 18
dw 00026h,00026h,00026h,00026h,00026h,00026h,00001h,001eeh ; 20
dw 00a05h,00a05h,00a05h,00a05h,00a05h,00a05h,00101h,001f4h ; 28
dw 00a55h,00a55h,00a55h,00a55h,00a55h,00a55h,00201h,00002h ; 30
dw 001a0h,001a0h,001a0h,001a0h,001a0h,001a0h,00301h,00014h ; 38
dw 005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h,005c2h ; 40
dw 00204h,00204h,00204h,00204h,00204h,00204h,00204h,00204h ; 48
dw 00808h,00808h,00808h,00808h,00808h,00808h,00808h,00808h ; 50
dw 007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h,007e4h ; 58
dw 0180fh,017eah,01033h,0202ch,03401h,03501h,03010h,03020h ; 60
dw 01808h,015b6h,01808h,015b6h,015c8h,015d6h,017cch,017dch ; 68
dw 006ach,00694h,00614h,0060eh,006c7h,006a6h,00619h,00609h ; 70
dw 006c2h,006a0h,006b6h,006bch,00643h,0063dh,00648h,00638h ; 78
dw 00100h,00100h,00000h,00108h,00a0bh,00a0bh,00a3fh,00a3fh ; 80
dw 00775h,00775h,00775h,00775h,00775h,006dfh,00775h,002f8h ; 88
dw 007afh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh,00a3fh ; 90
dw 0006dh,001e1h,00066h,00a20h,00820h,007f9h,00879h,006cch ; 98
dw 00775h,00775h,00775h,00775h,0077bh,0078bh,001a6h,001b6h ; a0
dw 00a0bh,00a0bh,009e7h,009f7h,00722h,00732h,00892h,008a2h ; a8
dw 00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h ; b0
dw 00775h,00775h,00775h,00775h,00775h,00775h,00775h,00775h ; b8
dw 00120h,00120h,0085ah,0085ah,006edh,006d9h,00300h,00300h ; c0
dw 0121ah,016e5h,00860h,00860h,005ddh,005ddh,005e3h,005fah ; c8
dw 00110h,00110h,00118h,00118h,0000eh,00008h,00000h,00a4dh ; d0
dw 00148h,00158h,00168h,00178h,00188h,00198h,001a8h,001b8h ; d8
dw 00752h,0075bh,0073ah,00624h,005bdh,005bdh,007c6h,007c6h ; e0
dw 00066h,0064eh,0064eh,0064eh,005bdh,005bdh,007c6h,007c6h ; e8
dw 00008h,00000h,00002h,00006h,005a9h,00092h,00128h,00128h ; f0
dw 00079h,009d5h,00085h,009e1h,0007fh,009dbh,002e0h,00130h ; f8
dw 00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h ; 100
dw 00020h,007bbh,0001ah,0088ch,00026h,00a05h,00a55h,001a0h ; 108
dw 00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h ; 110
dw 00867h,0086dh,00831h,00837h,009a1h,009aeh,00000h,00886h ; 118
dw 01867h,0186dh,01831h,01837h,019a1h,019aeh,00000h,01886h ; 120
dw 00a0bh,00000h,007b5h,007a9h,007a3h,005b6h,0020ah,005afh ; 128
dw 005c2h,00204h,00066h,00066h,0064eh,0064eh,00808h,00000h ; 130
dw 029c2h,029ffh,0270dh,0276fh,02a12h,02a19h,00000h,00000h ; 138
dw 0299ah,029bbh,026f9h,02706h,029c9h,00000h,02714h,045f1h ; 140
dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 148
dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 150
dw 003c8h,00000h,004f7h,0050eh,003ddh,0044bh,00477h,0046eh ; 158
dw 003c8h,00581h,00308h,00000h,00310h,001c8h,001d0h,001d8h ; 160
dw 0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh ; 168
dw 06276h,06289h,0627fh,062dah,00000h,00318h,00000h,00000h ; 170
dw 00387h,00000h,003a8h,003afh,00000h,003c8h,00000h,0050eh ; 178
dw 062a7h,062bch,062b1h,062c6h,00320h,0654ch,062f3h,00000h ; 180
dw 00236h,00419h,002ech,00304h,0051dh,0052ch,0032eh,0033dh ; 188
dw 00236h,00419h,00000h,00000h,0052ch,0051dh,0033dh,0032eh ; 190
dw 003c8h,00000h,004f7h,0050eh,004b6h,00000h,0045bh,00481h ; 198
dw 00355h,00000h,004f7h,0050eh,03544h,0355fh,00000h,00000h ; 1a0
dw 0035dh,0038eh,00365h,0036dh,003b7h,003bfh,00376h,0037eh ; 1a8
dw 0023dh,00420h,00000h,00328h,00534h,00524h,00345h,00335h ; 1b0
dw 00387h,00000h,003a8h,003afh,00245h,00387h,0024ch,003afh ; 1b8
dw 00000h,00000h,00000h,00000h,00330h,06555h,062fbh,00000h ; 1c0
dw 003ceh,003efh,003e6h,0040ah,003f8h,00401h,00412h,00000h ; 1c8
dw 00227h,00592h,004a4h,0048ah,00588h,0349bh,0031ch,00396h ; 1d0
dw 00493h,0059ah,004efh,034e5h,004ach,004cch,034deh,03315h ; 1d8
; The rest of these are squeezed.
dw 0,00138h,00140h,026d3h,02763h,0208bh,045eah,04a27h
dw 03775h,03775h,03775h,03775h,03775h,03775h,05a30h,0583dh
dw 0616eh,0614ah,060a9h,060a0h,06198h,06165h,060b1h,06098h
dw 06190h,0615ch,0617eh,06187h,060dbh,060d2h,060e3h,060cah
dw 036ach,03694h,03614h,0360eh,036c7h,036a6h,03619h,03609h
dw 036c2h,036a0h,036b6h,036bch,03643h,0363dh,03648h,03638h
dw 0396eh,0394eh,038bfh,038b7h,03993h,03966h,038c6h,038b0h
dw 0398ch,0395eh,0397ch,03984h,038ebh,038e3h,038f2h,038dch
dw 03808h,037e4h,051d4h,0304fh,039a7h,039a7h,03808h,037e4h
dw 05873h,03060h,039b4h,039b4h,035b6h,041beh,041beh,03769h
dw 0305ah,036f3h,03700h,0379bh,0379bh,002e8h,03054h,0303bh
dw 03041h,03793h,03793h,04a38h,04a38h,002f0h,04047h,04047h
dw 04047h,04047h,04047h,04047h,04047h,04047h,005c2h,00204h
dw 0304fh,03060h,0305ah,03054h,051c8h,007e4h,00775h,00454h
dw 00254h,0022fh,0053dh,0057ah,03568h,0043ah,00431h,00428h
dw 00442h,02464h,0030ch,00481h
; This table converts unsqueezed numbers to squeezed.
sqztab db 1, 2, 3, 4, 0, 0, 5, 0
db 6, 7, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 8, 9, 10, 11, 12, 0, 13, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 14, 0, 15, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 16, 17, 18, 19, 20, 21, 22, 23
db 24, 25, 26, 27, 28, 29, 30, 31
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 32, 33, 34, 35, 36, 37, 38, 39
db 40, 41, 42, 43, 44, 45, 46, 47
db 48, 49, 50, 51, 52, 53, 54, 55
db 56, 57, 58, 59, 60, 61, 62, 63
db 64, 65, 66, 67, 68, 69, 0, 0
db 70, 71, 72, 73, 74, 75, 0, 76
db 77, 78, 79, 80, 81, 82, 83, 84
db 0, 0, 85, 86, 87, 88, 89, 90
db 91, 92, 0, 0, 0, 0, 0, 93
db 94, 95, 96, 97, 98, 99,100,101
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 102,103, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0,104,105,106,107
db 0,108, 0, 0, 0, 0, 0, 0
db 109, 0, 0, 0, 0, 0, 0, 0
db 110, 0, 0, 0, 0, 0, 0, 0
db 111, 0, 0, 0, 0, 0, 0, 0
db 112,113, 0, 0,114,115, 0, 0
db 0,116, 0, 0, 0, 0, 0, 0
db 117,118,119,120,121, 0, 0, 0
db 0,122, 0, 0, 0, 0, 0, 0
db 123, 0, 0, 0, 0, 0, 0, 0
; This is the table of mnemonics that change in the presence of a WAIT
; instruction.
wtab1 dw 802, 801, 800, 803, 349, 414, 804, 351
dw 350, 816, 415
wtab2 dw 603, 806, 846, 928, 981, 1220, 1237, 1277
dw 1285, 1301, 1301
N_WTAB equ 11
; This is the table for operands which have a different mnemonic for
; their 32 bit versions.
ltab1 dw 152, 167, 153, 109, 207, 227, 173, 165
dw 111, 97, 157, 96, 156, 175, 171
ltab2 dw 487, 430, 115, 1487, 1537, 1584, 1834, 1923
dw 2004, 2033, 2048, 2071, 2088, 2202, 2543
N_LTAB equ 15
; This is the table of lockable instructions
locktab dw 266, 258, 16, 17, 264, 256, 0, 1
dw 268, 260, 32, 33, 667, 751, 659, 750
dw 651, 749, 656, 657, 737, 305, 736, 304
dw 299, 298, 265, 257, 8, 9, 267, 259
dw 24, 25, 269, 261, 40, 41, 672, 673
dw 134, 135, 270, 262, 48, 49
N_LOCK equ 46
; Equates used in the assembly-language code.
SPARSE_BASE equ 480
SFPGROUP3 equ 800
;-@@-@@-@@-End of auto-generated tables. You may edit below this point.
; debug22 - INT 22 (Program terminate) interrupt handler.
; This is for DEBUG itself: it's a catch-all for the various INT 23
; and INT 24 calls that may occur unpredictably at any time.
; What we do is pretend to be a command interpreter (which we are,
; in a sense, just a different sort of command) by setting the PSP of
; our parent equal to our own PSP so that DOS does not free our memory
; when we quit. Therefore control ends up here when Control-Break or
; an Abort in Abort/Retry/Fail is selected.
debug22:cld ;reestablish things
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
; Begin main command loop.
cmd3: mov word [errret],cmd3
mov sp,[savesp] ;restore stack (this must be first)
mov dx,prompt1
mov cx,1
call getline ;prompted input
cmp al,CR
je cmd3 ;if blank line
cmp al,';'
je cmd3 ;if comment
cmp al,'?'
je help ;if request for help
or al,TOLOWER
sub al,'a'
cmp al,'x'-'a'
ja errorj1 ;if not recognized
cbw
xchg bx,ax
call skipcomma
mov di,line_out
shl bx,1
call [cmdlist+bx]
jmp cmd3 ;back to the top
help: mov dx,helpmsg
prnquit:call int21ah9 ;print string
jmp cmd3 ;done
errorj1:jmp error
; A command - tiny assembler.
asm_mn_flags db 0 ;flags for the mnemonic
AMF_D32 equ 1 ;(order is important for D32/WAIT)
AMF_WAIT equ 2
AMF_A32 equ 4 ;if this is 32 bit addressing
AMF_SIB equ 8 ;there's a SIB in the arguments
AMF_MSEG equ 10h ;if a seg prefix was given b4 mnemonic
AMF_FSGS equ 20h ;if FS or GS was encountered
aa_saved_prefix db 0 ;WAIT or REP... prefix
; aa_saved_prefix and aa_seg_pre must be consecutive.
aa_seg_pre db 0 ;segment prefix
mneminfo dw 0 ;address associated with the mnemonic
; The following (through a_opcode) must all be consecutive.
rmaddr dw 0 ;address of operand giving the R/M byte
regmem db 0 ;mod reg r/m part of instruction
;regmem and sibbyte must be consecutive
sibbyte db 0 ;SIB byte
immaddr dw 0 ;address of operand giving the immed stf
xxaddr dw 0 ;address of additional stuff
dismach db 0 ;type of processor needed
dmflags db 0 ;flags for extra processor features
DM_COPR equ 1 ;math coprocessor
DM_MMX equ 2 ;MMX extensions
opcode_or db 0 ;extra bits in the op code
opsize db 0 ;size of this operation
varflags db 0 ;flags for this variant
VAR_LOCKABLE equ 1 ;variant is lockable
VAR_MODRM equ 2 ;if there's a MOD R/M here
VAR_SIZ_GIVN equ 4 ;if a size was given
VAR_SIZ_FORCD equ 8 ;if only one size is permitted
VAR_SIZ_NEED equ 10h ;if we need the size
VAR_D32 equ 20h ;if there's a 32 bit operand size prefix
a_opcode dw 0 ;op code info for this variant
a_reqsize db 0 ;size that this arg should be
a_opcode2 dw 0 ;copy of a_opcode for obs-instruction
dw 0dbe0h,0dbe1h,0dbe4h,124h,126h ;obs. instruction codes
;(the above must follow a_opcode2)
obsmach db 1,1,2,4,4 ;max permissible machine for the above
aadbsiz db 0,4,2,1 ;table for max size of db operand
aadbsto dw 0,aa28,aa29,aa30;table for routine to store a number
modrmtab db 11,0,13,0,15,0,14,0 ;[bx], [bp], [di], [si]
db 15,13,14,13,15,11,14,11 ;[bp+di],[bp+si],[bx+di],[bx+si]
aam_args db 'a',CR
; Equates for parsed arguments.
ARG_DEREF equ 1 ;non-immediate memory reference
ARG_MODRM equ 2 ;if we've computed the MOD R/M byte
ARG_JUSTREG equ 4 ;a solo register
ARG_WEIRDREG equ 8 ;if it's a segment register or CR, etc.
ARG_IMMED equ 10h ;if it's just a number
ARG_FARADDR equ 20h ;if it's of the form xxxx:yyyyyyyy
; For each operand type in the following table, the first byte is
; the bits, at least one of which must be present; the second is the
; bits all of which must be absent.
bittab db ARG_IMMED ;OP_IMM
db ARG_DEREF+ARG_JUSTREG ;OP_RM
db ARG_DEREF ;OP_M
db ARG_JUSTREG ;OP_R_MOD
db ARG_DEREF ;OP_MOFFS
db ARG_JUSTREG ;OP_R
db ARG_JUSTREG ;OP_R_ADD
db ARG_JUSTREG ;OP_AX
db ARG_DEREF ;OP_M64
db ARG_DEREF ;OP_MFLOAT
db ARG_DEREF ;OP_MDOUBLE
db ARG_DEREF ;OP_M80
db ARG_DEREF ;OP_MXX
db ARG_DEREF ;OP_FARMEM
db ARG_FARADDR ;OP_FARP
db ARG_IMMED ;OP_REL8
db ARG_IMMED ;OP_REL1632
db ARG_WEIRDREG ;OP_1CHK
db ARG_WEIRDREG ;OP_STI
db ARG_WEIRDREG ;OP_CR
db ARG_WEIRDREG ;OP_DR
db ARG_WEIRDREG ;OP_TR
db ARG_WEIRDREG ;OP_SEGREG
db ARG_IMMED ;OP_IMMS8
db ARG_IMMED ;OP_IMM8
db ARG_JUSTREG ;OP_ECX
db 0ffh ;OP_SHOSIZ
db ARG_IMMED ;OP_1
db ARG_IMMED ;OP_3
db ARG_JUSTREG ;OP_DX
db ARG_JUSTREG ;OP_CL
db ARG_WEIRDREG ;OP_ST
db ARG_WEIRDREG ;OP_CS
db ARG_WEIRDREG ;OP_DS
db ARG_WEIRDREG ;OP_ES
db ARG_WEIRDREG ;OP_FS
db ARG_WEIRDREG ;OP_GS
db ARG_WEIRDREG ;OP_SS
; Jump table for operand types.
asm_jmp1 dw ao04,ao01,ao01,ao01 ;OP_IMM, OP_RM, OP_M, OP_R_MOD
dw ao05,ao02,ao03,ao06 ;OP_MOFFS, OP_R, OP_R_ADD, OP_AX
dw ao17,ao17,ao17 ;OP_M64, OP_MFLOAT, OP_MDOUBLE
dw ao17,ao17,ao17 ;OP_M80, OP_MXX, OP_FARMEM
dw ao21,ao23,ao25 ;OP_FARP, OP_REL8, OP_REL1632
dw ao29,ao30,ao31 ;OP_1CHK, OP_STI, OP_CR
dw ao34,ao35,ao39 ;OP_DR, OP_TR, OP_SEGREG
dw ao41,ao42,ao43m ;OP_IMMS8, OP_IMM8, OP_ECX
dw ao44,ao46,ao47 ;OP_SHOSIZ, OP_1, OP_3
dw ao48,ao48,ao48 ;OP_DX, OP_CL, OP_ST
dw ao48,ao48,ao48 ;OP_CS, OP_DS, OP_ES
dw ao48,ao48,ao48 ;OP_FS, OP_GS, OP_SS
asm_regnum db 10,1,30 ;DX, CL, ST
db 25,27,24,28,29,26 ;CS, DS, ES, FS, GS, SS
asm_siznum db 5, 6, 7, 8 ;qword, float, double, tbyte
db -1, 12 ;none, far
aa00: jmp cmd3 ;done with this command
aa: mov word [errret],aa01
cmp al,CR
je aa01 ;if end of line
mov bx,[reg_cs] ;default segment to use
aa00a: call getaddr ;get address into bx:dx
call chkeol ;expect end of line here
mov [a_addr],dx ;save the address
mov [a_addr+2],bx
; Begin loop over input lines.
aa01: mov sp,[savesp] ;restore the stack (this implies no "ret")
mov di,line_out
mov ax,[a_addr+2]
call hexword
mov al,':'
stosb
mov ax,[a_addr]
call hexword
mov al,' '
stosb
call getline00
cmp al,CR
je aa00 ;if done
cmp al,';'
je aa01 ;if comment
mov byte [asm_mn_flags],0
mov word [aa_saved_prefix],0 ;clear aa_saved_prefix and aa_seg_pre
; Get mnemonic and look it up.
aa02: mov di,line_out ;return here after LOCK/REP/SEG prefix
push si ;save position of mnemonic
aa03: cmp al,'a'
jb aa04 ;if not lower case letter
cmp al,'z'
ja aa04
and al,TOUPPER ;convert to upper case
aa04: stosb
lodsb
cmp al,CR
je aa05 ;if end of mnemonic
cmp al,' '
je aa05
cmp al,TAB
jne aa03
aa05: call skipwh0 ;skip to next field
dec si
push si ;save position in input line
mov al,0
stosb
mov bx,mnlist
mov dx,end_mnlist
aa06: mov si,bx ;begin bisection loop looking for mnemonic
add si,dx
rcr si,1
aa07: lodsb ;skip to end of string
cmp al,0
jne aa07 ;if not end of string
cmp si,dx
jb aa09 ;if not end of table
aa08: dec si
cmp si,bx
je aa09 ;if beginning of table
cmp byte [si-1],0
jne aa08
aa09: push si ;compare op codes
inc si ;skip over the data word
inc si
push di
mov cx,line_out
sub di,cx
xchg cx,di
repe cmpsb
pop di
pop si
je aa14 ;if found it
jg aa11 ;if (di) < (si)
aa10: lodsb
cmp al,0
jne aa10 ;skip to end of string
mov bx,si
jmp aa12
aa11: mov dx,si
aa12: cmp bx,dx
jne aa06 ;if more to search
aa13: pop si ;end of mnemonic
aa13a: pop si ;beginning of mnemonic
aa13b: jmp error ;complain
; We found the mnemonic.
aa14: lodsb ;get significant byte of address
mov ah,al ;multiply by 255
neg al
xchg ax,bx
lodsb
mov ah,0
add bx,ax
lea si,[asmtab+bx-512]
; Now si points to the spot in asmtab corresponding to this mnemonic.
; The format of the assembler table is as follows.
; First, there is optionally one of the following bytes:
; ASM_DB db mnemonic
; ASM_DW dw mnemonic
; ASM_DD dd mnemonic
; ASM_WAIT the mnemonic should start with a wait
; instruction.
; ASM_D32 This is a 32 bit instruction.
; ASM_AAX Special for AAM and AAD instructions:
; put 0ah in for a default operand.
; ASM_SEG This is a segment prefix.
; ASM_LOCKREP This is a LOCK or REP... prefix.
;
; Then, in most cases, this is followed by one or more of the following
; sequences, indicating an instruction variant.
; ASM_LOCKABLE (optional) indicates that this instruction can
; follow a LOCK prefix.
; ASM_MACHx Indicates the first machine on which this
; instruction appeared.
; [word] This is a 16-bit integer, most significant byte
; first, giving ASMMOD * a + b, where b is an
; index into the array opindex (indicating the
; key, or type of operand list), and a is as
; follows:
; 0-255 The (one-byte) instruction.
; 256-511 The lower 8 bits give the second byte of
; a two-byte instruction beginning with 0fh.
; 512-575 Bits 2-0 say which floating point instruction
; this is (0d8h-0dfh), and 5-3 give the /r
; field.
; 576-... (a-576)/8 is the index in the array agroups
; (which gives the real value of a), and the
; low-order 3 bits gives the /r field.
;
; [byte] This gives the second byte of a floating
; instruction if 0d8h <= a <= 0dfh.
;
; Following these is an ASM_END byte.
;
; Exceptions:
; ASM_SEG and ASM_LOCKREP are followed by just one byte, the
; prefix byte.
; ASM_DB, ASM_DW, and ASM_DD don't need to be followed by
; anything.
;
ASM_END equ 0ffh
ASM_DB equ 0feh
ASM_DW equ 0fdh
ASM_DD equ 0fch
ASM_ORG equ 0fbh
ASM_WAIT equ 0fah
ASM_D32 equ 0f9h
ASM_AAX equ 0f8h
ASM_SEG equ 0f7h
ASM_LOCKREP equ 0f6h
ASM_LOCKABLE equ 0f5h
ASM_MACH6 equ 0f4h
ASM_MACH0 equ 0eeh
cmp byte [si],ASM_LOCKREP ;check for mnemonic flag byte
jb aa15 ;if none
lodsb ;get the prefix
sub al,ASM_LOCKREP
je aa18 ;if LOCK or REP...
cbw
dec ax
jz aa17 ;if segment prefix
dec ax
jz aa16 ;if aad or aam
cmp al,3
jae aa20 ;if ASM_ORG or ASM_DD or ASM_DW or ASM_DB
or [asm_mn_flags],al ;save AMF_D32 or AMF_WAIT
aa15: jmp ab01 ;now process the arguments
aa16: jmp ab00
; segment prefix
aa17: lodsb ;get prefix value
mov [aa_seg_pre],al
or byte [asm_mn_flags],AMF_MSEG
pop si
pop ax
lodsb
cmp al,CR
je aa13a ;if end of line ( ==> error)
cmp al,';'
je aa13a ;if end of line (comment) ( ==> error)
jmp aa02 ;back for more
; LOCK or REP prefix
aa18: lodsb ;get prefix value
xchg al,[aa_saved_prefix]
cmp al,0
jnz aa13a ;if there already was a saved prefix
pop si
pop ax
lodsb
cmp al,CR
je aa19 ;if end of line
cmp al,';'
je aa19 ;if end of line (comment)
jmp aa02 ;back for more
aa19: mov al,[aa_saved_prefix] ;just a prefix, nothing else
mov di,line_out
stosb
jmp aa27
; Pseudo ops (org or db/dw/dd).
aa20: cmp word [aa_saved_prefix],0
jnz aa13a ;if there was a prefix or a segment
pop si ;get position in input line
sub al,3 ;AX=0 if org, 1 if dd, 2 if dw, 3 if db.
jnz aa20m ;if not ORG
; Process ORG pseudo op.
call skipwhite
cmp al,CR
je aa20a ;if nothing
mov bx,[a_addr+2] ;default segment
jmp aa00a ;go to top
aa20a: jmp aa01 ;get next line
; Data instructions (DB/DW/DD).
aa20m: mov di,line_out ;put the bytes here when we get them
xchg ax,bx ;mov bx,ax
mov al,[aadbsiz+bx] ;move maximum size
mov [aadbsiz],al
shl bx,1
mov ax,[aadbsto+bx] ;move address of storage routine
mov [aadbsto],ax
call skipwhite
cmp al,CR
je aa27 ;if end of line
aa21: cmp al,'"'
je aa22 ;if string
cmp al,"'"
je aa22 ;if string
call aageti ;get a numerical value into dx:bx, size into cl
cmp cl,[aadbsiz]
jg aa24 ;if overflow
xchg ax,bx
call [aadbsto] ;store the value
cmp di,real_end
ja aa24 ;if output line overflow
xchg ax,bx
jmp aa26 ;done with this one
aa22: mov ah,al
aa23: lodsb
cmp al,CR
je aa24 ;if end of line
cmp al,ah
je aa25 ;if end of string
stosb
cmp di,real_end
jbe aa23 ;if output line not overflowing
aa24: jmp aa13b ;error
aa25: lodsb
aa26: call skipcomm0
cmp al,CR
jne aa21 ;if not end of line
; End of line. Copy it over.
aa27: mov si,line_out
mov cx,di
sub cx,si
les di,[a_addr]
rep movsb ;copy it
push ds ;restore es
pop es
mov [a_addr],di
jmp aa01
; Routines to store a byte/word/dword.
aa28: stosw ;store a dword value
xchg ax,dx
stosw
xchg ax,dx
ret
aa29: stosw ;store a word value
ret
aa30: stosb ;store a byte value
ret
; Here we process the AAD and AAM instructions. They are special
; in that they may take a one-byte argument, or none (in which case
; the argument defaults to 0ah = ten).
ab00: mov [mneminfo],si ;save this address
pop si
lodsb
cmp al,CR
je ab00a ;if end of line
cmp al,';'
jne ab01b ;if not end of line
ab00a: mov si,aam_args ;fake a 0ah argument
jmp ab01a
; Process normal instructions.
; First we parse each argument into a 12-byte data block, stored
; consecutively at line_out, line_out+12, etc.
; This is stored as follows.
; [di] Flags (ARG_DEREF, etc.)
; [di+1] Unused
; [di+2] Size argument, if any (1=byte, 2=word, 3=(unused), 4=dword,
; 5=qword, 6=float, 7=double, 8=tbyte, 9=short, 10=long, 11=near,
; 12=far).
; [di+3] Size of MOD R/M displacement
; [di+4] First register, or MOD R/M byte
; [di+5] Second register or index register or SIB byte
; [di+6] Index factor
; [di+7] Sizes of numbers are or-ed here
; [di+8] (dword) number
; For arguments of the form xxxx:yyyyyyyy, xxxx is stored in [di+5],
; and yyyyyyyy in [di+8]. The number of bytes in yyyyyyyy is stored in
; opaddr, 2 is stored in [di+4], and di is stored in xxaddr.
ab01: mov [mneminfo],si ;save this address
pop si ;get position in line
ab01a: lodsb
ab01b: mov di,line_out
; Begin loop over operands.
ab02: cmp al,CR
je ab03 ;if end of line
cmp al,';'
jne ab04 ;if not end of line
ab03: jmp ab99 ;to next phase
ab04: push di ;clear out the next storage area
mov cx,6
xor ax,ax
rep stosw
pop di
; Small loop over "BYTE PTR" and segment prefixes.
ab05: dec si
mov ax,[si]
and ax,TOUPPER_W
cmp byte [di+2],0
jne ab07 ;if already have "BYTE PTR"
push di
mov di,sizetcnam
mov cx,12
repne scasw
pop di
jne ab07 ;if not found
or cx,cx
jnz ab06 ;if not 'FA'
mov al,[si+2]
and al,TOUPPER
cmp al,'R'
jne ab09 ;if not 'FAR' (could be hexadecimal)
ab06: sub cl,12
neg cl ;convert to 1, ..., 12
mov [di+2],cl
call skipalpha
call skipwh0
mov ah,[si]
and ax,TOUPPER_W
cmp ax,'FA'
jne ab06a ;if not 'FA'
mov al,[si+1]
and al,TOUPPER
cmp al,'R'
jne ab05 ;if not 'FAR'
mov byte [di+2],12 ;set 'FAR'
or byte [asm_mn_flags],AMF_D32
call skipalpha
call skipwh0
mov ah,[si]
and ax,TOUPPER_W
ab06a: cmp ax,'PT'
jne ab05 ;if not 'PTR'
call skipalpha
call skipwh0
jmp ab05
ab07: cmp byte [aa_seg_pre],0
jne ab09 ;if we already have a segment prefix
push di
mov di,segrgnam
mov cx,6
repne scasw
pop di
jne ab09 ;if not found
push si ;save si in case there's no colon
lodsw
call skipwhite
cmp al,':'
jne ab08 ;if not followed by ':'
pop ax ;discard saved si
call skipwhite ;skip it
mov bx,prefixlist + 5
sub bx,cx
mov al,[bx] ;look up the prefix byte
mov [aa_seg_pre],al ;save it away
jmp ab05
ab08: pop si
; Begin parsing main part of argument.
ab09: push di ;check for solo registers
mov di,rgnam816
mov cx,27
call aagetreg
pop di
jc ab14 ;if not a register
or byte [di],ARG_JUSTREG
mov [di+4],bl ;save register number
cmp bl,24
jae ab09a ;if it's not a normal register
xchg ax,bx ;mov al,bl
mov cl,3
shr al,cl ;al = size: 0 -> byte, 1 -> word, 2 -> dword
add al,-2
adc al,3 ;convert to 1, 2, 4 (respectively)
jmp ab13
ab09a: xor byte [di],ARG_JUSTREG + ARG_WEIRDREG
mov al,2 ;register size
cmp bl,30
ja ab11 ;if it's CR, DR, TR, or MM
je ab09b ;if it's ST
cmp bl,28
jb ab13 ;if it's a normal segment register
or byte [asm_mn_flags],AMF_FSGS ;flag it
jmp ab13
ab09b: cmp byte [si],'('
jne ab12 ;if just plain ST
lodsb
lodsb
sub al,'0'
cmp al,7
ja ab10 ;if not 0..7
mov [di+5],al ;save the number
lodsb
cmp al,')'
je ab12 ;if not error
ab10: jmp aa13b ;error
ab11: lodsb ;other registers (CR, DR, TR, MM)
sub al,'0'
cmp al,7
ja ab10 ;if error
mov [di+5],al ;save the number
mov al,4 ;register size
cmp bl,31
jne ab13 ;if not MM register
ab12: mov al,0
ab13: cmp al,[di+2] ;compare with stated size
je ab13a ;if same
xchg al,[di+2]
cmp al,0
jne ab10 ;if wrong size given
ab13a: jmp ab44 ;done with this operand
; It's not a register reference. Try for a number.
ab14: lodsb
call aaifnum
jc ab17 ;it's not a number
ab14a: call aageti ;get the number
mov [di+7],cl
mov [di+8],bx
mov [di+10],dx
call skipwh0
cmp cl,2
jg ab17 ;if we can't have a colon here
cmp al,':'
jne ab17 ;if not xxxx:yyyy
call skipwhite
call aageti
mov cx,[di+8]
mov [di+5],cx
mov [di+8],bx
mov [di+10],dx
or byte [di],ARG_FARADDR
jmp ab43 ;done with this operand
; Check for [...].
ab15: jmp ab30 ;do post-processing
ab16: call skipwhite
ab17: cmp al,'[' ;begin loop over sets of []
jne ab15 ;if not [
or byte [di],ARG_DEREF ;set the flag
ab18: call skipwhite
ab19: cmp al,']' ;begin loop within []
je ab16 ;if done
; Check for a register (within []).
dec si
push di
mov di,rgnam16
mov cx,8
call aagetreg
pop di
jc ab25 ;if not a register
cmp bl,16
jae ab20 ;if 32-bit register
add bl,8 ;adjust 0..7 to 8..15
jmp ab21
ab20: cmp byte [di+5],0
jnz ab21 ;if we already have an index
call skipwhite
dec si
cmp al,'*'
jne ab21 ;if not followed by '*'
inc si
mov [di+5],bl ;save index register
call skipwhite
call aageti
call aaconvindex
jmp ab28 ;ready for next part
ab21: cmp byte [di+4],0
jne ab22 ;if there's already a register
mov byte [di+4],bl
jmp ab23
ab22: cmp byte [di+5],0
jne ab24 ;if too many registers
mov byte [di+5],bl
ab23: call skipwhite
jmp ab28 ;ready for next part
ab24: jmp aa13b ;error
; Try for a number (within []).
ab25: lodsb
ab26: call aageti ;get a number (or flag an error)
call skipwh0
cmp al,'*'
je ab27 ;if it's an index factor
or [di+7],cl
add [di+8],bx
adc [di+10],dx
jmp ab28 ;next part ...
ab27: call aaconvindex
call skipwhite
dec si
push di
mov di,rgnam16
xor cx,cx
call aagetreg
pop di
jc ab24 ;if error
cmp byte [di+5],0
jne ab24 ;if there is already a register
mov [di+5],bl
call skipwhite
; Ready for the next term within [].
ab28: cmp al,'-'
je ab26 ;if a (negative) number is next
cmp al,'+'
jne ab29 ;if no next term (presumably)
jmp ab18
ab29: jmp ab19 ;back for more
; Post-processing for complicated arguments.
ab30: cmp word [di+4],0
jnz ab32 ;if registers were given ( ==> create MOD R/M)
cmp byte [di+7],0
jz ab31 ;if nothing was given ( ==> error)
cmp byte [di],0
jnz ab30b ;if it was not immediate
or byte [di],ARG_IMMED
ab30a: jmp ab43 ;done with this argument
ab30b: mov al,2 ;size of the displacement
test byte [di+7],4
jz ab30c ;if not 32-bit displacement
inc ax
inc ax
or byte [asm_mn_flags],AMF_A32 ;32-bit addressing
ab30c: mov byte [di+3],al ;save displacement size
jmp ab30a ;done with this argument
ab31: jmp aa13b ;flag an error
; Create the MOD R/M byte.
; (For disp-only or register, this will be done later as needed.)
ab32: or byte [di],ARG_MODRM
mov al,[di+4]
or al,[di+5]
test al,16
jnz ab34 ;if 32-bit addressing
test byte [di+7],4
jnz ab34 ;if 32-bit addressing
mov ax,[di+4]
cmp al,ah
ja ab33 ;make sure al >= ah
xchg al,ah
ab33: push di
mov di,modrmtab
mov cx,8
repne scasw
pop di
jne ab31 ;if not among the possibilities
mov bx,206h ;max disp = 2 bytes; 6 ==> (non-existent) [bp]
jmp ab39 ;done (just about)
ab34: or byte [asm_mn_flags],AMF_A32 ;32-bit addressing
mov al,[di+4]
or al,[di+6]
jnz ab35 ;if we can't optimize [EXX*1] to [EXX]
mov ax,[di+4]
xchg al,ah
mov [di+4],ax
ab35: mov bx,405h ;max disp = 4 bytes; 5 ==> (non-existent) [bp]
cmp byte [di+5],0
jne ab36 ;if there's a SIB
mov cl,[di+4]
cmp cl,16
jl ab31 ;if wrong register type
and cl,7
cmp cl,4 ;check for ESP
jne ab39 ;if not, then we're done (otherwise do SIB)
ab36: or byte [asm_mn_flags],AMF_SIB ;form SIB
mov ch,[di+6] ;get SS bits
mov cl,3
shl ch,cl ;shift them halfway into place
mov al,[di+5] ;index register
cmp al,20
je ab31 ;if ESP ( ==> error)
cmp al,0
jne ab37 ;if not zero
mov al,20 ;set it for index byte 4
ab37: cmp al,16
jl ab31 ;if wrong register type
and al,7
or ch,al ;put it into the SIB
shl ch,cl ;shift it into place
inc cx ;R/M for SIB = 4
mov al,[di+4] ;now get the low 3 bits
cmp al,0
jne ab38 ;if there was a first register
or ch,5
jmp ab42 ;MOD = 0, disp is 4 bytes
ab38: cmp al,16
jl ab45 ;if wrong register type
and al,7 ;first register
or ch,al ;put it into the SIB
cmp al,5
je ab40 ;if it's EBP, then we don't recognize disp=0
;otherwise bl will be set to 0
; Find the size of the displacement.
ab39: cmp cl,bl
je ab40 ;if it's [(E)BP], then disp=0 is still 1 byte
mov bl,0 ;allow 0-byte disp
ab40: push cx
mov al,[di+8]
mov cl,7
sar al,cl
pop cx
mov ah,[di+9]
cmp al,ah
jne ab41 ;if it's bigger than 1 byte
cmp ax,[di+10]
jne ab41 ;ditto
mov bh,0 ;no displacement
or bl,[di+8]
jz ab42 ;if disp = 0 and it's not (E)BP
inc bh ;disp = 1 byte
or cl,40h ;set MOD = 1
jmp ab42 ;done
ab41: or cl,80h ;set MOD = 2
ab42: mov [di+3],bh ;store displacement size
mov [di+4],cx ;store MOD R/M and maybe SIB
; Finish up with the operand.
ab43: dec si
ab44: call skipwhite
add di,12
cmp al,CR
je ab99 ;if end of line
cmp al,';'
je ab99 ;if comment (ditto)
cmp al,','
jne ab45 ;if not comma ( ==> error)
cmp di,line_out+36
jae ab45 ;if too many operands
call skipwhite
jmp ab02
ab45: jmp aa13b ;error jump
ab99: mov byte [di],-1 ;end of parsing phase
push si ;save the location of the end of the string
; For the next phase, we match the parsed arguments with the set of
; permissible argument lists for the opcode. The first match wins.
; Therefore the argument lists should be ordered such that the
; cheaper ones come first.
; There is a tricky issue regarding sizes of memory references.
; Here are the rules:
; 1. If a memory reference is given with a size, then it's OK.
; 2. If a memory reference is given without a size, but some
; other argument is a register (which implies a size),
; then the memory reference inherits that size.
; Exceptions: OP_CL does not imply a size
; OP_SHOSIZ
; 3. If 1 and 2 do not apply, but this is the last possible argument
; list, and if the argument list requires a particular size, then
; that size is used.
; 4. In all other cases, flag an error.
ac01: xor ax,ax ;zero out rmaddr through varflags or a_opcode
mov di,rmaddr
mov cx,7
rep stosw
mov si,[mneminfo] ;address of the next argument variant
; Sort out initial bytes. At this point:
; si = address of next argument variant
; di = address of next parsed argument table
ac02: lodsb
sub al,ASM_MACH0
jb ac05 ;if no more special bytes
cmp al,ASM_LOCKABLE-ASM_MACH0
je ac03 ;if ASM_LOCKABLE
ja ac04 ;if ASM_END ( ==> error)
mov byte [dismach],al ;save machine type
jmp ac02 ;back for next byte
ac03: or byte [varflags],VAR_LOCKABLE
jmp ac02 ;back for next byte
ac04: jmp aa13a ;error
; Get and unpack the word.
ac05: dec si
lodsw
xchg al,ah ;put into little-endian order
xor dx,dx
mov bx,ASMMOD
div bx ;ax = a_opcode; dx = index into opindex
mov [a_opcode],ax ;save ax
mov [a_opcode2],ax ;save the second copy
cmp ax,0dfh
ja ac05a ;if not coprocessor instruction
cmp al,0d8h
jb ac05a ;ditto
or byte [dmflags],DM_COPR ;flag it as an x87 instruction
mov ah,al ;ah = low order byte of opcode
lodsb ;get extra byte
mov [regmem],al ;save it in regmem
mov [a_opcode2],ax ;save this for obsolete-instruction detection
or byte [varflags],VAR_MODRM ;flag its presence
ac05a: mov [mneminfo],si ;save si back again
mov si,dx
mov bl,[opindex+si]
lea si,[oplists+bx] ;si = the address of our operand list
mov di,line_out
; Begin loop over operands. At this point si and di are as for ac02.
ac06: lodsb ;get next operand byte
cmp al,0
je ac10 ;if end of list
cmp byte [di],-1
je ac01 ;if too few operands were given
cmp al,OP_SIZE
jb ac07 ;if no size needed
mov ah,0
mov cl,4
shl ax,cl
shr al,cl
mov [a_reqsize],ah ;save it away
jmp ac08
ac07: add al,16-2 ;move these to the end of the previous list
ac08: cbw
xchg ax,bx ;now bx contains the offset
mov cx,[asm_jmp1+bx] ;subroutine address
shr bx,1
mov al,[bittab+bx]
test al,[di]
jz ac09 ;if no required bits are present
call cx ;call its specific routine
cmp word [si-1],(OP_1632+OP_R)*256+(OP_1632+OP_R_MOD)
je ac06 ;(hack) for IMUL instruction
add di,12 ;next operand
jmp ac06 ;back for more
ac09: jmp ac01 ;back to next possibility
; End of operand list.
ac10: cmp byte [di],-1
jne ac09 ;if too many operands were given
; Final check on sizes
mov al,[varflags]
test al,VAR_SIZ_NEED
jz ac12 ;if no size needed
test al,VAR_SIZ_GIVN
jnz ac12 ;if a size was given
test al,VAR_SIZ_FORCD
jz ac09 ;if the size was not forced ( ==> reject)
mov si,[mneminfo]
cmp byte [si],ASM_END
je ac12 ;if this is the last one
ac11: jmp aa13a ;it was not ==> error (not a retry)
; Check other prefixes.
ac12: mov al,[aa_saved_prefix]
cmp al,0
jz ac14 ;if no saved prefixes to check
cmp al,0f0h
jne ac13 ;if it's a rep prefix
test byte [varflags],VAR_LOCKABLE
jz ac11 ;if this variant is not lockable ( ==> error)
jmp ac14 ;done
ac13: mov ax,[a_opcode] ;check if opcode is OK for rep{,z,nz}
and al,~1 ;clear low order bit
cmp ax,0ffh
ja ac11 ;if it's not a 1 byte instruction
mov di,replist ;list of instructions that go with rep
mov cx,7
repne scasb
jnz ac11 ;if it's not among them
ac14: test byte [asm_mn_flags],AMF_MSEG
jz ac15 ;if no segment prefix before mnemonic
mov ax,[a_opcode] ;check if opcode allows this
cmp ax,0ffh
ja ac11 ;if it's not a 1 byte instruction
mov di,prfxtab
mov cx,P_LEN
repne scasb
jnz ac11 ;if it's not in the list
ac15: mov bx,[immaddr]
or bx,bx
jz ac16 ;if no immediate data
mov al,[opsize]
neg al
shl al,1
test al,[bx+7]
jnz ac11 ;if the immediate data was too big
; Put the instruction together
; (maybe is this why they call it an assembler)
; First, the prefixes (including preceding WAIT instruction)
ac16: les di,[a_addr]
test byte [asm_mn_flags],AMF_WAIT
jz ac17 ;if no wait instruction beforehand
mov al,9bh
stosb
ac17: mov al,[aa_saved_prefix]
cmp al,0
jz ac18 ;if no LOCK or REP prefix
stosb
ac18: mov al,67h ;address-size prefix
test byte [asm_mn_flags],AMF_A32
jz ac19 ;if none
stosb
ac19: dec ax ;al = 66h, operand-size prefix
test byte [asm_mn_flags],AMF_D32
jnz ac20 ;if flag set for 32-bit operands
test byte [varflags],VAR_D32
jz ac21 ;if no flag on instruction variant
ac20: stosb ;store operand-size prefix
ac21: mov al,[aa_seg_pre]
cmp al,0
jz ac22 ;if no segment prefix
stosb
cmp al,64h
jb ac22 ;if not 64 or 65 (FS or GS)
or byte [asm_mn_flags],AMF_FSGS ;flag it
; Now emit the instruction itself.
ac22: mov ax,[a_opcode]
mov bx,ax
sub bx,576
jae ac23 ;if 576-...
cmp ax,512
jb ac24 ;if regular instruction
or byte [dmflags],DM_COPR ;flag it as an x87 instruction
and al,038h ;get register part
or [regmem],al
xchg ax,bx ;mov ax,bx (the low bits of bx are good)
and al,7
or al,0d8h
jmp ac25 ;on to decoding the instruction
ac23: mov cl,3 ;one instruction of a group
shr bx,cl
and al,7
shl al,cl
or [regmem],al
shl bx,1
mov ax,[agroups+bx] ;get actual opcode
ac24: cmp ah,0
jz ac25 ;if no 0fh first
push ax ;store a 0fh
mov al,0fh
stosb
pop ax
ac25: or al,[opcode_or] ;put additional bits into the op code
stosb ;store the op code itself
; Now store the extra stuff that comes with the instruction.
mov ax,word [regmem]
test byte [varflags],VAR_MODRM
jz ac26 ;if no mod reg/mem
stosb
test byte [asm_mn_flags],AMF_SIB
jz ac26 ;if no SIB
dec di
stosw ;store the MOD R/M and SIB, too
ac26: mov bx,[rmaddr]
or bx,bx
jz ac27 ;if no offset associated with the R/M
mov cl,[bx+3]
mov ch,0
lea si,[bx+8]
rep movsb ;store the R/M offset (or memory offset)
; Now store immediate data
ac27: mov bx,[immaddr]
or bx,bx
jz ac28 ;if no immediate data
mov al,[opsize]
cbw
xchg ax,cx ;mov cx,ax
lea si,[bx+8]
rep movsb
; Now store additional bytes (needed for, e.g., enter instruction)
ac28: mov bx,[xxaddr]
or bx,bx
jz ac29 ;if no additional data
lea si,[bx+4]
lodsb
cbw
xchg ax,cx ;mov cx,ax
rep movsb
; Done emitting.
ac29: push cs ;restore ES
pop es
mov [a_addr],di
; Compute machine type.
cmp byte [dismach],3
jae ac31 ;if we already know a 386 is needed
test byte [asm_mn_flags],AMF_D32 | AMF_A32 | AMF_FSGS
jnz ac30 ;if 386
test byte [varflags],VAR_D32
jz ac31 ;if not 386
ac30: mov byte [dismach],3
ac31: mov di,a_opcode2+2 ;info on this instruction
call showmach ;get machine message into si, length into cx
jcxz ac33 ;if no message
ac32: mov di,line_out
rep movsb ;copy the line to line_out
call putsline
ac33: jmp aa01 ;back for the next input line
; ||| This is debugging code. It assumes that the original value
; of a_addr is on the top of the stack.
; pop si ;get orig. a_addr
; mov ax,[a_addr+2]
; mov [u_addr],si
; mov [u_addr+2],ax
; mov bx,[a_addr]
; sub bx,si
; mov di,line_out
; mov cx,10
; mov al,' '
; rep stosb
; mov ds,[a_addr+2]
;ax1: lodsb
; call hexbyte ;display the bytes generated
; dec bx
; jnz ax1
; push cs
; pop ds
; call putsline
; mov byte disflags,0
; call disasm ;disassemble the new instruction
; jmp aa01 ;back to next input line
; Routines to check for specific operand types.
; Upon success, the routine returns.
; Upon failure, it pops the return address and jumps to ac01.
; The routines must preserve si and di.
; OP_RM and OP_M: form MOD R/M byte.
ao01: call ao90 ;form reg/mem byte
jmp ao07 ;go to the size check
; OP_R: register.
ao02: mov al,[di+4] ;register number
and al,7
mov cl,3
shl al,cl ;shift it into place
or [regmem],al ;put it into the reg/mem byte
jmp ao07 ;go to the size check
; OP_R_ADD: register, added to the instruction.
ao03: mov al,[di+4]
and al,7
mov [opcode_or],al ;put it there
jmp ao07 ;go to the size check
; OP_IMM: immediate data.
ao04: mov [immaddr],di ;save the location of this
jmp ao07 ;go to the size check
; OP_MOFFS: just the memory offset
ao05: test byte [di],ARG_MODRM
jnz ao11 ;if MOD R/M byte ( ==> reject)
mov [rmaddr],di ;save the pointer
jmp ao07 ;go to the size check
; OP_AX: check for AL/AX/EAX
ao06: test byte [di+4],7
jnz ao11 ;if wrong register
;jmp ao07 ;go to the size check
; Size check
ao07: or byte [varflags],VAR_SIZ_NEED
mov al,[a_reqsize]
sub al,5 ;OP_1632 >> 4
jl ao12 ;if OP_ALL
jz ao13 ;if OP_1632
add al,-3
adc al,3 ;convert 3 --> 4
ao08: or byte [varflags],VAR_SIZ_FORCD + VAR_SIZ_NEED
mov bl,[di+2]
or bl,bl
jz ao09 ;if no size given
or byte [varflags],VAR_SIZ_GIVN
cmp al,bl
jne ao11 ;if sizes conflict
ao09: cmp al,[opsize]
je ao10 ;if sizes agree
xchg al,[opsize]
cmp al,0
jnz ao11 ;if sizes disagree
ao10: ret
ao11: jmp ao50 ;reject
; OP_ALL - Allow all sizes.
ao12: mov al,[di+2]
cmp al,1
je ao15 ;if byte
jb ao14 ;if unknown
or byte [opcode_or],1 ;set bit in instruction
jmp ao14 ;if size is 16 or 32
; OP_1632 - word or dword.
ao13: mov al,[di+2]
ao14: cmp al,0
je ao16 ;if still unknown
cmp al,2
je ao15 ;if word
cmp al,4
jne ao11 ;if not dword
or byte [varflags],VAR_D32 ;set flag
ao15: mov [opsize],al
or byte [varflags],VAR_SIZ_GIVN
ao16: ret
; OP_M64 - 64-bit memory reference.
; OP_MFLOAT - single-precision floating point memory reference.
; OP_MDOUBLE - double-precision floating point memory reference.
; OP_M80 - 80-bit memory reference.
; OP_MXX - memory reference, size unknown.
; OP_FARMEM - far memory pointer
ao17: call ao90 ;form reg/mem byte
mov al,[asm_siznum+bx-(OP_M64+16-2)/2]
jmp ao08 ;check size
; OP_FARP - far memory address contained in instruction
ao21: mov al,2
cmp word [di+10],0
jz ao22 ;if 16 bit address
or byte [varflags],VAR_D32
mov al,4
ao22: mov byte [di+4],2
mov [immaddr],di
mov [opsize],al
ao22a: mov [xxaddr],di
ret
; OP_REL8 - relative address
ao23: mov al,9 ;short
call ao60 ;check the size
mov ax,[a_addr] ;offset
inc ax
inc ax ;$
test byte [asm_mn_flags],AMF_D32
jnz ao23a ;if JECXZ
test byte [varflags],VAR_D32
jz ao23b ;if no ECX given in loop instruction
ao23a: inc ax
ao23b: xchg ax,bx
xor cx,cx
mov ax,[di+8]
mov dx,[di+10]
sub ax,bx
sbb dx,cx
mov [di+5],al
mov cl,7
sar al,cl
cmp al,ah
jne ao24 ;if too big
cmp ax,dx
jne ao24 ;if too big
mov byte [di+4],1 ;save the length
jmp ao22a ;save it away
ao24: jmp ao50 ;reject
; OP_REL1632: relative jump to a longer address.
ao25: mov bx,[a_addr]
inc bx
inc bx
inc bx
cmp word [a_opcode],100h
jb ao26
inc bx
ao26: mov dx,[di+10]
mov al,[di+2]
cmp al,0
je ao27 ;if no size given
cmp al,10
je ao27 ;if "long" given
cmp al,4
jne ao24 ;if the size given was not "dword"
inc bx ;once for the prefix, twice for the longer data
inc bx
inc bx
or byte [varflags],VAR_D32
jmp ao28
ao27: or dx,dx
jnz ao24 ;if operand is too big
mov al,2
ao28: mov [di+4],al ;store the size
mov ax,[di+8]
xor cx,cx
sub ax,bx
sbb dx,cx
mov [di+5],ax
mov [di+7],dx
mov [xxaddr],di
ret
; OP_1CHK - The assembler can ignore this one.
ao29: pop ax ;discard return address
jmp ac06 ;next operand
; OP_STI - ST(I).
ao30: mov al,30 ;code for ST
mov bl,[di+5]
jmp ao38 ;to common code
; OP_CR
ao31: mov al,[di+5] ;get the index
cmp al,4
ja ao24 ;if too big
jne ao32 ;if not CR4
mov byte [dismach],5 ;CR4 is new to the 586
ao32: cmp al,1
jne ao33
cmp byte [di+12],-1
jne ao24 ;if another arg (can't mov CR1,xx)
ao33: mov al,32 ;code for CR
jmp ao37 ;to common code
; OP_DR
ao34: mov al,33 ;code for DR
jmp ao37 ;to common code
; OP_TR
ao35: mov al,[di+5] ;get the index
cmp al,3
jb ao24 ;if too small
cmp al,6
jae ao36
mov byte [dismach],4 ;TR3-5 are new to the 486
ao36: mov al,34 ;code for TR
; Common code for these weird registers.
ao37: mov bl,[di+5]
mov cl,3
shl bl,cl
ao38: or [regmem],bl
or byte [varflags],VAR_MODRM
cmp al,[di+4] ;check for the right numbered register
je ao40 ;if yes, then return
ao38a: jmp ao50
; OP_SEGREG
ao39: mov al,[di+4]
sub al,24
cmp al,6
jae ao38a ;if not a segment register
mov cl,3
shl al,cl
or [regmem],al
ao40: ret
; OP_IMMS8 - Sign-extended immediate byte
ao41: mov ax,[di+8]
mov cl,7
sar al,cl
jmp ao43 ;common code
; OP_IMM8 - Immediate byte
ao42: mov ax,[di+8]
mov al,0
ao43: cmp al,ah
jne ao50 ;if too big
cmp ax,[di+10]
jne ao50 ;if too big
mov al,1
call ao60 ;check that size == 0 or 1
mov ah,[di+8] ;store the byte, length 1
mov [di+4],ax
mov [xxaddr],di
ao43r: ret
; OP_ECX - CX or ECX, determining the operand size
ao43m: cmp byte [di+4],9 ;CX
je ao43r ;if CX (do nothing)
or byte [varflags],VAR_D32
mov al,17
jmp ao48a ;require ECX
; OP_SHOSIZ - force the user to declare the size of the next operand
ao44: test byte [varflags],VAR_SIZ_NEED
jz ao45 ;if no testing needs to be done
test byte [varflags],VAR_SIZ_GIVN
jz ao50 ;if size was given ( ==> reject)
ao45: and byte [varflags],~VAR_SIZ_GIVN ;clear the flag
cmp byte [si],OP_IMM8
je ao45a ;if OP_IMM8 is next, then don't set VAR_SIZ_NEED
or byte [varflags],VAR_SIZ_NEED
ao45a: mov byte [opsize],0
pop ax ;discard return address
jmp ac06 ;next operand
; OP_1
ao46: cmp word [di+7],101h
jmp ao49 ;test it later
; OP_3
ao47: cmp word [di+7],301h
jmp ao49 ;test it later
; OP_DX, OP_CL, OP_ST, OP_ES, ..., OP_GS
ao48: mov al,[asm_regnum+bx-(OP_DX+16-2)/2]
ao48a: cbw
cmp ax,[di+4]
ao49: je ao51
; Reject this operand list.
ao50: pop ax ;discard return address
jmp ac01 ;go back to try the next alternative
ao51: ret
; AASIZCHK - Check that the size given is 0 or AL.
ao60: cmp byte [di+2],0
je ao51
cmp byte [di+2],al
je ao51
pop ax ;discard return address
jmp ao50
; Do reg/mem processing.
; Uses AX
ao90: test byte [di],ARG_JUSTREG
jnz ao92 ;if just register
test byte [di],ARG_MODRM
jz ao91 ;if no precomputed MOD R/M byte
mov ax,word [di+4] ;get the precomputed bytes
jmp ao93 ;done
ao91: mov al,6 ;convert plain displacement to MOD R/M
test byte [asm_mn_flags],AMF_A32
jz ao93 ;if 16 bit addressing
dec ax
jmp ao93 ;done
ao92: mov al,[di+4] ;convert register to MOD R/M
and al,7 ;get low 3 bits
or al,0c0h
ao93: or word [regmem],ax ;store the MOD R/M and SIB
or byte [varflags],VAR_MODRM ;flag its presence
mov [rmaddr],di ;save a pointer
ret ;done
; AAIFNUM - Determine if there's a number next.
; Entry AL First character of number
; SI Address of next character of number
; Exit CY Clear if there's a number, set otherwise.
; Uses None.
aaifnum:
cmp al,'-'
je aai2 ;if minus sign (carry is clear)
push ax
sub al,'0'
cmp al,10
pop ax
jb aai1 ;if a digit
push ax
and al,TOUPPER
sub al,'A'
cmp al,6
pop ax
aai1: cmc ;carry clear <==> it's a number
aai2: ret
; AAGETI - Get a number from the input line.
; Entry AL First character of number
; SI Address of next character of number
; Exit DX:BX Resulting number
; CL 1 if it's a byte, 2 if a word, 4 if a dword
; AL Next character not in number
; SI Address of next character after that
; Uses AH, CH
aageti: cmp al,'-'
je aag1 ;if negative
call aag4 ;get the bare number
mov cx,1 ;set up cx
or dx,dx
jnz aag2 ;if dword
or bh,bh
jnz aag3 ;if word
ret ;it's a byte
aag1: lodsb
call aag4 ;get the bare number
mov cx,bx
or cx,dx
mov cx,1
jz aag1a ;if -0
not dx ;negate the answer
neg bx
cmc
adc dx,0
test dh,80h
jz aag7 ;if error
cmp dx,-1
jne aag2 ;if dword
test bh,80h
jz aag2 ;if dword
cmp bh,-1
jne aag3 ;if word
test bl,80h
jz aag3 ;if word
aag1a: ret ;it's a byte
aag2: inc cx ;return: it's a dword
inc cx
aag3: inc cx ;return: it's a word
ret
aag4: xor bx,bx ;get the basic integer
xor dx,dx
call getnyb
jc aag7 ;if not a hex digit
aag5: or bl,al ;add it to the number
lodsb
call getnyb
jc aag1a ;if done
test dh,0f0h
jnz aag7 ;if overflow
mov cx,4
aag6: shl bx,1 ;shift it by 4
rcl dx,1
loop aag6
jmp aag5
aag7: jmp aa13b ;error
; AACONVINDEX - Convert results from AAGETI and store index value
; Entry DX:BX,CL As in exit from AAGETI
; DI Points to information record for this arg
; Exit SS bits stored in [di+6]
; Uses DL
aaconvindex:
cmp cl,1
jne aacv1 ;if the number is too large
cmp bl,1
je aacv2 ;if 1
inc dx
cmp bl,2
je aacv2 ;if 2
inc dx
cmp bl,4
je aacv2 ;if 4
inc dx
cmp bl,8
je aacv2 ;if 8
aacv1: jmp aa13b ;error
aacv2: mov [di+6],dl ;save the value
ret
; AAGETREG - Get register for the assembler.
; Entry DI Start of register table
; CX Length of register table
; SI Address of first character in register name
; Exit SI Updated if a register was found
; BX Register number, defined as in the table below.
; Uses AX, CX, DI
; Exit value of BX:
; DI = rgnam816, CX = 27 DI = rgnam16, CX = 8
; ---------------------- --------------------
; 0 .. 7: AL .. BH 0 .. 7: AX .. DI
; 8 .. 15: AX .. DI 16 .. 23: EAX..EDI
; 16 .. 23: EAX..EDI
; 24 .. 29: ES .. GS
; 30 .. 34: ST .. MM
aagetreg:
mov ax,[si]
and ax,TOUPPER_W ;convert to upper case
cmp al,'E' ;check for EAX, etc.
jne aagr1 ;if not
push ax
mov al,ah
mov ah,[si+2]
and ah,TOUPPER
push di
mov di,rgnam16
push cx
mov cx,8
repne scasw
mov bx,cx
pop cx
pop di
pop ax
jne aagr1 ;if no match
inc si
not bx
add bl,8+16 ;adjust BX
jmp aagr2 ;finish up
aagr1: mov bx,cx ;(if cx = 0, this is always reached with
repne scasw ; ZF clear)
jne aagr3 ;if no match
sub bx,cx
dec bx
cmp bl,16
jb aagr2 ;if AL .. BH or AX .. DI
add bl,8
aagr2: inc si ;skip the register name
inc si
clc
ret
aagr3: stc ;not found
ret
; C command - compare bytes.
cc: call parsecm ;parse arguments
inc cx
cc1: push si ;do the interrupt pointer hack
push di
push ds
push es
push cs ;ds := cs
pop ds
call dohack
pop es
pop ds
pop di
pop si
repe cmpsb ;start comparing
lahf
mov dl,[si-1] ;save the possibly errant characters
mov dh,[es:di-1]
push si ;undo the interrupt pointer hack
push di
push ds
push es
push cs ;ds := cs
pop ds
call unhack
pop es
pop ds
pop di
pop si
sahf
je cc2 ;if we're done
push cx
push es
push cs
pop es
mov bx,di
mov di,line_out
mov ax,ds
call hexword
mov al,':'
stosb
lea ax,[si-1]
call hexword
mov ax,' '
stosw
mov al,dl
call hexbyte
mov ax,' '
stosw
mov al,dh
call hexbyte
mov ax,' '
stosw
pop ax
push ax
call hexword
mov al,':'
stosb
lea ax,[bx-1]
call hexword
push ds
push cs
pop ds
push bx
call putsline
pop di
pop ds
pop es
pop cx
inc cx
loop cc1 ;if not done yet
cc2: push cs ;restore segment registers
pop ds
push cs
pop es
ret
; D command - hex/ascii dump.
ddd: cmp al,CR
jne dd1 ;if an address was given
mov dx,[d_addr] ;compute range of 80h or until end of segment
mov si,dx
add dx,7fh
jnc dd2 ;if no overflow
mov dx,0ffffh
jmp dd2
dd1: mov cx,80h ;default length
mov bx,[reg_ds]
call getrange ;get address range into dx:bx
call chkeol ;expect end of line here
mov [d_addr+2],bx ;save segment (offset is saved later)
mov si,dx
mov dx,cx ;dx = end address
; Parsing is done. Print first line.
dd2: mov ax,[d_addr+2]
call hexword
mov al,':'
stosb
mov ax,si
and al,0f0h
push ax
call hexword
mov ax,' '
stosw
pop ax
lea bx,[di+50]
mov word [bx-2],' '
push si
push di
call prehack ;set up for faking int vectors 23 and 24
pop di
pop si
dd3: cmp ax,si ;skip to position in line
je dd4 ;if we're there yet
push ax
mov ax,' '
stosw
stosb
mov [es:bx],al
inc bx
pop ax
inc ax
jmp dd3
; Begin main loop over lines of output.
dd4: mov cx,si
or cl,0fh
cmp cx,dx ;compare with end address
jb dd5 ;if we write to the end of the line
mov cx,dx
dd5: sub cx,si
inc cx ;cx = number of bytes to print this line
push si
push di
call dohack ;substitute interrupt vectors
pop di
pop si
mov ds,[d_addr+2]
dd6: lodsb
push ax
push cx
call hexbyte
pop cx
mov al,' '
stosb
pop ax
cmp al,' '
jb dd7 ;if control character
cmp al,'~'
jbe dd8 ;if printable
dd7: mov al,'.'
dd8: mov [es:bx],al
inc bx
loop dd6
dd9: test si,0fh ;space out till end of line
jz dd10
mov ax,' '
stosw
stosb
inc si
jmp dd9
dd10: push cs ;restore ds
pop ds
mov [d_addr],si
mov byte [di-25],'-'
push si
call unhack
pop si
mov di,bx
push dx
call putsline
pop dx
dec si
cmp si,dx
jae dd11 ;if we're done
inc si
mov di,line_out+5 ;set up for next time
mov ax,si
call hexword
inc di
inc di
lea bx,[di+50]
jmp dd4
dd11: inc dx ;set up the address for the next 'D' command.
mov [d_addr],dx
ret
errorj4:jmp error
; E command - edit memory.
ee: push si
push di
call prehack
pop di
pop si
mov bx,[reg_ds]
call getaddr ;get address into bx:dx
call skipcomm0
cmp al,CR
je ee1 ;if prompt mode
push dx
call getstr ;get data bytes
mov cx,di
mov dx,line_out
sub cx,dx ;length of byte string
pop di
mov ax,cx
dec ax
add ax,di
jc errorj4 ;if it wraps around
push di
call dohack
pop di
mov si,dx
mov es,bx
rep movsb
; Restore ds and es and undo the interrupt vector hack.
; This code is also used by the `m' command.
ee0a: push cs ;restore es
pop es
mov di,run2324
call prehak1 ;copy things back and restore ds
call unhack
ret
; Prompt mode.
ee1: xchg bx,dx
; Begin loop over lines.
ee2: mov ax,dx ;print out segment and offset
call hexword
mov al,':'
stosb
mov ax,bx
call hexword
; Begin loop over bytes.
ee3: mov ax,' ' ;print old value of byte
stosw
push di
call dohack ;do the INT pointer hack
mov es,dx
mov al,[es:bx]
call unhack ;undo the INT pointer hack and restore es.
pop di
call hexbyte
mov al,'.'
stosb
push dx ;save dx
push bx
call puts
pop bx
mov si,line_out+16 ;address of buffer for characters
xor cx,cx ;number of characters so far
ee4: cmp byte [notatty],0
jz ee9 ;if it's a tty
push si
mov di,line_in+2
mov si,[bufnext]
ee5: cmp si,[bufend]
jb ee6 ;if there's a character already
call fillbuf
mov al,CR
jc ee8 ;if eof
ee6: cmp byte [notatty],CR
jne ee7 ;if no need to compress CR/LF
cmp byte [si],LF
jne ee7 ;if not a line feed
inc si ;skip it
inc byte [notatty] ;avoid repeating this
jmp ee5 ;next character
ee7: lodsb ;get the character
mov [notatty],al
ee8: mov [bufnext],si
pop si
jmp ee10
ee9: mov ah,8 ;console input without echo
int 21h
ee10: cmp al,' '
je ee13 ;if done with this byte
cmp al,CR
je ee13 ;ditto
cmp al,BS
je ee11 ;if backspace
cmp cx,2 ;otherwise, it should be a hex character
jae ee4 ;if we have a full byte already
mov [si],al
call getnyb
jc ee4 ;if it's not a hex character
inc cx
lodsb ;get the character back
jmp ee12
ee11: jcxz ee4 ;if nothing to backspace over
dec cx
dec si
ee12: xchg ax,dx ;move character into dl
mov ah,2 ;display output
int 21h
jmp ee4 ;back for more
; We have a byte (if CX != 0).
ee13: jcxz ee14 ;if no change for this byte
mov [si],al ;terminate the string
sub si,cx ;point to beginning
push cx
lodsb
call getbyte ;convert byte to binary
pop cx
call dohack ;do the INT pointer hack
pop ds ;get segment register
mov [bx],dl ;save the byte
push ds ;segment back on the stack
mov di,run2324
call prehak1 ;copy things back and restore ds
call unhack ;undo the INT pointer hack
; End the loop over bytes.
ee14: inc bx ;next word
pop dx ;restore dx
mov di,line_out
cmp al,CR
je ee16 ;if done
test bl,7
jz ee15 ;if new line
not cx
add cx,4 ;compute 3 - cx
mov al,' '
rep stosb ;store that many spaces
jmp ee3 ;back for more
ee15: mov ax,LF * 256 + CR;terminate this line
stosw
jmp ee2 ;back for a new line
ee16: jmp putsline ;call putsline and return
; F command - fill memory
ff: xor cx,cx ;get address range (no default length)
mov bx,[reg_ds]
call getrange
sub cx,dx
inc cx ;cx = number of bytes
push cx ;save it
push dx ;save start address
call skipcomm0
call getstr ;get string of bytes
mov cx,di
sub cx,line_out
pop di
mov es,bx
cmp cx,1
je ff3 ;a common optimization
pop ax
xor dx,dx
div cx ;compute number of whole repetitions
or ax,ax
jz ff2 ;if less than one whole rep
ff1: mov si,line_out
push cx
rep movsb
pop cx
dec ax
jnz ff1 ;if more to go
ff2: mov cx,dx
jcxz ff4 ;if no partial copies
mov si,line_out
rep movsb
jmp ff4 ;done (almost)
ff3: pop cx
mov al,[line_out]
rep stosb
ff4: push cs ;restore es
pop es
ret
; G command - go.
gg: xchg ax,bx ;mov bx,ax
mov ax,[reg_cs] ;save original CS
mov [run_cs],ax
mov [eqladdr+2],ax
xchg ax,bx ;mov ax,bx
call parseql ;process =addr
mov di,line_out+2
mov [di-2],si ;save si
; Parse the rest of the line to make sure there are no errors.
gg1: call skipcomm0
cmp al,CR
je gg2 ;if end of line
call getaddr
jmp gg1 ;back for more
; Store breakpoint bytes in the given locations.
gg2: mov si,[di-2]
gg3: dec si
call skipcomma
cmp al,CR
je gg4 ;if done
mov bx,[eqladdr+2] ;default segment
call getaddr ;get address into bx:dx
mov ds,bx
mov bx,dx
mov al,0cch ;INT 3 instruction
xchg al,[bx] ;put it there
push cs ;restore DS
pop ds
stosb ;save the old contents
jmp gg3 ;back for more
; Now run the program.
gg4: call seteq ;make the = operand take effect
call run
; Restore breakpoint bytes.
mov di,line_out+2
mov si,[di-2]
gg5: dec si
call skipcomma
cmp al,CR
je gg6 ;if done
mov bx,[run_cs] ;default segment
call getaddr ;get address into bx:dx
mov al,[di] ;get old contents
inc di
cmp al,0cch ;this is because of possible duplicate values
je gg5 ;if it was INT 3 originally
mov ds,bx
mov bx,dx
mov [bx],al ;restore value
push cs ;restore DS
pop ds
jmp gg5 ;back for more
; Finish up. Check if it was one of _our_ breakpoints.
gg6: cmp word [run_int],int3msg
jne gg9 ;if not CC interrupt
dec word [reg_ip]
mov si,[line_out] ;loop over the set breakpoints
gg7: dec si
call skipcomma
cmp al,CR
je gg8 ;if done
mov bx,[run_cs] ;default segment
call getaddr ;get address into bx:dx
mov ax,dx
xor ax,[reg_ip]
test al,0fh
jnz gg7 ;if no match
mov cl,4
mov ax,[reg_ip]
shr ax,cl
add ax,[reg_cs]
shr dx,cl
add bx,dx
cmp ax,bx
jne gg7 ;if no match
; It's one of ours.
call dumpregs
ret
; It's not.
gg8: inc word [reg_ip]
gg9: jmp tt2 ;print messages and quit.
; H command - hex addition and subtraction.
hh: call getword
push dx
call skipcomm0
call getword
call chkeol ;expect end of line here
pop bx
mov ax,bx
add ax,dx
call hexword
mov ax,' '
stosw
mov ax,bx
sub ax,dx
call hexword
call putsline
ret
; I command - input from I/O port.
ii: call getword
call chkeol ;expect end of line here
in al,dx
call hexbyte
call putsline
iiret: ret
errorj5:jmp error
; L command - read a program, or disk sectors, from disk.
ll: call parselw ;parse it
jz ll1 ;if request to read program
int 25h
mov dx,reading
jmp ww1
; For .com or .exe files, we can only load at cs:100. Check that first.
ll1: test byte [fileext],EXT_COM+EXT_EXE
jz ll3 ;if not .com or .exe file
cmp bx,[reg_cs]
jne ll2 ;if segment is wrong
cmp dx,100h
je ll4 ;if address is OK (or not given)
ll2: jmp error ;can only load .com or .exe at cs:100
; Get length of file
ll3: cmp byte [fileext],0
jz iiret ;if no file name given
ll4: mov si,bx ;save destination address
mov di,dx
mov ax,3d00h ;open file for reading
mov dx,DTA
int 21h
jnc ll5 ;if no error
jmp ll16 ;error
ll5: xchg ax,bx ;mov bx,ax
mov ax,4202h ;lseek
xor cx,cx
xor dx,dx
int 21h
; Split off file types
; At this point:
; bx file handle
; dx:ax file length
; si:di load address
test byte [fileext],EXT_COM | EXT_EXE
jnz ll13 ;if .com or .exe file
; Load it ourselves.
; For non-.com/.exe files, we just do a read, and set BX:CX to the
; number of bytes read.
; Check the size against available space.
push si
push bx
cmp si,[ALASAP]
pushf
neg si
popf
jae ll6 ;if loading past end of mem, allow through ffff
add si,[ALASAP] ;si = number of paragraphs available
ll6: mov cx,4
xor bx,bx
ll7: shl si,1
rcl bx,1
loop ll7
sub si,di
sbb bx,0 ;bx:si = number of words left
jb ll9 ;if already we're out of space
cmp bx,dx
jne ll8
cmp si,ax
ll8: jae ll10 ;if not out of space
ll9: pop bx ;out of space
pop si
mov dx,doserr8 ;not enough memory
call int21ah9 ;print string
jmp ll12
ll10: pop bx
pop si
; Store length in registers
mov [reg_bx],dx
mov [reg_cx],ax
; Rewind the file
mov ax,4200h ;lseek
xor cx,cx
xor dx,dx
int 21h
mov dx,0fh
and dx,di
mov cl,4
shr di,cl
add si,di ;si:dx is the address to read to
; Begin loop over chunks to read
ll11: mov ah,3fh ;read from file
mov cx,0fe00h ;read up to this many bytes
mov ds,si
int 21h
cmp ax,cx
jne ll12 ;if end of file reached
add si,0fe0h
jmp ll11
; Close the file and finish up.
ll12: mov ah,3eh ;close file
int 21h
push cs ;restore ds
pop ds
ret ;done
; Close the file
ll13: push ax
mov ah,3eh ;close file
int 21h
pop bx ;dx:bx is the file length
; adjust .exe size by 200h (who knows why)
test byte [fileext],EXT_EXE
jz ll14 ;if not .exe
sub bx,200h
sbb dx,0
; Clear registers
ll14: mov di,reg_bx
xor ax,ax
mov cx,7
rep stosw
mov [reg_bx],dx
mov [reg_cx],bx
; Free up memory
call freemem ;return the previous process's memory
; Fix up interrupt vectors in PSP
mov si,0eh ;address of original INT 23 and 24 (in PSP)
mov di,run2324
movsw
movsw
movsw
movsw
; Actual program loading. Use the DOS interrupt.
mov ax,4b01h ;load program
mov dx,DTA ;offset of file to load
mov bx,execblk ;parameter block
int 21h ;load it
jc ll16 ;if error
mov ax,sp
sub ax,[SPSAV]
cmp ax,80h
jb ll15 ;if in range
mov ax,80h
ll15: mov [spadjust],ax
mov byte [running],1 ;set flag
les si,[execblk+14]
es lodsw ;recover ax
mov [reg_ax],ax
mov [reg_sp],si
mov [reg_ss],es
les si,[execblk+18]
mov [reg_ip],si
mov [reg_cs],es
push cs
pop es
mov ah,51h ;get new PSP
int 21h
xchg ax,bx ;mov ax,bx
mov [psp],ax
mov di,reg_ds
stosw
stosw ;reg_es
mov ah,50h ;set PSP back
mov bx,cs
int 21h
; Finish up. Set termination address.
mov ax,2522h ;set interrupt vector 22
mov dx,int22
int 21h
mov ds,[psp]
mov word [TPIVOFS],int22
mov [TPIVSEG],cs
push cs
pop ds
; Set up initial addresses for 'a', 'd', and 'u' commands.
adusetup:
mov ax,[reg_ip]
mov bx,[reg_cs]
mov di,a_addr
stosw
xchg ax,bx
stosw
xchg ax,bx ;d_addr
stosw
xchg ax,bx
stosw
xchg ax,bx ;u_addr
stosw
xchg ax,bx
stosw
ret
; Error messages. Print and quit.
ll16: call ww15 ;print error message
ret
; M command - move from place to place.
mm: push si ;scan for comma or 'l'
m1: cmp al,','
je m2 ;if comma found
cmp al,CR
je m5 ;if end of string
or al,TOLOWER
cmp al,'l'
je m2 ;if 'l' found
lodsb
jmp m1 ;loop back
; Normal 'm' command (move).
m2: pop si
dec si
lodsb
call parsecm ;parse arguments
push cx
mov cl,4
shr dx,cl
add dx,bx ;upper 16 bits of destination
mov ax,si
shr ax,cl
mov bx,ds
add ax,bx
cmp ax,dx
jne m3 ;if we know which is larger
mov ax,si
and al,0fh
mov bx,di
and bl,0fh
cmp al,bl
m3: pop cx
lahf
push si ;do the interrupt pointer hack
push di
push ds
push es
push cs ;ds := cs
pop ds
call dohack
pop es
pop ds
pop di
pop si
sahf
jae m4 ;if forward copy is OK
add si,cx
add di,cx
std
m4: rep movsb ;do the move
movsb ;one more byte
cld ;restore flag
jmp ee0a ;restore ds and es and undo the int pointer hack
; Other 'm' command: set machine type.
m5: pop si
dec si
lodsb
cmp al,CR
je m10 ;if just an 'm' (query machine type)
cmp al,'?'
je m10 ;if '?' (also query)
cmp al,'0'
jb m6 ;if not a digit
cmp al,'6'
ja m6 ;ditto
sub al,'0'
mov [machine],al ;set machine type
mov [mach_87],al ;coprocessor type, too
ret
m6: or al,TOLOWER
cmp al,'c'
je m7 ;if coprocessor declaration
cmp al,'n'
jne errorj3 ;if something else
lodsb
or al,TOLOWER
cmp al,'c'
jne errorj3 ;if not 'c' after that
lodsb
call chkeol
mov byte [has_87],0 ;clear coprocessor flag
ret ;done
m7: call skipwhite ;get next nonblank character
mov ah,[machine]
cmp ah,3
jne m9 ;if not a 386
cmp al,'3'
je m8 ;if declaring a 387
cmp al,'2'
jne m9 ;if not '2'
mov ah,2
m8: call skipwhite
m9: cmp al,CR
jne errorj3 ;if not end of line
mov byte [has_87],1 ;set coprocessor flag
mov [mach_87],ah ;set copr. type
ret
; Display machine type.
m10: mov si,msg8088
mov al,[machine]
cmp al,0
je m11 ;if 8088
mov si,msgx86
add al,'0'
mov [si],al
m11: call showstring
mov si,no_copr
cmp byte [has_87],0
je m12 ;if no coprocessor
mov si,has_copr
mov al,[mach_87]
cmp al,[machine]
je m12 ;if has coprocessor same as processor
mov si,has_287
m12: call showstring ;show string
jmp putsline ;call puts and quit
errorj3:jmp error
; N command - change the name of the program being debugged.
nn: mov di,DTA ;destination address
; Copy and canonicalize file name.
nn1: cmp al,CR
je nn3 ;if end of line
call ifsep ;check for separators space, TAB, comma, ;, =
je nn3 ;if end of file name
cmp al,[swch1]
je nn3 ;if '/' (and '/' is the switch character)
cmp al,'a'
jb nn2 ;if not lower case
cmp al,'z'
ja nn2 ;ditto
and al,TOUPPER ;convert to upper case
nn2: stosb
lodsb
jmp nn1 ;back for more
nn3: mov al,0 ;null terminate the file name string
stosb
mov [execblk+2],di ;save start of command tail
; Determine file extension
cmp di,DTA+1
je nn3d ;if no file name at all
cmp di,85h
jb nn3c ;if no extension (name too short)
mov al,EXT_HEX
cmp word [di-5],'.H'
jne nn3a ;if not .HEX
cmp word [di-3],'EX'
je nn3d ;if .HEX
nn3a: mov al,EXT_EXE
cmp word [di-5],'.E'
jne nn3b ;if not .EXE
cmp word [di-3],'XE'
je nn3d ;if .EXE
nn3b: mov al,EXT_COM
cmp word [di-5],'.C'
jne nn3c ;if not .COM
cmp word [di-3],'OM'
je nn3d ;if .COM
nn3c: mov al,EXT_OTHER
nn3d: mov [fileext],al
; Finish the N command
push di
mov di,line_out
dec si
nn4: lodsb ;copy the remainder to line_out
stosb
cmp al,CR
jne nn4
; Set up FCBs.
mov si,line_out
mov di,5ch
call nn6 ;do first FCB
mov byte [reg_ax],al
mov di,6ch
call nn6 ;second FCB
mov byte [reg_ax+1],al
; Copy command tail.
mov si,line_out
pop di
push di
inc di
nn5: lodsb
stosb
cmp al,CR
jne nn5 ;if not end of string
pop ax ;recover old DI
xchg ax,di
sub ax,di ;compute length of tail
dec ax
dec ax
stosb
ret ;done
; Subroutine to process an FCB.
nn6: lodsb
cmp al,CR
je nn7 ;if end
call ifsep
je nn6 ;if separator
cmp al,[switchar]
je nn10 ;if switch character
nn7: dec si
mov ax,2901h ;parse filename
int 21h
push ax ;save AL
nn8: lodsb ;skip till separator
cmp al,CR
je nn9 ;if end
call ifsep
je nn9 ;if separator character
cmp al,[swch1]
jne nn8 ;if not switchar (sort of)
nn9: dec si
pop ax ;recover AL
cmp al,1
jne nn9a ;if not 1
dec ax
nn9a: ret
; Handle a switch (differently).
nn10: lodsb
cmp al,CR
je nn7 ;if end of string
call ifsep
je nn10 ;if another separator
mov al,0
stosb
dec si
lodsb
cmp al,'a'
jb nn11 ;if not a lower case letter
cmp al,'z'
ja nn11
and al,TOUPPER ;convert to upper case
nn11: stosb
mov ax,' '
stosw
stosw
stosw
stosw
stosw
xor ax,ax
stosw
stosw
stosw
stosw
ret ;return with AL=0
; O command - output to I/O port.
oo: call getword
push dx
call skipcomm0
call getbyte
call chkeol ;expect end of line here
xchg ax,dx ;al = byte
pop dx ;recover port number
out dx,al
ret
; P command - proceed (i.e., skip over call/int/loop/string instruction).
pp: call parse_pt ;process arguments
; Do it <count> times. First check the type of instruction.
pp1: push cx ;save cx
mov si,[reg_ip]
mov dx,15 ;DL = number of bytes to go; DH = prefix flags.
pp2: call pp16 ;get next instruction byte into AL
mov di,ppbytes
mov cx,PPLEN
repne scasb
jne pp5 ;if not one of these
mov al,[di+PPLEN-1] ;get corresponding byte in ppinfo
test al,80h
jz pp3 ;if not a prefix
or dh,al ;set the flags
dec dl
jnz pp2 ;if not out of bytes
jmp pp12
pp3: test al,40h
jz pp4 ;if no size dependency
and al,3fh
and dh,2
add al,dh
pp4: cbw
add si,ax
jmp pp11 ;we have a skippable instruction here
pp5: cmp al,0ffh
jne pp12 ;just an ordinary instruction
call pp16 ;get MOD REG R/M byte
and al,~8 ;clear lowest bit of REG field (/3 --> /2)
xor al,10h ;/2 --> /0
test al,38h
jnz pp12 ;if not ff/2 or ff/3
cmp al,0c0h
jae pp11 ;if just a register
test dh,1
jnz pp6 ;if 32 bit addressing
cmp al,6
je pp9 ;if just plain disp16
cmp al,40h
jb pp11 ;if indirect register
cmp al,80h
jb pp10 ;if disp8[reg(s)]
jmp pp9 ;it's disp16[reg(s)]
pp6: cmp al,5
je pp8 ;if just plain disp32
xor al,4
test al,7
jnz pp7 ;if no SIB byte
inc si
pp7: cmp al,40h
jb pp11 ;if indirect register
cmp al,80h
jb pp10 ;if disp8[reg(s)]
;otherwise, it's disp32[reg(s)]
pp8: inc si
inc si
pp9: inc si
pp10: inc si
; Special instruction. Set a breakpoint and run until we hit it.
pp11: mov ds,[reg_cs]
mov al,0cch
xchg al,[si]
push cs
pop ds
mov di,line_out ;save old byte here
stosb
xchg ax,si
stosw
mov ax,[reg_cs]
stosw
call run
mov si,line_out
lodsb ;get old byte
xchg ax,cx
lodsw ;old IP
xchg ax,bx
lodsw ;old CS
xchg ax,cx
mov ds,cx
mov [bx],al
push cs
pop ds
xor dx,dx ;set flag
cmp word [run_int],int3msg
jne pp13 ;if not CC interrupt
cmp cx,[reg_cs]
jne pp13 ;if not same segment
mov ax,[reg_ip]
dec ax
cmp ax,bx
jne pp13 ;if not same offset
mov [reg_ip],ax
mov dx,int3msg
jmp pp13
; Ordinary instruction. Just do a trace.
pp12: or word [flags],100h ;set single-step mode
call run
mov dx,int1msg
; Common part to finish up.
pp13: cmp [run_int],dx
jne pp15 ;if some other interrupt
call dumpregs
pop cx
loop pp14 ;back for more
ret
pp14: jmp pp1 ;back for more
pp15: jmp tt2 ;print message about unexpected interrupt
;and quit
; PPX - Get next byte in instruction stream.
pp16: mov ds,[reg_cs]
lodsb
push cs
pop ds
ret
; begin loop over instruction bytes.
; Q command - quit.
qq: call freemem ;free the child process memory
; Restore interrupt vectors.
mov si,intsave
lodsw
xchg ax,dx ;mov dx,ax
lodsw
mov ds,ax
mov ax,2500h ;set interrupt vector 0
int 21h
push cs
pop ds
lodsw
xchg ax,dx ;mov dx,ax
lodsw
mov ds,ax
mov ax,2501h ;set interrupt vector 1
int 21h
push cs
pop ds
lodsw
xchg ax,dx ;mov dx,ax
lodsw
mov ds,ax
mov ax,2503h ;set interrupt vector 3
int 21h
push cs
pop ds
; Restore termination address.
mov si,psp22 ;restore termination address
mov di,0ah
movsw
movsw
mov di,16h ;restore PSP of parent
movsw
; Really done.
int 20h
; R command - manipulate registers.
rr: cmp al,CR
jne rr1 ;if there's an argument
call dumpregs
ret
rr1: dec si
lodsw
and ax,TOUPPER_W
mov di,regnames
mov cx,13
repne scasw
mov bx,di
mov di,line_out
jne rr2 ;if not found
stosw ;print register name
mov al,' '
stosb
sub bx,regnames+2
call skipcomma ;skip white spaces
cmp al,CR
jne rr1a ;if not end of line
push bx ;save bx for later
mov ax,[bx+regs]
call hexword
call getline0 ;prompt for new value
pop bx
cmp al,CR
je rr1b ;if no change required
rr1a: call getword
call chkeol ;expect end of line here
mov [bx+regs],dx ;save new value
cmp bx,reg_ip - regs
jne rr1b ;if not changing IP
mov byte [prg_trm],0 ;clear flag
rr1b: ret
; Change flags
rr2: cmp al,'F'
jne rr6 ;if not 'f'
dec si
lodsb
cmp al,CR
je rr2b ;if end of line
cmp al,' '
je rr2a ;if white space
cmp al,TAB
je rr2a ;ditto
cmp al,','
jne errorj9 ;if not, then it's an error
rr2a: call skipcomm0
cmp al,CR
jne rr3 ;if not end of line
rr2b: call dmpflags
call getline0 ;get input line (using line_out as prompt)
rr3: cmp al,CR
je rr1b ;return if done
dec si
lodsw
and ax,TOUPPER_W ;here's the mnemonic
mov di,flgnams
mov cx,16
repne scasw
jne rr6 ;if no match
cmp di,flgnons
ja rr4 ;if we're clearing
mov ax,[di-16-2]
not ax
and [flags],ax
jmp rr5
rr4: mov ax,[di-32-2]
or [flags],ax
rr5: call skipcomma
jmp rr3 ;if done
rr6: dec si ;back up one before flagging an error
errorj9:jmp error
; S command - search for a string of bytes.
sss: mov bx,[reg_ds] ;get search range
xor cx,cx
call getrange ;get address range into BX:DX..BX:CX
call skipcomm0
push cx
push dx
call getstr ;get string of bytes
pop dx
pop cx
sub cx,dx ;cx = number of bytes in search range minus one
sub di,line_out ;di = number of bytes to look for
dec di ; minus one
sub cx,di ;number of possible positions of string minus 1
jb errorj9 ;if none
push di
call prehack ;set up for the interrupt vector hack
pop di
inc cx ;cx = number of possible positions of string
xchg dx,di
push bx ;push the segment
sss1: push di
call dohack ;do the interrupt pointer hack
pop di
pop es ;recover the segment
mov si,line_out ;si = address of search string
lodsb ;first character in al
repne scasb ;look for first byte
jne sss3 ;if we're done
push es ;save the segment again
mov ax,es ;also in ax
push cx
push di
mov cx,dx
repe cmpsb
push si
pushf
call unhack ;undo the interrupt vector hack and restore es
popf
pop si
pop di
jne sss2 ;if not equal
push dx
xchg si,di ;write address right after search string
call hexword
mov al,':'
stosb
lea ax,[si-1]
call hexword
mov ax,LF * 256 + CR
stosw
mov ah,40h ;write to file
mov bx,1
mov cx,11
lea dx,[di-11]
int 21h
pop dx
mov di,si
sss2: pop cx
inc cx
loop sss1 ;go back for more
pop ax ;remove saved es from the stack
sss3: jmp unhack ;undo the interrupt vector hack, restore es,
;and return
; T command - Trace.
tt: call parse_pt ;process arguments
; Do it <count> times.
tt1: push cx
or word [flags],100h ;set single-step mode
call run
cmp word [run_int],int1msg
jne tt2 ;if some other interrupt
call dumpregs
pop cx
loop tt1
ret
; Print message about unexpected interrupt, dump registers, and end
; command. This code is also used by the G and P commands.
tt2: mov dx,[run_int]
call int21ah9 ;print string
cmp dx,progtrm
je tt3 ;if it terminated, skip the registers
call dumpregs
tt3: jmp cmd3 ;back to the start
; U command - disassemble.
uu: cmp al,CR
jne uu1 ;if an address was given
mov cx,[u_addr]
add cx,1fh
jnc uu2 ;if no overflow
mov cx,-1
jmp uu2
uu1: mov cx,20h ;default length
mov bx,[reg_cs]
call getrange ;get address range into dx:bx
call chkeol ;expect end of line here
mov [u_addr+2],bx
mov [u_addr],dx
; At this point, cx holds the last address, and dx the address.
uu2: inc cx ;cx = last address + 1
uu3: push cx
push dx
mov byte [disflags],0
call disasm ;do it
pop bx
pop cx
mov ax,[u_addr]
mov dx,ax
sub ax,cx ;current position - end
sub bx,cx ;previous position - end
cmp ax,bx
jnb uu3 ;if we haven't reached the goal
uu4: ret
; W command - write a program, or disk sectors, to disk.
ww: call parselw ;parse it
jz ww4 ;if request to write program
int 26h
mov dx,writing
ww1: mov bx,cs ;restore segment registers
mov ds,bx
mov ss,bx
mov sp,[savesp]
mov es,bx
jnc ww3 ;if no error
cmp al,0ch
jbe ww2 ;if in range
mov al,0ch
ww2: cbw
shl ax,1
xchg si,ax
mov si,[si+dskerrs]
mov di,line_out
call showstring
mov si,dx
call showstring
mov si,drive
call showstring
call putsline
ww3: jmp cmd3 ;can't ret because stack is wrong
; Write to file. First check the file extension.
ww4: mov al,[fileext] ;get flags of file extension
test al,EXT_EXE + EXT_HEX
jz ww5 ;if not EXE or HEX
mov dx,nowhexe
jmp ww6
ww5: cmp al,0
jnz ww7 ;if extension exists
mov dx,nownull
ww6: jmp ww16
; File extension is OK; write it. First, create the file.
ww7: mov bp,line_out
cmp dh,0feh
jb ww8 ;if dx < fe00h
sub dh,0feh ;dx -= 0xfe00
add bx,0fe0h
ww8: mov [bp+10],dx ;save lower part of address in line_out+10
mov si,bx ;upper part goes into si
mov ah,3ch ;create file
xor cx,cx ;no attributes
mov dx,DTA
int 21h
jc ww15 ;if error
push ax ;save file handle
; Print message about writing.
mov dx,wwmsg1
call int21ah9 ;print string
mov ax,[reg_bx]
cmp ax,10h
jb ww9 ;if not too large
xor ax,ax ;too large: zero it out
ww9: mov [bp+8],ax
or ax,ax
jz ww10
add al,90h ;convert to hex and print
daa
adc al,40h
daa
stosb
ww10: mov ax,[reg_cx]
mov [bp+6],ax
call hexword
call puts ;print size
mov dx,wwmsg2
call int21ah9 ;print string
; Now write the file. Size remaining is in line_out+6.
pop bx ;recover file handle
mov dx,[bp+10] ;address to write from is si:dx
ww11: mov ax,0fe00h
sub ax,dx
cmp byte [bp+8],0
jnz ww12 ;if more than 0fe00h bytes remaining
cmp ax,[bp+6]
jb ww12 ;ditto
mov ax,[bp+6]
ww12: xchg ax,cx ;mov cx,ax
mov ah,40h ;write to file
mov ds,si
int 21h
push cs ;restore DS
pop ds
cmp ax,cx
jne ww13 ;if disk full
xor dx,dx ;next time write from xxxx:0
add si,0fe0h ;update segment pointer
sub [bp+6],cx
lahf
sbb byte [bp+8],0
jnz ww11 ;if more to go
sahf
jnz ww11 ;ditto
jmp ww14 ;done
ww13: mov dx,diskful
call int21ah9 ;print string
mov ah,41h ;unlink file
mov dx,DTA
int 21h
; Close the file.
ww14: mov ah,3eh ;close file
int 21h
ret
; Error opening file. This is also called by the load command.
ww15: cmp ax,2
mov dx,doserr2 ;File not found
je ww16
cmp ax,3
mov dx,doserr3 ;Path not found
je ww16
cmp ax,5
mov dx,doserr5 ;Access denied
je ww16
cmp ax,8
mov dx,doserr8 ;Insufficient memory
je ww16
mov di,wwerr1
call hexword
mov dx,wwerr ;Error ____ opening file
ww16:
int21ah9:mov ah,9 ;print string
int 21h
ret
; X commands - manipulate EMS memory.
;
; Reference:
; http://www.nondot.org/sabre/os/files/MemManagement/LIMEMS41.txt
xx: cmp al,'?'
je xhelp ;if a call for help
or al,TOLOWER
cmp al,'a'
je xa ;if XA command
cmp al,'d'
je xd ;if XD command
cmp al,'m'
je xm ;if XM command
cmp al,'s'
je xs ;if XS command
jmp error
xhelp: mov dx,xhelpmsg
jmp int21ah9 ;print string and return
; XA - Allocate EMS.
xa: call emschk
call skipcomma
call getword ;get argument into DX
call chkeol ;expect end of line here
mov bx,dx
mov ah,43h ;allocate handle
call callems
xchg ax,dx ;mov ax,dx
mov di,xaans1
call hexword
mov dx,xaans
jmp int21ah9 ;print string and return
; XD - Deallocate EMS handle.
xd: call emschk
call skipcomma
call getword ;get argument into DX
call chkeol ;expect end of line here
mov ah,45h ;deallocate handle
call callems
xchg ax,dx ;mov ax,dx
mov di,xdans1
call hexword
mov dx,xdans
jmp int21ah9 ;print string and return
; XM - Map EMS memory to physical page.
xm: call emschk
call skipcomma
call getword ;get logical page
mov bx,dx ;save it in BX
call skipcomm0
call getbyte ;get physical page
push dx
call skipcomm0
call getword ;get handle into DX
call chkeol ;expect end of line
pop ax ;recover physical page into AL
push ax
mov ah,44h ;function 5 - map memory
call callems
mov di,xmans1
xchg ax,bx ;mov al,bl
call hexbyte
add di,xmans2-xmans1-2
pop ax
call hexbyte
mov dx,xmans
jmp int21ah9 ;print string and return
; XS - Print EMS status.
xs: call emschk
lodsb
call chkeol ;no arguments allowed
; First print out the handles and handle sizes. This can be done either
; by trying all possible handles or getting a handle table.
; The latter is preferable, if it fits in memory.
mov ah,4bh ;function 12 - get handle count
call callems
cmp bx,(real_end-line_out)/4
jbe xs3 ;if we can do it by getting the table
xor dx,dx ;handle
xs1: mov ah,4ch ;function 13 - get handle pages
int 67h
cmp ah,83h
je xs2 ;if no such handle
or ah,ah
jnz ce1 ;if other error
xchg ax,bx ;mov ax,bx
call hndlshow
xs2: inc dl ;end of loop
jnz xs1 ;if more to be done
jmp xs5 ;done with this part
; Get the information in tabular form.
xs3: mov ah,4dh ;function 14 - get all handle pages
mov di,line_out
call callems
mov si,di
xs4: lodsw
xchg ax,dx
lodsw
call hndlshow
dec bx
jnz xs4 ;if more to go
xs5: mov dx,crlf
call int21ah9 ;print string
; Next print the mappable physical address array.
; The size of the array shouldn't be a problem.
mov ax,5800h ;function 25 - get mappable phys. address array
mov di,line_out ;address to put array
call callems
mov si,di
xs6: push cx
lodsw
mov di,xsstr2b
call hexword
lodsw
mov di,xsstr2a
call hexbyte
mov dx,xsstr2
call int21ah9 ;print string
pop cx ;end of loop
loop xs6
mov dx,crlf ;blank line
call int21ah9 ;print string
; Finally, print the cumulative totals.
mov ah,42h ;function 3 - get unallocated page count
call callems
mov ax,dx ;total pages available
sub ax,bx ;number of pages allocated
mov bx,xsstrpg
call sumshow ;print the line
mov ah,4bh ;function 12 - get handle count
call callems
xchg ax,bx ;ax = number of handles allocated
mov dx,0ffh ;total number of handles
mov bx,xsstrhd
call sumshow ;print the line
ret ;done
; Call EMS
callems:int 67h
cmp ah,0
jz echk1 ;return if OK
ce1: mov al,ah
cmp al,8bh
jg ce2 ;if out of range
cbw
mov bx,ax
shl bx,1
mov dx,[emserrs+100h+bx]
or dx,dx
jnz ce3 ;if there's a word there
ce2: mov di,emserrxa
call hexbyte
mov dx,emserrx
ce3: jmp prnquit ;print string and quit
; Check for EMS
emschk: push si ;save si
mov ax,3567h ;get interrupt vector 67h
int 21h
mov si,emmname
mov di,0ah
mov cx,4
repe cmpsw
push cs ;restore es
pop es
pop si ;restore si
jne echk2 ;if EMS not installed
echk1: ret
echk2: mov dx,emsnot
jmp prnquit ;print string and quit
; HNDLSHOW - Print XS line giving the handle and pages allocated.
;
; Entry DX Handle
; AX Number of pages
;
; Exit Line printed
;
; Uses ax,cl,di.
hndlshow:
mov di,xsstr1b
call hexword
mov ax,dx
mov di,xsstr1a
call hexword
push dx
mov dx,xsstr1
call int21ah9 ;print string
pop dx
ret
; SUMSHOW - Print summary line for XS command.
;
; Entry AX Number of xxxx's that have been used
; DX Total number of xxxx's
; BX Name of xxxx
;
; Exit String printed
;
; Uses AX, CX, DX, DI
sumshow:mov di,xsstr3
push di
call trimhex
xchg ax,dx ;mov ax,dx
mov di,xsstr3a
call trimhex
pop dx ;mov dx,xsstr3
call int21ah9 ;print string
mov dx,bx
call int21ah9 ;print string
mov dx,xsstr4
jmp int21ah9 ;print string and return
; TRIMHEX - Print word without leading zeroes.
;
; Entry AX Number to print
; DI Where to print it
;
; Uses AX, CX, DI.
trimhex:call hexword
sub di,4 ;back up DI to start of word
mov cx,3
mov al,'0'
tx1: scasb
jne tx2 ;return if not a '0'
mov byte [di-1],' '
loop tx1
tx2: ret
; Error handlers.
error: mov cx,si
sub cx,line_in+4
add cx,[promptlen]
cmp cx,127
ja err2 ;if we're really messed up
inc cx ;number of spaces to skip
mov dl,' '
err1: mov ah,2 ;display output
int 21h
loop err1
err2: mov dx,errcarat
call int21ah9 ;print string
jmp [errret]
; FREEMEM - Free the child process's memory.
freemem:mov byte [prg_trm],0 ;clear 'term' flag
cmp byte [running],0
jz fmem1 ;if process has already terminated
mov [reg_cs],cs
mov word [reg_ip],fmem2
mov [reg_ss],ss
push ax
mov [reg_sp],sp ;save sp-2
pop ax
call run
ret
fmem1: mov ah,4ah ;SETBLOCK
xor bx,bx
xchg bx,[newmem] ;ultimate size of DEBUG
or bx,bx
jz fmret ;if we've already shrunk ourselves
int 21h ;shrink DEBUG
fmret: ret
fmem2: mov ax,4c00h ;quit
int 21h
; This is the routine that starts up the running program.
run: call seteq ;set CS:IP to '=' address
mov ah,50h ;set PSP
mov bx,[psp]
int 21h
mov ax,2524h ;set interrupt vector 24h
lds dx,[run2324+4]
int 21h
mov ax,2523h ;set interrupt vector 23h
lds dx,[cs:run2324]
int 21h
push cs ;restore ds
pop ds
mov [run_sp],sp ;save stack position
sub sp,[spadjust]
mov [SPSAV],sp
cli
mov sp,regs
pop ax
pop bx
pop cx
pop dx
pop bp ;we'll get sp later
pop bp
pop si
pop di
pop ds
pop es
pop ss
mov sp,[cs:reg_sp] ;restore program stack
push word [cs:flags]
push word [cs:reg_cs]
push word [cs:reg_ip]
iret ;jump to program
; Interrupt 22 (program termination) handler.
int22: cli
mov word [cs:run_int],progtrm ;remember interrupt type
mov [cs:reg_cs],cs ;put in dummy value for CS:IP
mov word [cs:reg_ip],0
mov word [cs:flags],200h
mov byte [cs:running],0
mov byte [cs:prg_trm],1
jmp intrtn1 ;jump to register saving routine (sort of)
; Interrupt 0 (divide error) handler.
intr0: mov word [cs:run_int],int0msg ;remember interrupt type
jmp intrtn ;jump to register saving routine
; Interrupt 1 (single-step interrupt) handler.
intr1: mov word [cs:run_int],int1msg ;remember interrupt type
jmp intrtn ;jump to register saving routine
; Interrupt 3 (breakpoint interrupt) handler.
intr3: mov word [cs:run_int],int3msg ;remember interrupt type
; Common interrupt routine.
; Housekeeping.
intrtn: cli ;just in case
pop word [cs:reg_ip] ;recover things from stack
pop word [cs:reg_cs]
pop word [cs:flags]
intrtn1:mov [cs:reg_ss],ss ;save stack position
mov [cs:reg_sp],sp
mov sp,cs ;mov ss,cs
mov ss,sp
mov sp,reg_ss
push es
push ds
push di
push si
push bp
dec sp ;we already saved sp
dec sp
push dx
push cx
push bx
push ax
; Clean up.
mov sp,[cs:run_sp] ;restore running stack
sti ;interrupts back on
cld ;clear direction flag
push cs ;reestablish DS
pop ds
mov ax,3523h ;get interrupt vector 23h into ES:BX
int 21h
mov [run2324],bx
mov [run2324+2],es
mov ax,2523h ;set interrupt vector 23h
lds dx,[CCIV]
int 21h
push cs ;reestablish DS
pop ds
mov ax,3524h ;get interrupt vector 24h
int 21h
mov [run2324+4],bx
mov [run2324+6],es
mov ax,2524h ;set interrupt vector 24h
lds dx,[CEIV] ;get original vector from PSP
int 21h
mov ah,50h ;set PSP
mov bx,cs
int 21h
mov ds,bx ;reestablish DS and ES
mov es,bx
and word [flags],~100h ;clear single-step interrupt
; Return.
ret
; The next three subroutines concern the handling of INT 23 and 24.
; These interrupt vectors are saved and restored when running the
; child process, but are not active when DEBUG itself is running.
; It is still useful for the programmer to be able to check where INT 23
; and 24 point, so these values are copied into the interrupt table
; during parts of the c, d, e, m, and s commands, so that they appear
; to be in effect. The e command also copies these values back.
; Between calls to dohack and unhack, there should be no calls to DOS,
; so that there is no possibility of these vectors being used when
; the child process is not running.
; PREHACK - Set up for interrupt vector substitution.
; Entry es = cs
; Exit ds = cs
; Uses si, di.
prehack:cmp byte [hakstat],0
jnz ph_err ;if hack status error |||
mov di,sav2324
prehak1:xor si,si
mov ds,si
mov si,4*23h
movsw
movsw
movsw
movsw
push cs
pop ds
ret
ph_err: push ax
push dx
mov dx,ph_msg
call int21ah9 ;print string |||
pop dx
pop ax
ret
ph_msg db 'Error in sequence of calls to hack.',CR,LF,'$'
; DOHACK - Fake the interrupt vectors 23 and 24.
; UNHACK - Restore interrupt vectors 23 and 24 to their original values.
; It's OK to do either of these twice in a row.
; In particular, the `s' command may do unhack twice in a row.
; Entry ds = cs
; Exit es = cs
; Uses si, di.
dohack: mov byte [hakstat],1
mov si,run2324
jmp hak1
unhack: mov byte [hakstat],0
mov si,sav2324
hak1: xor di,di
mov es,di
mov di,4*23h
movsw
movsw
movsw
movsw
push cs
pop es
ret
; GETLINE - Print a prompt (address in DX, length in CX) and read a line
; of input.
; GETLINE0 - Same as above, but use the output line (so far), plus two
; spaces and a colon, as a prompt.
; GETLINE00 - Same as above, but use the output line (so far) as a prompt.
; Entry CX Length of prompt (getline only)
; DX Address of prompt string (getline only)
;
; DI Address + 1 of last character in prompt (getline0 and
; getline00 only)
;
; Exit AL First nonwhite character in input line
; SI Address of the next character after that
; Uses AH,BX,CX,DX,DI
getline0:
mov ax,' ' ;add two spaces and a colon
stosw
mov al,':'
stosb
getline00:
mov dx,line_out
mov cx,di
sub cx,dx
getline:
mov [promptlen],cx ;save length of prompt
call bufsetup
pushf
mov ah,40h ;write to file
mov bx,1 ;standard output
int 21h
popf
jc gl5 ;if tty input
; This part reads the input line from a file (in the case of
; `debug < file'). It is necessary to do this by hand because DOS
; function 0ah does not handle EOF correctly otherwise. This is
; especially important for debug because it traps Control-C.
gl1: mov cx,[bufend]
sub cx,si ;cx = number of valid characters
jz gl3 ;if none
gl2: lodsb
cmp al,CR
je gl4 ;if end of line
cmp al,LF
je gl4 ;if eol
stosb
loop gl2 ;if there are more valid characters
gl3: call fillbuf
jnc gl1 ;if we have more characters
mov al,LF
cmp di,line_in+LINE_IN_LEN
jb gl4
dec si
dec di
gl4: mov [bufnext],si
mov [notatty],al
mov al,CR
stosb
mov ah,40h ;write to file: print out the received line
mov bx,1
mov cx,di
mov dx,line_in + 2
sub cx,dx
int 21h
jmp gl6 ;done
gl5: mov ah,0ah ;buffered keyboard input
mov dx,line_in
int 21h
gl6: mov ah,2 ;display output
mov dl,LF ;print a line feed afterwards
int 21h
mov si,line_in + 2
call skipwhite
ret
; BUFSETUP - Set up buffer reading. This just means discard an LF
; if the last character read (as stored in `notatty') is CR.
; Entry DI First available byte in input buffer
; Exit SI Address of next character.
; If the input is from a tty, then bufsetup returns with carry set.
bufsetup:
cmp byte [notatty],0
jnz bs1 ;if not a tty
stc
ret
bs1: mov di,line_in+2
mov si,[bufnext]
cmp si,[bufend]
jb bs2 ;if there's a character already
call fillbuf
jc bs4 ;if eof
bs2: cmp byte [notatty],CR
jne bs3 ;if nothing more to do
cmp byte [si],LF
jne bs3 ;if not a line feed
inc si ;skip it
bs3: clc
ret
bs4: jmp qq ;quit: we've hit an eof
; FILLBUF - Fill input buffer. Mostly this is an internal routine
; for getline.
; Entry DI First available byte in input buffer
; Exit SI Next readable byte (i.e., equal to DI)
; Carry flag is set if and only if there is an error (e.g., eof)
; Uses None.
fillbuf:push ax
push bx
push cx
push dx
mov si,di ;we know this already
mov ah,3fh ;read from file
xor bx,bx
mov cx,line_in+LINE_IN_LEN
mov dx,di
sub cx,dx
jz fb1 ;if no more room
int 21h
jc fb1 ;if error
or ax,ax
jz fb1 ;if eof
add ax,dx
clc
jmp fb2
fb1: xchg ax,dx ;ax = last valid byte address + 1
stc
fb2: mov [bufend],ax
pop dx
pop cx
pop bx
pop ax
ret
; PARSECM - Parse command line for C and M commands.
; Entry AL First nonwhite character of parameters
; SI Address of the character after that
; Exit DS:SI Address from first parameter
; ES:DI Address from second parameter
; CX Length of address range minus one
parsecm:push si
call prehack
pop si
mov bx,[reg_ds] ;get source range
xor cx,cx
call getrange
sub cx,dx ;number of bytes minus one
push bx
push dx
push cx
call skipcomm0
mov bx,[reg_ds]
call getaddr ;get destination address
pop cx
mov di,cx
add di,dx
jc errorj7 ;if it wrapped around
call chkeol ;expect end of line
mov di,dx
mov es,bx
pop si
pop ds
ret
errorj7:jmp error
; PARSELW - Parse command line for L and W commands.
;
; Entry AL First nonwhite character of parameters
; SI Address of the character after that
;
; Exit If there is at most one argument (program load/write), then the
; zero flag is set, and registers are set as follows:
; bx:dx Transfer address
;
; If there are more arguments (absolute disk read/write), then the
; zero flag is clear, and registers are set as follows:
;
; DOS versions prior to 3.31:
; AL Drive number
; CX Number of sectors to read
; DX Beginning logical sector number
; DS:BX Transfer address
;
; Later DOS versions:
; AL Drive number
; BX Offset of packet
; CX 0FFFFh
usepacket db 0 ;if the packet is to be used
packet dw 0,0 ;sector number
dw 0 ;number of sectors to read
dw 0,0 ;transfer address
parselw:mov bx,[reg_cs] ;default segment
mov dx,100h ;default offset
cmp al,CR
je plw2 ;if no arguments
call getaddr ;get address
call skipcomm0
cmp al,CR
je plw2 ;if only one argument
push dx
push bx
mov bx,80h ;max number of sectors to read
neg dx
jz plw1 ;if address is zero
mov cl,9
shr dx,cl ;max number of sectors which can be read
mov di,dx
plw1: call getbyte ;get drive number
call skipcomm0
push dx
add dl,'A'
mov [driveno],dl
call getdbl ;get relative sector number
call skipcomm0
push dx
push bx
push si ;in case we find an error
call getword ;get sector count
dec dx
cmp dx,di
jae errorj7 ;if too many sectors
inc dx
mov cx,dx
call chkeol ;expect end of line
cmp byte [usepacket],0
jnz plw3 ;if new-style packet called for
pop si ;in case of error
pop bx ;high bits of sector number
or bx,bx
jnz errorj7 ;if too big
pop dx ;beginning logical sector number
pop ax ;drive number
pop ds ;transfer address
pop bx
or cx,cx ;set nonzero flag
plw2: ret
plw3: pop bx ;discard si
mov bx,packet
pop word [bx+2] ;sector number
pop word [bx]
mov [bx+4],cx ;number of sectors
pop ax ;drive number
pop word [bx+8] ;transfer address
pop word [bx+6]
xor cx,cx
dec cx ;set nonzero flag and make cx = -1
ret
; PARSE_PT - Parse 'p' or 't' command.
; Entry AL First character of command
; SI Address of next character
; Exit CX Number of times to repeat
; Uses AH,BX,CX,DX.
parse_pt:
call parseql ;process =addr
call skipcomm0 ;skip any white space
mov cx,1 ;default count
cmp al,CR
je ppt1 ;if no count given
call getword
call chkeol ;expect end of line here
mov cx,dx
ppt1: call seteq ;make the = operand take effect
ret
; PARSEQL - Parse `=' operand for `g' and `t' commands.
; Entry AL First character of command
; SI Address of next character
; Exit AL First character beyond range
; SI Address of the character after that
; eqflag Nonzero if an `=' operand was present
; eqladdr Address, if one was given
; Uses AH,BX,CX,DX.
parseql:mov byte [eqflag],0 ;mark `=' as absent
cmp al,'='
jne peq1 ;if no `=' operand
call skipwhite
mov bx,[reg_cs] ;default segment
call getaddr ;get the address into bx:dx
mov [eqladdr],dx
mov [eqladdr+2],bx
mov byte [eqflag],1
peq1: ret
; SETEQ - Copy the = arguments to their place, if appropriate. (This
; is not done immediately, because the 'g' command may have a syntax
; error.)
; Uses AX.
seteq: cmp byte [eqflag],0
jz seq2 ;if no `=' operand
mov ax,[eqladdr]
mov [reg_ip],ax
mov ax,[eqladdr+2]
mov [reg_cs],ax
mov byte [eqflag],0 ;clear the flag
mov byte [prg_trm],0;clear 'program terminated' flag, too
seq1: ret
seq2: cmp byte [prg_trm],0
je seq1 ;if program was not already terminated
mov dx,trmerr ;Program has terminated
call int21ah9 ;print string
jmp cmd3 ;quit command
; GETRANGE - Get address range from input line.
; Entry AL First character of range
; SI Address of next character
; BX Default segment to use
; CX Default length to use (or 0 if not allowed)
; Exit AL First character beyond range
; SI Address of the character after that
; BX:DX First address in range
; BX:CX Last address in range
; Uses AH
getrange:
push cx ;save the default length
call getaddr
push si
call skipwh0
cmp al,','
je gr2 ;if an upper bound is given
or al,TOLOWER
cmp al,'l'
je gr3 ;if a range is given
pop si ;restore si and cx
pop cx
jcxz errorj2 ;if a range is mandatory
dec cx
add cx,dx
jnc gr1 ;if no wraparound
mov cx,0ffffh ;go to end of segment
gr1: dec si ;restore al
lodsb
ret
gr2: call skipwhite ;discard the ','
or al,TOLOWER
cmp al,'l'
je gr3 ;if a range is given
call skipwh0 ;get next nonblank
push dx
call getword
mov cx,dx
pop dx
cmp dx,cx
ja errorj2 ;if empty range
jmp gr4
gr3: call skipcomma ;discard the 'l'
push dx
call getword
mov cx,dx
pop dx
jcxz errorj2 ;if zero length
dec cx
add cx,dx
jc errorj2 ;if it wraps around
gr4: add sp,4 ;discard saved cx, si
ret
; GETADDR - Get address from input line.
; Entry AL First character of address
; SI Address of next character
; BX Default segment to use
; Exit AL First character beyond address
; SI Address of the character after that
; BX:DX Address found
; Uses AH,CX
getaddr:mov ah,[si]
or ah,TOLOWER
cmp ah,'s'
jne ga1 ;if not a segment specifier
push di
or al,TOLOWER
mov di,segletrs
mov cx,4
repne scasb
jne errorj2 ;if not a valid segment name
sub di,segletrs+1
shl di,1
mov bx,[reg_ds+di]
pop di
inc si ;skip over 's'
call skipwhite ;get next character
cmp al,':'
jne errorj2 ;expect a colon
jmp ga3 ;get colon and lower part of address
ga1: call getword
push si
call skipwh0
cmp al,':'
je ga2 ;if this is a segment descriptor
pop si
dec si
lodsb
ret
ga2: pop ax ;throw away saved si
mov bx,dx
ga3: call skipwhite ;skip to next word
call getword
ret
errorj2:jmp error
; GETSTR - Get string of bytes. Put the answer in line_out.
; Entry AL first character
; SI address of next character
; Exit [line_out] first byte of string
; DI address of last+1 byte of string
; Uses AX,CL,DL,SI
getstr: mov di,line_out
cmp al,CR
je errorj2 ;we don't allow empty byte strings
gs1: cmp al,"'"
je gs2 ;if string
cmp al,'"'
je gs2 ;ditto
call getbyte
mov [di],dl ;store the byte
inc di
jmp gs6
gs2: mov ah,al ;save quote character
gs3: lodsb
cmp al,ah
je gs5 ;if possible end of string
cmp al,CR
je errorj2 ;if end of line
gs4: stosb ;save character and continue
jmp gs3
gs5: lodsb
cmp al,ah
je gs4 ;if doubled quote character
gs6: call skipcomm0 ;go back for more
cmp al,CR
jne gs1 ;if not done yet
ret
; GETDBL - Get (hex) dword from input line.
; Entry AL first character
; SI address of next character
; Exit BX:DX word
; AL first character not in the word
; SI address of the next character after that
; Uses AH,CL
getdbl: call getnyb
jc errorj2 ;if error
cbw
xchg ax,dx
xor bx,bx ;clear high order word
gd1: lodsb
call getnyb
jc gd3
test bh,0f0h
jnz errorj2 ;if too big
mov cx,4
gd2: shl dx,1 ;double shift left
rcl bx,1
loop gd2
or dl,al
jmp gd1
gd3: ret
; GETWORD - Get (hex) word from input line.
; Entry AL first character
; SI address of next character
; Exit DX word
; AL first character not in the word
; SI address of the next character after that
; Uses AH,CL
getword:call getnyb
jc errorj2 ;if error
cbw
xchg ax,dx
mov cl,4
gw1: lodsb
call getnyb
jc gw2
test dh,0f0h
jnz errorj2 ;if too big
shl dx,cl
or dl,al
jmp gw1
gw2: ret
; GETBYTE - Get (hex) byte from input line.
; Entry AL first character
; SI address of next character
; Exit DL byte
; AL first character not in the word
; SI address of the next character after that
; Uses AH,CL
getbyte:call getnyb
jc errorj2 ;if error
mov dl,al
mov cl,4
gb1: lodsb
call getnyb
jc gb2
test dl,0f0h
jnz errorj8 ;if too big
shl dl,cl
or dl,al
jmp gb1
gb2: ret
; GETNYB - Convert the hex character in AL into a nybble. Return
; carry set in case of error.
getnyb: push ax
sub al,'0'
cmp al,9
jbe gn1 ;if normal digit
pop ax
push ax
or al,TOLOWER
sub al,'a'
cmp al,'f'-'a'
ja gn2 ;if not a-f or A-F
add al,10
gn1: inc sp ;normal return (first pop old AX)
inc sp
clc
ret
gn2: pop ax ;error return
stc
ret
; CHKEOL1 - Check for end of line.
chkeol: call skipwh0
cmp al,CR
jne errorj8 ;if not found
ret
errorj8:jmp error
; SKIPCOMMA - Skip white space, then an optional comma, and more white
; space.
; SKIPCOMM0 - Same as above, but we already have the character in AL.
skipcomma:
lodsb
skipcomm0:
call skipwh0
cmp al,','
jne sc2 ;if no comma
push si
call skipwhite
cmp al,CR
jne sc1 ;if not end of line
pop si
mov al,','
ret
sc1: add sp,2 ;pop si into nowhere
sc2: ret
; SKIPALPHA - Skip alphabetic character, and then white space.
skipalpha:
lodsb
and al,TOUPPER
sub al,'A'
cmp al,'Z'-'A'
jbe skipalpha
dec si
; jmp skipwhite ;(control falls through)
; SKIPWHITE - Skip spaces and tabs.
; SKIPWH0 - Same as above, but we already have the character in AL.
skipwhite:
lodsb
skipwh0:cmp al,' '
je skipwhite
cmp al,TAB
je skipwhite
ret
; IFSEP Compare AL with separators ' ', '\t', ',', ';', '='.
ifsep: cmp al,' '
je ifs1
cmp al,TAB
je ifs1
cmp al,','
je ifs1
cmp al,';'
je ifs1
cmp al,'='
ifs1: ret
; Here is the start of the disassembly part of the program.
; Jump table for OP_IMM, OP_RM, OP_M, OP_R_MOD, OP_MOFFS, OP_R, OP_R_ADD,
; and OP_AX.
disjmp2 dw dop01,dop04,dop29,dop29a,dop30,dop32,dop36,dop37
optab dw dop38,dop38a,dop38b,dop39,dop42,dop41 ;jump table
dw dop43,dop46,dop47,dop49,dop51,dop52
dw dop53,dop54,dop56,dop58,dop59,dop59e,dop60
db '1',0,'3',0,'DXCLSTCSDSESFSGSSS' ;simple strings
OP_STR equ OP_1 ;first string entry
; DISASM - Disassemble.
dis_n dw 0 ;number of bytes in instruction so far
preflags db 0 ;flags for prefixes found so far
preused db 0 ;flags for prefixes used so far
PRESEG equ 1 ;segment prefix
PREREP equ 2 ;rep prefixes
PREREPZ equ 4 ;f3, not f2
PRELOCK equ 8 ;lock prefix
PRE32D equ 10h ;flag for 32-bit data
PRE32A equ 20h ;flag for 32-bit addressing
PREWAIT equ 40h ;prefix wait (not really a prefix)
GOTREGM equ 80h ;set if we have the reg/mem part
instru db 0 ;the main instruction byte
index dw 0 ;index of the instruction (unsqueezed)
dw SFPGROUP3, SFPGROUP3+1, SFPGROUP3+4
dw SPARSE_BASE+24h, SPARSE_BASE+26h ;obsolete-instruction values
rmsize db 0 ;<0 or 0 or >0 means mod r/m is 8 or 16 or 32
segmnt db 0 ;segment determined by prefix (or otherwise)
addrr dw 0 ;address in mod r/m byte
savesp2 dw 0 ;save the stack pointer here (used in disasm)
disflags db 0 ;flags for the disassembler
;equates for disflags:
DIS_F_REPT equ 1 ;repeat after pop ss, etc.
DIS_F_SHOW equ 2 ;show memory contents
DIS_I_SHOW equ 4 ;there are memory contents to show
DIS_I_UNUSED equ 8 ;(internal) print " (unused)"
DIS_I_SHOWSIZ equ 10h ;(internal) always show the operand size
DIS_I_KNOWSIZ equ 20h ;(internal) we know the operand size of instr.
disflags2 db 0 ;another copy of DIS_I_KNOWSIZ
sizeloc dw 0 ;address of size words in output line
; Jump table for a certain place.
disjmp dw disbad ;illegal instruction
dw da6 ;two byte instruction
dw da7 ;instruction group
dw da8 ;coprocessor instruction
dw da9 ;coprocessor instruction group
dw da10 ;instruction prefix
; Table for 16-bit mod r/m addressing. 8 = BX, 4 = BP, 2 = SI, 1 = DI.
rmtab db 8+2, 8+1, 4+2, 4+1, 2, 1, 4, 8
; Tables of register names.
; rgnam816/rgnam16/segrgnam/xregnam must be consecutive.
rgnam816 dw 'AL','CL','DL','BL','AH','CH','DH','BH'
rgnam16 dw 'AX','CX','DX','BX','SP','BP','SI','DI'
segrgnam dw 'ES','CS','SS','DS','FS','GS'
xregnam dw 'ST','MM','CR','DR','TR'
sizetcnam dw 'BY','WO','WO','DW','QW','FL','DO','TB','SH','LO','NE','FA'
segrgaddr dw reg_es,reg_cs,reg_ss,reg_ds
; Tables for handling of named prefixes.
prefixlist db 26h,2eh,36h,3eh,64h,65h ;segment prefixes (in order)
db 9bh,0f0h,0f2h,0f3h ;WAIT,LOCK,REPNE,REPE
prefixmnem dw MNEM_WAIT,MNEM_LOCK,MNEM_REPNE,MNEM_REPE
disasm: mov [savesp2],sp
mov word [dis_n],0
mov word [preflags],0 ;clear preflags and preused
mov byte [segmnt],3 ;initially use DS segment
mov byte [rmsize],80h ;don't display any memory
mov word [dismach],0 ;no special machine needed, so far
call disgetbyte ;get a byte of the instruction
cmp al,9bh ;wait instruction (must be the first prefix)
jne da2 ;if not
; The wait instruction is actually a separate instruction as far as
; the x86 is concerned, but we treat it as a prefix since there are
; some mnemonics that incorporate it. But it has to be treated specially
; since you can't do, e.g., seg cs wait ... but must do wait seg cs ...
; instead. We'll catch it later if the wait instruction is not going to
; be part of a shared mnemonic.
or byte [preflags],PREWAIT
; If we've found a prefix, we return here for the actual instruction
; (or another prefix).
da1: call disgetbyte
da2: mov [instru],al ;save away the instruction
mov ah,0
; Now we have the sequence number of the instruction in AX. Look it up.
da3: mov bx,ax
mov [index],ax ;save the compressed index
cmp ax,SPARSE_BASE
jb da4 ;if it's not from the squeezed part of the table
mov bl,[sqztab+bx-SPARSE_BASE]
mov bh,0
add bx,SPARSE_BASE ;bx = compressed index
da4: mov cl,[optypes+bx] ;cx = opcode type
mov ch,0
shl bx,1
mov bx,[opinfo+bx] ;bx = other info (usually the mnemonic)
mov si,cx
mov ax,bx
mov cl,12
shr ax,cl
cmp al,[dismach]
jb da5 ;if a higher machine is already required
mov [dismach],al ;set machine type
da5: and bx,0fffh ;remove the machine field
cmp si,OPTYPES_BASE
jae da13 ;if this is an actual instruction
call [disjmp+si] ;otherwise, do more specific processing
jmp da3 ;back for more
; Two-byte instruction.
da6: call disgetbyte
mov [instru],al
mov ah,0
add ax,SPARSE_BASE
ret
; Instruction group.
da7: call getregmem_r ;get the middle 3 bits of the R/M byte
cbw
add ax,bx ;offset
ret
; Coprocessor instruction.
da8: or byte [disflags],DIS_I_SHOWSIZ
or byte [dmflags],DM_COPR
call getregmem
cmp al,0c0h
jb da7 ;range 00-bfh is same as an instruction group
mov cl,3
shr al,cl ;C0h --> 18h
sub al,18h-8 ;18h --> 8
cbw
add ax,bx ;offset
ret
; Coprocessor instruction group.
da9: mov al,[regmem]
and al,7
cbw
add ax,bx
ret
; Instruction prefix. At this point, bl = prefix bits; bh = segment
da10: test bl,[preflags]
jnz da12 ;if there are duplicates
or [preflags],bl
test bl,PRESEG
jz da11 ;if not a segment
mov [segmnt],bh ;save the segment
da11: pop ax ;discard return address
jmp da1
da12: jmp disbad ;we don't allow duplicate prefixes
; OK. Here we go. This is an actual instruction.
; First print the op mnemonic.
da13: push si
lea si,[mnlist+bx] ;offset of mnemonic
cmp si,mnlist+MNEM_BSWAP
jne da13a ;if not BSWAP
call dischk32d
jz da12 ;if no operand-size prefix
da13a: call showop ;print out the op code (at line_out+24)
mov word [sizeloc],0 ;clear out this flag
pop si ;recover list of operands
add si,oplists-OPTYPES_BASE
cmp byte [si],0
je da21 ;if we're done
; Loop over operands. [si] = pointer to next operand type.
; Fortunately the operands appear in the instruction in the same
; order as they appear in the disassembly output.
da14: mov byte [disflags2],0 ;clear out size-related flags
lodsb ;get the operand type
cmp al,OP_SIZE
jb da18 ;if it's not size dependent
mov byte [disflags2],DIS_I_KNOWSIZ ;indicate variable size
cmp al,OP_8
jae da16 ;if the size is fixed
cmp al,OP_1632
jae da15 ;if word or dword
mov ah,-1
test byte [instru],1
jz da17 ;if byte
da15: or byte [preused],PRE32D ;mark this flag as used
mov ah,[preflags]
and ah,PRE32D ;this will be >0 for dword, =0 for word
jmp da17 ;done
da16: mov ah,al ;OP_8 or OP_16 or OP_32 (we know which)
and ah,0f0h ;this converts ah to <0 for byte, =0 for word,
sub ah,OP_16 ;and >0 for dword
; Now we know the size (in ah); branch off to do the operand itself.
da17: mov bl,al
and bx,0fh
call [disjmp2+bx] ;print out the operand
jmp da20 ;done with operand
; Sizeless operands.
da18: cbw
xchg ax,bx
cmp bl,OP_STR
jb da19 ;if it's not a string
mov ax,[optab+bx-2]
stosw
cmp ah,0
jnz da20 ;if it's two characters
dec di
jmp da20 ;done with operand
da19: call [optab+bx-2] ;otherwise, do something else
da20: cmp byte [si],0
jz da21 ;if we're done
mov al,','
stosb
jmp da14 ;another operand
da21: mov al,[preused]
not al
and al,[preflags]
jnz da22 ;if some flags remain unused
jmp da28 ;if all flags were used
da22: mov cx,N_WTAB
mov bx,wtab1
mov dx,2*N_WTAB-2
mov ah,PREWAIT
test al,ah
jnz da23 ;if there's a WAIT prefix hanging
mov cx,N_LTAB
mov bx,ltab1
mov dx,2*N_LTAB-2
mov ah,PRE32D
test al,ah
jz da24 ;if it's not a 32-bit prefix that's hanging
da23: or [preused],ah ;mark this prefix as used
push di
mov di,bx
mov ax,[index]
repne scasw
jne disbad2 ;if not found in the list
add di,dx ;replace the mnemonic with the 32-bit name
mov si,[di]
add si,mnlist
call showop ;copy op mnemonic
pop di
jmp da21
disbad2:jmp disbad
da24: test al,PRESEG
jz da25 ;if not because of a segment prefix
mov ax,[index]
cmp ah,0
jnz disbad2 ;if index > 256
push di
mov cx,P_LEN
mov di,prfxtab
repne scasb
pop di
jne disbad2 ;if it's not on the list
mov cx,3
call moveover
push di
mov di,line_out+24
call showseg
mov al,' '
stosb
pop di
or byte [preused],PRESEG ;mark it as used
jmp da21
da25: test al,PREREP
jz da26 ;if not a REP prefix
and al,PREREP+PREREPZ
or [preused],al
mov ax,[index]
cmp ah,0
jnz disbad2 ;if not in the first 256 bytes
and al,0feh ;clear the low bit
push di
mov di,replist
mov cx,5
repne scasb
mov si,mnlist+MNEM_REP
je da27 ;if one of the REP instructions
inc cx
inc cx
repne scasb
jne disbad2 ;if not one of the REPE/REPNE instructions
mov si,mnlist+MNEM_REPE
test byte [preused],PREREPZ
jnz da27 ;if REPE
mov si,mnlist+MNEM_REPNE
jmp da27 ;it's REPNE
disbad3:jmp disbad
da26: test al,PRELOCK
jz disbad3 ;if not a lock prefix, either
push di
mov ax,[index]
mov di,locktab
mov cx,N_LOCK
repne scasw
jne disbad3 ;if not in the approved list
test byte [preused],PRESEG
jz disbad3 ;if memory was not accessed
mov si,mnlist+MNEM_LOCK
or byte [preused],PRELOCK
; Slip in another mnemonic. SI = offset of mnemonic, what should be
; DI is on the stack.
da27: pop di
mov cx,8
push si
call moveover
pop si
push di
call showop
pop di
jmp da21
; Done with instruction. Erase the size indicator, if appropriate.
da28: mov cx,[sizeloc]
cmp cx,0
jz da28b ;if there was no size given
mov al,[disflags]
test al,DIS_I_SHOWSIZ
jnz da28b ;if we need to show the size
test al,DIS_I_KNOWSIZ
jz da28b ;if the size is not known already
xchg cx,di
mov si,di ;save old di
mov al,' '
da28a: scasb ;skip size name
jne da28a ;if not done yet
;(The above is the same as repne scasb, but
;has no effect on cx.)
add di,4 ;skip 'PTR '
xchg si,di
sub cx,si
rep movsb ;move the line
; Now we're really done. Print out the bytes on the left.
da28b: push di ;print start of disassembly line
mov di,line_out
mov ax,[u_addr+2] ;print address
call hexword
mov al,':'
stosb
mov ax,[u_addr]
call hexword
mov al,' '
stosb
mov bx,[dis_n]
cmp bx,6
jle da29 ;if it's a short instruction
mov bx,6
call disshowbytes
call puts
mov di,line_out
mov bx,[dis_n]
sub bx,6
call disshowbytes
call putsline
mov di,line_out
jmp da30 ;done
da29: call disshowbytes
da30: mov ax,' ' ;pad to op code
mov cx,line_out+24
sub cx,di
shr cx,1
rep stosw
pop di
test byte [disflags],DIS_I_UNUSED
jz da32 ;if we don't print ` (unused)'
mov si,unused
cmp byte [di-1],' '
jne da31 ;if there's already a space here
inc si
da31: call showstring
; Print info. on minimal processor needed.
da32: push di
mov di,index+2
call showmach ;show the machine type, if needed
pop di
jcxz da32f ;if no message
; Print a message on the far right.
mov ax,line_out+79
sub ax,cx
push cx
call tab_to ;tab out to the location
pop cx
rep movsb ;copy the string
jmp da32z ;done
; Dump referenced memory location.
da32f: mov al,[disflags]
xor al,DIS_F_SHOW + DIS_I_SHOW
test al,DIS_F_SHOW + DIS_I_SHOW
jnz da32z ;if there is no memory location to show
cmp byte [segmnt],3
ja da32z ;if FS or GS
mov ax,line_out+79-10
cmp byte [rmsize],0
jl da32h ;if byte
jz da32g ;if word
sub ax,4
da32g: dec ax
dec ax
da32h: call tab_to
call showseg ;show segment name
mov al,':'
stosb
mov ax,[addrr]
call hexword ;show offset
mov al,'='
stosb
mov al,[segmnt] ;segment number
cbw
shl ax,1
xchg ax,bx ;mov bx,ax
mov bx,[segrgaddr+bx] ;get address of value
mov es,[bx]
mov bx,[addrr]
mov ax,[es:bx]
mov dx,[es:bx+2]
push cs ;restore es
pop es
cmp byte [rmsize],0
jl da32j ;if byte
jz da32i ;if word
xchg ax,dx
call hexword
xchg ax,dx
da32i: call hexword
jmp da32z ;done
da32j: call hexbyte ;display byte
da32z: call trimputs ;done with operand list
mov al,[disflags]
test al,DIS_F_REPT
jz da34 ;if we're not allowed to repeat ourselves
test al,DIS_I_UNUSED
jnz da33 ;if we printed ` (unused)'
mov ax,[index]
cmp ax,17h
je da33 ;if it was `pop ss'
cmp ax,8eh
je da33 ;if it was `mov ss,--'
cmp ax,0fbh
jne da34 ;if it was not `sti'
da33: mov byte [disflags],0
jmp disasm
da34: ret
; Here are the routines for printing out the operands themselves.
; Immediate data (OP_IMM)
dop01: cmp ah,0
jl dop03 ;if just a byte
pushf
test byte [disflags],DIS_I_SHOWSIZ
jz dop01a ;if we don't need to show the size
call showsize
sub di,4 ;erase "PTR "
dop01a: call disgetword
popf
jz dop02 ;if just a word
push ax
call disgetword ;print the high order word
call hexword
pop ax
dop02: call hexword
ret
dop03: call disgetbyte ;print immediate byte
call hexbyte
ret
; MOD R/M (OP_RM)
dop04: call getregmem
cmp al,0c0h
jb dop05
jmp dop33 ;if pure register reference
dop05: call showsize ;print out size
dop06: or byte [preused],PRESEG;needed even if there's no segment override
;because handling of LOCK prefix relies on it
test byte [preflags],PRESEG
jz dop07 ;if no segment override
call showseg ;print segment name
mov al,':'
stosb
dop07: mov al,[regmem]
and al,0c7h
or byte [preused],PRE32A
test byte [preflags],PRE32A
jz dop08
jmp dop18 ;if 32-bit addressing
dop08: or byte [disflags],DIS_I_SHOW ;we'd like to show this address
mov word [addrr],0 ;zero out the address initially
cmp al,6
xchg ax,bx ;mov bx,ax
mov al,'['
stosb
je dop16 ;if [xxxx]
and bx,7
mov bl,[rmtab+bx]
test bl,8
jnz dop09 ;if BX
test bl,4
jz dop11 ;if not BP
mov ax,'BP'
mov cx,[reg_bp]
test byte [preflags],PRESEG
jnz dop10 ;if segment override
dec byte [segmnt] ;default is now SS
jmp dop10
dop09: mov ax,'BX' ;BX
mov cx,[reg_bx]
dop10: mov [addrr],cx ;print it out, etc.
stosw
test bl,2+1
jz dop13 ;if done
mov al,'+'
stosb
dop11: mov ax,'SI'
mov cx,[reg_si]
test bl,1
jz dop12 ;if SI
mov al,'D' ;DI
mov cx,[reg_di]
dop12: add [addrr],cx ;print it out, etc.
stosw
dop13: test byte [regmem],0c0h
jz dop17 ;if no displacement
test byte [regmem],80h
jnz dop15 ;if word displacement
call disgetbyte
cbw
add [addrr],ax
cmp al,0
mov ah,'+'
jge dop14 ;if >= 0
mov ah,'-'
neg al
dop14: mov [di],ah
inc di
call hexbyte ;print the byte displacement
jmp dop17 ;done
dop15: mov al,'+'
stosb
dop16: call disgetword
add [addrr],ax
call hexword
dop17: mov al,']'
stosb
ret
; 32-bit MOD REG R/M addressing.
dop18: cmp al,5
jne dop19 ;if not just a disp32 address
mov al,'['
stosb
call disp32
jmp dop27
dop19: push ax
and al,7
cmp al,4
jne dop20 ;if no SIB
call disgetbyte ;get and save it
mov [sibbyte],al
dop20: pop ax
test al,80h
jnz dop22 ;if disp32
test al,40h
jz dop23 ;if no disp8
call disgetbyte
cmp al,0
jge dop21 ;if >= 0
neg al
mov byte [di],'-'
inc di
dop21: call hexbyte
jmp dop23 ;done
dop22: call disp32 ;print disp32
dop23: mov al,[regmem]
and al,7
cmp al,4
jne dop28 ;if no SIB
mov al,[sibbyte]
and al,7
cmp al,5
jne dop24 ;if not [EBP]
test byte [regmem],0c0h
jnz dop24 ;if MOD != 0
call disp32 ;show 32-bit displacement instead of [EBP]
jmp dop25
dop24: mov word [di],'[E'
inc di
inc di
call showreg16
mov al,']'
stosb
dop25: mov al,[sibbyte]
shr al,1
shr al,1
shr al,1
and al,7
cmp al,4
je disbad1 ;if illegal
mov word [di],'[E'
inc di
inc di
call showreg16
mov ah,[sibbyte]
test ah,0c0h
jz dop27 ;if SS = 0
mov al,'*'
stosb
mov al,'2'
test ah,80h
jz dop26 ;if *2
mov al,'4'
test ah,40h
jz dop26 ;if *4
mov al,'8'
dop26: stosb
dop27: mov al,']'
stosb
ret
; 32-bit addressing without SIB
dop28: mov word [di],'[E'
inc di
inc di
call showreg16
mov al,']'
stosb
ret
; Memory-only reference (OP_M)
dop29: call getregmem
cmp al,0c0h
jae disbad1 ;if it's a register reference
jmp dop05
disbad1:jmp disbad ;this is not supposed to happen
; Register reference from MOD R/M part (OP_R_MOD)
dop29a: call getregmem
cmp al,0c0h
jb disbad1 ;if it's a memory reference
jmp dop33
; Memory offset reference (OP_MOFFS)
dop30: call showsize ;print the size and save various things
mov al,5
test byte [preflags],PRE32A
jnz dop31 ;if 32-bit addressing
inc ax
dop31: mov [regmem],al
jmp dop06
; Pure register reference (OP_R)
dop32: call getregmem_r
dop33: and al,7 ;entry point for regs from MOD R/M, and others
mov cl,[disflags2]
or [disflags],cl ;if it was variable size operand, the size
;should now be marked as known.
cmp ah,0
jl dop35 ;if byte register
jz dop34 ;if word register
dop33a: mov byte [di],'E' ;enter here from OP_ECX
inc di
dop34: add al,8
dop35: cbw
shl ax,1
xchg ax,bx ;mov bx,ax
mov ax,[rgnam816+bx] ;get the register name
stosw
ret
; Register number embedded in the instruction (OP_R_ADD)
dop36: mov al,[instru]
jmp dop33
; AL or AX or EAX (OP_AX)
dop37: mov al,0
jmp dop33
; QWORD mem (OP_M64).
dop38: mov ax,'Q' ;print 'QWORD'
jmp dop40
; FLOAT mem (OP_MFLOAT).
dop38a: mov ax,'FL'
stosw
mov al,'O'
stosb
mov ax,'AT'
jmp dop38c
; DOUBLE mem (OP_MDOUBLE).
dop38b: mov ax,'DO'
stosw
mov ax,'UB'
stosw
mov ax,'LE'
dop38c: stosw
call showptr
jmp dop42a
; TBYTE mem (OP_M80).
dop39: mov ax,0ff00h+'T' ;print 'tbyte'
dop40: stosb
call getregmem
cmp al,0c0h
jae disbad1 ;if it's a register reference
and byte [disflags],~DIS_F_SHOW ;don't show this
jmp dop05
; far memory (OP_FARMEM).
dop41: call dischk32d
jz dop41a ;if not dword far
call showdwd
sub di,4 ;erase "PTR "
dop41a: mov ax,'FA' ;store "FAR "
stosw
mov ax,'R '
stosw
; mem (OP_MXX).
dop42: and byte [disflags],~DIS_F_SHOW ;don't show this
dop42a: call getregmem
cmp al,0c0h
jae disbad5 ;if it's a register reference
jmp dop06
disbad5:jmp disbad
; far pointer (OP_FARP).
dop43: call disgetword
push ax
call dischk32d
jz dop44 ;if not 32-bit address
call disgetword
push ax
dop44: call disgetword
call hexword
mov al,':'
stosb
call dischk32d
jz dop45 ;if not 32-bit address
pop ax
call hexword
dop45: pop ax
call hexword
ret
; 8-bit relative jump (OP_REL8)
dop46: call disgetbyte
cbw
jmp dop48
; 16/32-bit relative jump (OP_REL1632)
dop47: call disgetword
call dischk32d
jz dop48 ;if not 32-bit offset
push ax
call showdwd
sub di,4 ;erase "PTR "
pop dx
call disgetword
mov bx,[u_addr]
add bx,[dis_n]
add dx,bx
adc ax,0 ;this would normally be the upper word of IP
call hexword
xchg ax,dx
jmp hexword ;call hexword and return
dop48: add ax,[u_addr]
add ax,[dis_n]
jmp hexword ;call hexword and return
; Check for ST(1) (OP_1CHK).
dop49: pop ax ;discard return address
mov al,[regmem]
and al,7
cmp al,1
je dop50 ;if it's ST(1)
jmp da14 ;another operand (but no comma)
dop50: jmp da21 ;end of list
; ST(I) (OP_STI).
dop51: mov al,[regmem]
and al,7
xchg ax,bx ;mov bx,ax
mov ax,'ST'
stosw ;store ST(bl)
mov al,'('
stosb
mov ax,'0)'
or al,bl
stosw
ret
; CRx (OP_CR).
dop52: mov bx,'CR'
call getregmem_r
cmp al,4
ja disbad4 ;if too large
jne dop52a
mov byte [dismach],5 ;CR4 is new to the 586
dop52a: cmp word [index],SPARSE_BASE+22h
jne dop55 ;if not MOV CRx,xx
cmp al,1
jne dop55 ;if not CR1
disbad4:jmp disbad ;can't MOV CR1,xx
; DRx (OP_DR).
dop53: call getregmem_r
mov bx,'DR'
mov cx,-1 ;no max or illegal value
jmp dop55
; TRx (OP_TR).
dop54: call getregmem_r
cmp al,3
jb disbad ;if too small
cmp al,6
jae dop54a ;if TR6-7
mov byte [dismach],4 ;TR3-5 are new to the 486
dop54a: mov bx,'TR'
dop55: xchg ax,bx
stosw ;store XX
xchg ax,bx
or al,'0'
stosb
ret
; Segment register (OP_SEGREG).
dop56: call getregmem_r
cmp al,6
jae disbad ;if not a segment register
cmp al,2
je dop57 ;if SS
and byte [disflags],~DIS_F_REPT ;clear flag: don't repeat
dop57: cmp al,4
jb dop57a ;if not FS or GS
mov byte [dismach],3;(no new 486-686 instructions involve seg regs)
dop57a: add al,16
jmp dop35 ;go print it out
; Sign-extended immediate byte (OP_IMMS8).
dop58: call disgetbyte
cmp al,0
xchg ax,bx ;mov bl,al
mov al,'+'
jge dop58a ;if >= 0
neg bl
mov al,'-'
dop58a: stosb
xchg ax,bx ;mov al,bl
jmp dop59a ;call hexbyte and return
; Immediate byte (OP_IMM8).
dop59: call disgetbyte
dop59a: jmp hexbyte ;call hexbyte and return
; Show ECX if it's a 32-bit operand.
dop59e: call dischk32d
jz dop60a ;if not 32 bit instruction
mov al,1
jmp dop33a ;print out register ECX and return
; Set flag to always show size (OP_SHOSIZ).
dop60: or byte [disflags],DIS_I_SHOWSIZ
dop60a: pop ax ;discard return address
jmp da14 ;next...
disbad: mov sp,[savesp2] ;pop junk off stack
mov word [dis_n],0
mov word [preflags],0 ;clear preflags and preused
mov byte [rmsize],80h ;don't display any memory
mov word [dismach],0;forget about the machine type
and byte [disflags],~DIS_I_SHOW ;and flags
call disgetbyte
mov di,prefixlist
mov cx,10
repne scasb
je dbad1 ;if it's a named prefix
dec word [dis_n]
mov bx,MNEM_DB ;offset of 'DB' mnemonic
mov si,OPLIST_Z ;this says OP_8+OP_IMM
jmp da13
dbad1: or byte [disflags],DIS_I_UNUSED ;print special flag
mov bx,9
sub bx,cx
shl bx,1
cmp bx,12
jb dbad2 ;if SEG directive
mov bx,[prefixmnem+bx-12]
mov si,OPTYPES_BASE
jmp da13
dbad2: lea si,[bx+OPLIST_ES]
mov bx,MNEM_SEG
jmp da13
; GETREGMEM_R - Get the reg part of the reg/mem part of the instruction
; Uses CL
getregmem_r:
call getregmem
mov cl,3
shr al,cl
and al,7
ret
; GETREGMEM - Get the reg/mem part of the instruction
getregmem:
test byte [preused],GOTREGM
jnz grm1 ;if we have it already
or byte [preused],GOTREGM
call disgetbyte ;get the byte
mov [regmem],al ;save it away
grm1: mov al,[regmem]
ret
; SHOWOP Show the op code
; Entry SI Null-terminated string containing the op mnemonic
; Exit DI Address of next available byte in output line
; (>= offset line_out + 32 due to padding)
; Uses AL
showop:
mov di,line_out+24
call showstring
mov al,' '
so1: stosb
cmp di,line_out+32
jb so1
ret
; SHOWSEG - Show the segment descriptor in SEGMNT
; Entry DI Where to put it
; Exit DI Updated
; Uses AX, BX
showseg:
mov al,[segmnt] ;segment number
cbw
shl ax,1
xchg ax,bx ;mov bx,ax
mov ax,[segrgnam+bx] ;get register name
stosw
ret
; SHOWSIZE - Print a description of the size
; Entry AH >0 for DWORD, =0 for WORD, <0 for BYTE
; Uses AX
; SHOWPTR - Print " PTR "
; Uses AX
; SHOWDWD - Print "DWORD PTR"
; Uses AX
showsize:
mov [rmsize],ah ;save r/m size
mov [sizeloc],di ;save where we're putting this
cmp ah,0
jge ssz1 ;if word or dword
mov ax,'BY'
stosw
mov ax,'TE'
jmp ssz3
ssz1: je ssz2 ;if word
showdwd:mov al,'D'
stosb
ssz2: mov ax,'WO'
stosw
mov ax,'RD'
ssz3: stosw
showptr:mov ax,' P'
stosw
mov ax,'TR'
stosw
mov al,' '
stosb
ret
; DISP32 - Print 32-bit displacement for addressing modes.
; Entry None
; Exit None
; Uses AX
disp32: call disgetword
push ax
call disgetword
call hexword
pop ax
call hexword
ret
; SHOWREG16 - Show 16-bit register name.
; Entry AL register number (0-7)
; Exit None
; Uses AX
showreg16:
cbw
shl ax,1
xchg ax,bx
push ax
mov ax,[rgnam16+bx]
stosw
pop ax
xchg ax,bx
ret
; SHOWMACH - Return string "[needs math coprocessor]", etc.
; Exit si Address of string
; cx Length of string, or 0 if not needed
; Uses al, di
showmach:
mov si,needsmsg ;candidate message
test byte [dmflags],DM_COPR
jz sm1 ;if not a coprocessor instruction
mov byte [si+9],'7' ;change message text
mov al,[mach_87]
cmp byte [has_87],0
jnz sm2 ;if it has a coprocessor
mov al,[machine]
cmp al,[dismach]
jb sm3 ;if we display the message
mov si,needsmath ;print this message instead
mov cx,needsmath_L
ret
sm1: mov byte [si+9],'6' ;reset message text
mov al,[machine]
sm2: cmp al,[dismach]
jae sm4 ;if no message (so far)
sm3: mov al,[dismach]
add al,'0'
mov [si+7],al
mov cx,needsmsg_L ;length of the message
ret
; Check for obsolete instruction.
sm4: mov si,obsolete ;candidate message
mov ax,[di-2] ;get info on this instruction
mov cx,5
repne scasw
jne sm5 ;if no matches
mov di,obsmach + 5 - 1
sub di,cx
xor cx,cx ;clear CX: no message
mov al,[mach_87]
cmp al,[di]
jle sm5 ;if this machine is OK
mov cx,obsolete_L
sm5: ret
; DISGETBYTE - Get byte for disassembler.
; Entry None
; Exit AL Next byte in instruction stream
; Uses None
disgetbyte:
push si ;save si
lds si,[u_addr]
add si,[cs:dis_n] ;index to the right byte
lodsb ;get the byte
pop si ;restore things
push cs
pop ds
inc word [dis_n] ;indicate that we've gotten this byte
ret
; DISGETWORD - Get word for disassembler.
; Entry None
; Exit AX Next word
; Uses None
disgetword:
push si ;save si
lds si,[u_addr]
add si,[cs:dis_n] ;index to the right byte
lodsw ;get the byte
pop si ;restore things
push cs
pop ds
add word [dis_n],2 ;indicate that we've gotten this byte
ret
; DISSHOWBYTES - Show bytes for the disassembler.
; Entry BX Number of bytes (must be > 0)
; Exit u_addr updated
; Uses BX, SI.
disshowbytes:
lds si,[u_addr]
dsb1: lodsb
call hexbyte
dec bx
jnz dsb1
push cs
pop ds
mov [u_addr],si
ret
; MOVEOVER - Move the line to the right.
; Entry DI Last address + 1 of line so far
; Exit CX Number of bytes to move
; DI Updated
; Uses SI
moveover:
cmp word [sizeloc],0
je mo1 ;if sizeloc not saved
add [sizeloc],cx
mo1: mov si,di
add di,cx
mov cx,di
sub cx,line_out+24
push di
std
dec si
dec di
rep movsb
pop di
cld
ret
; DISCHK32D - Check for 32 bit operand size prefix.
dischk32d:
or byte [preused],PRE32D
test byte [preflags],PRE32D
ret
; DUMPREGS - Dump registers.
dumpregs:mov si,regs
mov bx,regnames
mov di,line_out
mov cx,8
call dmpr1 ;print first row
push bx
call trimputs
pop bx
mov di,line_out
mov cl,5
call dmpr1
mov al,' ' ;add a space
stosb
call dmpflags
call trimputs
mov ax,[reg_ip]
mov di,u_addr
stosw
mov ax,[reg_cs]
stosw
mov byte [disflags],DIS_F_REPT | DIS_F_SHOW
call disasm
mov ax,[reg_ip]
mov [u_addr],ax
ret
; Function to print multiple register entries.
dmpr1: mov ax,[bx]
inc bx
inc bx
stosw
mov al,'='
stosb
lodsw
push cx
call hexword
pop cx
mov ax,' '
stosw
loop dmpr1
ret
; DMPFLAGS - Dump flags output.
dmpflags:
mov bx,[flags]
mov si,flgbits
mov cx,8
dmpf1: mov ax,[si+16]
test bx,[si]
jz dmpf2 ;if not asserted
mov ax,[si+32]
dmpf2: stosw
mov al,' '
stosb
inc si
inc si
loop dmpf1
ret
flgbits dw 800h,400h,100h,80h,40h,10h,4,1
flgnams dw 'NV','UP','DI','PL','NZ','NA','PO','NC'
flgnons dw 'OV','DN','EI','NG','ZR','AC','PE','CY'
; SHOWSTRING - Print nonempty null-terminated string.
showstring:
lodsb
sstr1: stosb
lodsb
cmp al,0
jne sstr1
ret
; HEXWORD - Print hex word (in AX).
; HEXBYTE - Print hex byte (in AL).
; HEXNYB - Print hex digit.
; Uses al,cl.
hexword:
push ax
mov al,ah
call hexbyte
pop ax
hexbyte:
push ax
mov cl,4
shr al,cl
call hexnyb
pop ax
hexnyb:
and al,0fh
add al,90h ;these four instructions change to ascii hex
daa
adc al,40h
daa
stosb
ret
; TAB_TO - Space fill until reaching the column indicated by AX.
; (Print a new line if necessary.)
tab_to: push ax
sub ax,di
ja tabto1 ;if there's room on this line
call trimputs
mov di,line_out
tabto1: pop cx
sub cx,di
mov al,' '
rep stosb ;space fill to the right end
ret
; TRIMPUTS - Trim excess blanks from string and print (with CR/LF).
; PUTSLINE - Add CR/LF to string and print it.
; PUTS - Print string through DI.
trimputs:
dec di
cmp byte [di],' '
je trimputs
inc di
putsline:
mov ax,LF * 256 + CR
stosw
puts: mov ah,40h ;write to file
mov bx,1
mov cx,di
mov dx,line_out
sub cx,dx
int 21h
ret
; I/O buffers. (End of permanently resident part.)
end1:
line_in db 255,0,CR ;length = 257
line_out equ end1+258 ;length = 1 + 263
real_end equ end1+258+264
staksiz equ 200h
;lots of bytes follow this
;---------------------------------------
; Initialization second phase.
;
; Make this as small as possible, since we can't deallocate the memory.
; Upon entry:
; ax 0
; bx:dx reg_es:100h
; es:di child stack pointer
; interrupts off
;
;---------------------------------------
intwo: sti
push ax ;0 on stack, just in case
stosw ;do the same for the child process
mov byte [line_out-1],'0' ;initialize line_out
push bx
push dx
; Create a PSP
mov ah,55h ;create child PSP
mov dx,es
mov si,[ALASAP] ;memory size field
clc ;works around OS/2 bug
int 21h
push cs ;restore es
pop es
mov ah,50h ;set our PSP
mov bx,cs
int 21h
; Load the program.
pop dx ;restore bx:dx
pop bx
call ll3 ;load the program
jmp cmd3 ;done
;---------------------------------------
; Debug initialization code.
;---------------------------------------
align 2 ;align on word boundary
fp_status dw 5a5ah ;FPU status word
inttab dw intr0 ;table of interrupt initialization stuff
db 0
dw intr1
db 1
dw intr3
db 3
dw debug22
db 22h
imsg1 db 'DEBUG version 0.98. Debugger.',CR,LF,CR,LF
db 'Usage: DEBUG [[drive:][path]progname [arglist]]',CR,LF,CR,LF
db ' progname (executable) file to debug or examine',CR,LF
db ' arglist parameters given to program',CR,LF,CR,LF
db 'For a list of debugging commands, '
db 'run DEBUG and type ? at the prompt.',CR,LF,'$'
imsg2 db 'Invalid switch - '
imsg2a db 'x',CR,LF,'$'
initcode:
cld
mov [execblk+4],cs ;set up parameter block for exec command
mov [execblk+8],cs
mov [execblk+12],cs
; Check for console input vs. input from a file or other device.
mov ax,4400h ;IOCTL--get info
xor bx,bx
int 21h
jc init1 ;if not device
and dl,81h ;check if console device
cmp dl,81h
jne init1 ;if not the console input
mov byte [notatty],0 ;it _is_ a tty
; Check DOS version
init1: mov ax,3000h ;check DOS version
int 21h
xchg al,ah
cmp ax,31fh
jb init2 ;if early, then don't use new INT 25h method
inc byte [usepacket]
; Determine the processor type. This is adapted from code in the
; Pentium<tm> Family User's Manual, Volume 3: Architecture and
; Programming Manual, Intel Corp., 1994, Chapter 5. That code contains
; the following comment:
; This program has been developed by Intel Corporation.
; Software developers have Intel's permission to incorporate
; this source code into your software royalty free.
; Intel 8086 CPU check.
; Bits 12-15 of the FLAGS register are always set on the 8086 processor.
; Probably the 186 as well.
init2: pushf ;get original flags into AX
pop ax
mov cx,ax ;save them
and ax,0fffh ;clear bits 12-15
push ax ;save new flags value on stack
popf ;replace current flags value
pushf ;get new flags
pop ax ;store new flags in AX
and ax,0f000h ;check to see whether bits 12-15 are set
cmp ax,0f000h
je init6 ;if 8086 or 80186 (can't tell them apart)
; Intel 286 CPU check.
; Bits 12-15 of the flags register are always clear on the
; Intel 286 processor in real-address mode.
or cx,0f000h ;try to set bits 12-15
push cx ;save new flags value on stack
popf ;replace current flags value
pushf ;get new flags
pop ax ;store new flags in AX
test ax,0f000h ;if bits 12-15 clear, CPU = 80286
mov byte [machine],2
jz init6 ;if 80286
; Intel 386 CPU check.
; The AC bit, bit #18, is a new bit introduced in the EFLAGS
; register on the Intel486 DX cpu to generate alignment faults.
; This bit cannot be set on the Intel386 CPU.
; It is now safe to use 32-bit opcode/operands.
cpu 386
inc byte [machine]
mov bx,sp ;save current stack pointer to align
and sp,~3 ;align stack to avoid AC fault
pushfd ;push original EFLAGS
pop eax ;get original EFLAGS
mov ecx,eax ;save original EFLAGS in CX
xor eax,40000h ;flip (XOR) AC bit in EFLAGS
push eax ;put new EFLAGS value on stack
popfd ;replace EFLAGS value
pushfd ;get new EFLAGS
pop eax ;store new EFLAGS value in EAX
cmp eax,ecx
jz init5 ;if 80386 CPU
; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check.
; Checking for ability to set/clear ID flag (bit 21) in EFLAGS
; which indicates the presence of a processor with the ability
; to use the CPUID instruction.
inc byte [machine] ;it's a 486
mov eax,ecx ;get original EFLAGS
xor eax,200000h ;flip (XOR) ID bit in EFLAGS
push eax ;save new EFLAGS value on stack
popfd ;replace current EFLAGS value
pushfd ;get new EFLAGS
pop eax ;store new EFLAGS in EAX
cmp eax,ecx ;check if it's changed
je init5 ;if it's a 486 (can't toggle ID bit)
push ecx
popfd ;restore AC bit in EFLAGS first
mov sp,bx ;restore original stack pointer
; Execute CPUID instruction.
cpu 586
xor eax,eax ;set up input for CPUID instruction
cpuid
cmp eax,1
jl init6 ;if 1 is not a valid input value for CPUID
xor eax,eax ;otherwise, run CPUID with ax = 1
inc eax
cpuid
mov al,ah
and al,0fh ;bits 8-11 are the model number
cmp al,6
jbe init3 ;if <= 6
mov al,6 ;if > 6, set it to 6
init3: mov [machine],al ;save it
jmp init6 ;don't restore SP
init5: push ecx
popfd ;restore AC bit in EFLAGS first
mov sp,bx ;restore original stack pointer
cpu 8086 ;back to 1980s technology
; Next determine the type of FPU in a system and set the mach_87
; variable with the appropriate value. All registers are used by
; this code; none are preserved.
; Coprocessor check.
; The algorithm is to determine whether the floating-point
; status and control words can be written to. If not, no
; coprocessor exists. If the status and control words can be
; written to, the correct coprocessor is then determined
; depending on the processor ID. The Intel386 CPU can
; work with either an Intel 287 NDP or an Intel387 NDP.
; The infinity of the coprocessormust be checked
; to determine the correct coprocessor ID.
init6: mov al,[machine]
mov [mach_87],al ;by default, set mach_87 to machine
fninit ;reset FP status word
mov word [fp_status],5a5ah ;restore temp word to nonzero value
fnstsw [fp_status] ;save FP status word
mov ax,[fp_status] ;check FP status word
cmp al,0
jne init7 ;if no FPU present
fnstcw [fp_status] ;save FP control word
mov ax,[fp_status] ;check FP control word
and ax,103fh ;see if selected parts look OK
cmp ax,3fh
jne init7 ;if no FPU present
inc byte [has_87] ;there's an FPU
; If we're using a 386, check for 287 vs. 387 by checking whether
; +infinity = -infinity.
cmp byte [machine],3
jne init7 ;if not a 386
fld1 ;must use default control from FNINIT
fldz ;form infinity
fdivp ST1 ;1 / 0 = infinity
fld ST0 ;form negative infinity
fchs
fcompp ;see if they are the same and remove them
fstsw [fp_status] ;look at status from FCOMPP
mov ax,[fp_status]
sahf
jnz init7 ;if they are different, then it's a 387
dec byte [mach_87] ;otherwise, it's a 287
; Interpret switches and erase them from the command line.
init7: mov ax,3700h ;get switch character
int 21h
mov [switchar],dl
cmp dl,'/'
jne init8
mov [swch1],dl
init8: mov si,DTA+1
init9: lodsb
cmp al,' '
je init9
cmp al,TAB
je init9
; Process the /? switch (or the [switchar]? switch).
; If switchar != / and /? occurs, make sure nothing follows.
cmp al,dl
je init11 ;if switch character
cmp al,'/'
jne init12 ;if not the help switch
mov al,[si]
cmp al,'?'
jne init12 ;if not /?
mov al,[si+1]
cmp al,' '
je init10 ;if nothing after /?
cmp al,TAB
je init10 ;ditto
cmp al,CR
jne init12 ;if not end of line
; Print a help message
init10: mov dx,imsg1 ;command-line help message
call int21ah9 ;print string
int 20h ;done
; Do the (proper) switches.
init11: lodsb
cmp al,'?'
je init10 ;if -?
; ||| Other switches may go here.
mov [imsg2a],al
mov dx,imsg2 ;Invalid switch
call int21ah9 ;print string
mov ax,4c01h ;Quit and return error status
int 21h
; Feed the remaining command line to the 'n' command.
init12: dec si
lodsb
call nn ;process the rest of the line
; Save some interrupt vectors.
mov cx,2
mov di,intsave
mov ax,3500h ;get interrupt vector 0
int 21h
mov [intsave],bx
mov [intsave+2],es
mov ax,3501h ;get interrupt vector 1
int 21h
mov [intsave+4],bx
mov [intsave+6],es
mov ax,3503h ;get interrupt vector 3
int 21h
mov [intsave+8],bx
mov [intsave+10],es
push ds
pop es
; Set up interrupt vectors.
mov cx,4
mov si,inttab
init13: lodsw ;get address
xchg ax,dx ;mov dx,ax
mov ah,25h ;set interrupt vector
lodsb ;interrupt number
int 21h
loop init13
; Save and modify termination address and the parent PSP field.
mov si,0ah
mov di,psp22
movsw
movsw
mov word [si-4],debug22
mov [si-2],cs
mov si,16h
movsw
mov [si-2],cs
; Do some preparation for shrinking DEBUG and setting its stack
mov ax,real_end + staksiz + 15
and ax,~15 ;new stack pointer
push ax
dec ax
dec ax
mov [savesp],ax ;save new SP minus two (for the word we'll push)
inc ax
inc ax
mov cl,4
shr ax,cl
mov [newmem],ax ;save DEBUG's new size
mov bx,cs
add ax,bx ;new segment
mov di,reg_ds ;fill segment registers
stosw
stosw
stosw
stosw
mov [psp],ax
call adusetup
mov bx,[reg_cs] ;bx:dx = where to load program
mov dx,100h
mov ax,[ALASAP] ;allocate stack for child
sub ax,bx
cmp ax,1000h
jbe init14 ;if memory left <= 64K
xor ax,ax ;ax = 1000h (same thing, after shifting)
init14: mov cl,4
shl ax,cl
dec ax
dec ax
mov [reg_sp],ax
xchg ax,di ;es:di = child stack pointer
mov es,bx
; Done with the first phase.
pop ax
cli ;interrupts off -- new stack
mov sp,ax
xor ax,ax
jmp intwo ;jump to second phase
|