Commit 4b74fe1f0013c622693b26141c0ed031a284a45a
1 parent
586314f2
many fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@19 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
684 additions
and
178 deletions
cpu-i386.h
| ... | ... | @@ -78,19 +78,27 @@ enum { |
| 78 | 78 | CC_OP_ADDW, |
| 79 | 79 | CC_OP_ADDL, |
| 80 | 80 | |
| 81 | + CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 82 | + CC_OP_ADCW, | |
| 83 | + CC_OP_ADCL, | |
| 84 | + | |
| 81 | 85 | CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ |
| 82 | 86 | CC_OP_SUBW, |
| 83 | 87 | CC_OP_SUBL, |
| 84 | 88 | |
| 89 | + CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 90 | + CC_OP_SBBW, | |
| 91 | + CC_OP_SBBL, | |
| 92 | + | |
| 85 | 93 | CC_OP_LOGICB, /* modify all flags, CC_DST = res */ |
| 86 | 94 | CC_OP_LOGICW, |
| 87 | 95 | CC_OP_LOGICL, |
| 88 | 96 | |
| 89 | - CC_OP_INCB, /* modify all flags except, CC_DST = res */ | |
| 97 | + CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
| 90 | 98 | CC_OP_INCW, |
| 91 | 99 | CC_OP_INCL, |
| 92 | 100 | |
| 93 | - CC_OP_DECB, /* modify all flags except, CC_DST = res */ | |
| 101 | + CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
| 94 | 102 | CC_OP_DECW, |
| 95 | 103 | CC_OP_DECL, |
| 96 | 104 | |
| ... | ... | @@ -98,6 +106,10 @@ enum { |
| 98 | 106 | CC_OP_SHLW, |
| 99 | 107 | CC_OP_SHLL, |
| 100 | 108 | |
| 109 | + CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ | |
| 110 | + CC_OP_SARW, | |
| 111 | + CC_OP_SARL, | |
| 112 | + | |
| 101 | 113 | CC_OP_NB, |
| 102 | 114 | }; |
| 103 | 115 | ... | ... |
dyngen.c
| ... | ... | @@ -198,14 +198,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size, |
| 198 | 198 | { |
| 199 | 199 | uint8_t *p; |
| 200 | 200 | p = p_end - 1; |
| 201 | - /* find ret */ | |
| 202 | - while (p > p_start && *p != 0xc3) | |
| 203 | - p--; | |
| 204 | - /* skip double ret */ | |
| 205 | - if (p > p_start && p[-1] == 0xc3) | |
| 206 | - p--; | |
| 207 | 201 | if (p == p_start) |
| 208 | 202 | error("empty code for %s", name); |
| 203 | + if (p[0] != 0xc3) | |
| 204 | + error("ret expected at the end of %s", name); | |
| 209 | 205 | copy_size = p - p_start; |
| 210 | 206 | } |
| 211 | 207 | break; | ... | ... |
linux-user/main.c
| ... | ... | @@ -128,21 +128,21 @@ int main(int argc, char **argv) |
| 128 | 128 | /* Zero out image_info */ |
| 129 | 129 | memset(info, 0, sizeof(struct image_info)); |
| 130 | 130 | |
| 131 | - if(elf_exec(filename, argv+1, environ, regs, info) != 0) { | |
| 131 | + if(elf_exec(filename, argv+optind, environ, regs, info) != 0) { | |
| 132 | 132 | printf("Error loading %s\n", filename); |
| 133 | 133 | exit(1); |
| 134 | 134 | } |
| 135 | 135 | |
| 136 | -#if 0 | |
| 137 | - printf("start_brk 0x%08lx\n" , info->start_brk); | |
| 138 | - printf("end_code 0x%08lx\n" , info->end_code); | |
| 139 | - printf("start_code 0x%08lx\n" , info->start_code); | |
| 140 | - printf("end_data 0x%08lx\n" , info->end_data); | |
| 141 | - printf("start_stack 0x%08lx\n" , info->start_stack); | |
| 142 | - printf("brk 0x%08lx\n" , info->brk); | |
| 143 | - printf("esp 0x%08lx\n" , regs->esp); | |
| 144 | - printf("eip 0x%08lx\n" , regs->eip); | |
| 145 | -#endif | |
| 136 | + if (loglevel) { | |
| 137 | + fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk); | |
| 138 | + fprintf(logfile, "end_code 0x%08lx\n" , info->end_code); | |
| 139 | + fprintf(logfile, "start_code 0x%08lx\n" , info->start_code); | |
| 140 | + fprintf(logfile, "end_data 0x%08lx\n" , info->end_data); | |
| 141 | + fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack); | |
| 142 | + fprintf(logfile, "brk 0x%08lx\n" , info->brk); | |
| 143 | + fprintf(logfile, "esp 0x%08lx\n" , regs->esp); | |
| 144 | + fprintf(logfile, "eip 0x%08lx\n" , regs->eip); | |
| 145 | + } | |
| 146 | 146 | |
| 147 | 147 | target_set_brk((char *)info->brk); |
| 148 | 148 | syscall_init(); | ... | ... |
op-i386.c
| ... | ... | @@ -10,7 +10,18 @@ typedef signed short int16_t; |
| 10 | 10 | typedef signed int int32_t; |
| 11 | 11 | typedef signed long long int64_t; |
| 12 | 12 | |
| 13 | +#define bswap32(x) \ | |
| 14 | +({ \ | |
| 15 | + uint32_t __x = (x); \ | |
| 16 | + ((uint32_t)( \ | |
| 17 | + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ | |
| 18 | + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ | |
| 19 | + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ | |
| 20 | + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ | |
| 21 | +}) | |
| 22 | + | |
| 13 | 23 | #define NULL 0 |
| 24 | +#include <fenv.h> | |
| 14 | 25 | |
| 15 | 26 | typedef struct FILE FILE; |
| 16 | 27 | extern FILE *logfile; |
| ... | ... | @@ -18,41 +29,39 @@ extern int loglevel; |
| 18 | 29 | extern int fprintf(FILE *, const char *, ...); |
| 19 | 30 | |
| 20 | 31 | #ifdef __i386__ |
| 21 | -register int T0 asm("esi"); | |
| 22 | -register int T1 asm("ebx"); | |
| 23 | -register int A0 asm("edi"); | |
| 32 | +register unsigned int T0 asm("ebx"); | |
| 33 | +register unsigned int T1 asm("esi"); | |
| 34 | +register unsigned int A0 asm("edi"); | |
| 24 | 35 | register struct CPUX86State *env asm("ebp"); |
| 25 | -#define FORCE_RET() asm volatile ("ret"); | |
| 26 | 36 | #endif |
| 27 | 37 | #ifdef __powerpc__ |
| 28 | -register int T0 asm("r24"); | |
| 29 | -register int T1 asm("r25"); | |
| 30 | -register int A0 asm("r26"); | |
| 38 | +register unsigned int T0 asm("r24"); | |
| 39 | +register unsigned int T1 asm("r25"); | |
| 40 | +register unsigned int A0 asm("r26"); | |
| 31 | 41 | register struct CPUX86State *env asm("r27"); |
| 32 | -#define FORCE_RET() asm volatile ("blr"); | |
| 33 | 42 | #endif |
| 34 | 43 | #ifdef __arm__ |
| 35 | -register int T0 asm("r4"); | |
| 36 | -register int T1 asm("r5"); | |
| 37 | -register int A0 asm("r6"); | |
| 44 | +register unsigned int T0 asm("r4"); | |
| 45 | +register unsigned int T1 asm("r5"); | |
| 46 | +register unsigned int A0 asm("r6"); | |
| 38 | 47 | register struct CPUX86State *env asm("r7"); |
| 39 | -#define FORCE_RET() asm volatile ("mov pc, lr"); | |
| 40 | 48 | #endif |
| 41 | 49 | #ifdef __mips__ |
| 42 | -register int T0 asm("s0"); | |
| 43 | -register int T1 asm("s1"); | |
| 44 | -register int A0 asm("s2"); | |
| 50 | +register unsigned int T0 asm("s0"); | |
| 51 | +register unsigned int T1 asm("s1"); | |
| 52 | +register unsigned int A0 asm("s2"); | |
| 45 | 53 | register struct CPUX86State *env asm("s3"); |
| 46 | -#define FORCE_RET() asm volatile ("jr $31"); | |
| 47 | 54 | #endif |
| 48 | 55 | #ifdef __sparc__ |
| 49 | -register int T0 asm("l0"); | |
| 50 | -register int T1 asm("l1"); | |
| 51 | -register int A0 asm("l2"); | |
| 56 | +register unsigned int T0 asm("l0"); | |
| 57 | +register unsigned int T1 asm("l1"); | |
| 58 | +register unsigned int A0 asm("l2"); | |
| 52 | 59 | register struct CPUX86State *env asm("l3"); |
| 53 | -#define FORCE_RET() asm volatile ("retl ; nop"); | |
| 54 | 60 | #endif |
| 55 | 61 | |
| 62 | +/* force GCC to generate only one epilog at the end of the function */ | |
| 63 | +#define FORCE_RET() asm volatile (""); | |
| 64 | + | |
| 56 | 65 | #ifndef OPPROTO |
| 57 | 66 | #define OPPROTO |
| 58 | 67 | #endif |
| ... | ... | @@ -267,20 +276,6 @@ void OPPROTO op_orl_T0_T1_cc(void) |
| 267 | 276 | CC_DST = T0; |
| 268 | 277 | } |
| 269 | 278 | |
| 270 | -void OPPROTO op_adcl_T0_T1_cc(void) | |
| 271 | -{ | |
| 272 | - CC_SRC = T0; | |
| 273 | - T0 = T0 + T1 + cc_table[CC_OP].compute_c(); | |
| 274 | - CC_DST = T0; | |
| 275 | -} | |
| 276 | - | |
| 277 | -void OPPROTO op_sbbl_T0_T1_cc(void) | |
| 278 | -{ | |
| 279 | - CC_SRC = T0; | |
| 280 | - T0 = T0 - T1 - cc_table[CC_OP].compute_c(); | |
| 281 | - CC_DST = T0; | |
| 282 | -} | |
| 283 | - | |
| 284 | 279 | void OPPROTO op_andl_T0_T1_cc(void) |
| 285 | 280 | { |
| 286 | 281 | T0 &= T1; |
| ... | ... | @@ -320,12 +315,14 @@ void OPPROTO op_negl_T0_cc(void) |
| 320 | 315 | |
| 321 | 316 | void OPPROTO op_incl_T0_cc(void) |
| 322 | 317 | { |
| 318 | + CC_SRC = cc_table[CC_OP].compute_c(); | |
| 323 | 319 | T0++; |
| 324 | 320 | CC_DST = T0; |
| 325 | 321 | } |
| 326 | 322 | |
| 327 | 323 | void OPPROTO op_decl_T0_cc(void) |
| 328 | 324 | { |
| 325 | + CC_SRC = cc_table[CC_OP].compute_c(); | |
| 329 | 326 | T0--; |
| 330 | 327 | CC_DST = T0; |
| 331 | 328 | } |
| ... | ... | @@ -335,6 +332,11 @@ void OPPROTO op_testl_T0_T1_cc(void) |
| 335 | 332 | CC_DST = T0 & T1; |
| 336 | 333 | } |
| 337 | 334 | |
| 335 | +void OPPROTO op_bswapl_T0(void) | |
| 336 | +{ | |
| 337 | + T0 = bswap32(T0); | |
| 338 | +} | |
| 339 | + | |
| 338 | 340 | /* multiply/divide */ |
| 339 | 341 | void OPPROTO op_mulb_AL_T0(void) |
| 340 | 342 | { |
| ... | ... | @@ -399,7 +401,7 @@ void OPPROTO op_imulw_T0_T1(void) |
| 399 | 401 | void OPPROTO op_imull_T0_T1(void) |
| 400 | 402 | { |
| 401 | 403 | int64_t res; |
| 402 | - res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T1); | |
| 404 | + res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1); | |
| 403 | 405 | T0 = res; |
| 404 | 406 | CC_SRC = (res != (int32_t)res); |
| 405 | 407 | } |
| ... | ... | @@ -468,10 +470,10 @@ void OPPROTO op_divl_EAX_T0(void) |
| 468 | 470 | void OPPROTO op_idivl_EAX_T0(void) |
| 469 | 471 | { |
| 470 | 472 | int den, q, r; |
| 471 | - int16_t num; | |
| 473 | + int64_t num; | |
| 472 | 474 | |
| 473 | 475 | num = EAX | ((uint64_t)EDX << 32); |
| 474 | - den = (int16_t)T0; | |
| 476 | + den = T0; | |
| 475 | 477 | q = (num / den); |
| 476 | 478 | r = (num % den); |
| 477 | 479 | EAX = q; |
| ... | ... | @@ -495,6 +497,16 @@ void OPPROTO op_movl_A0_im(void) |
| 495 | 497 | A0 = PARAM1; |
| 496 | 498 | } |
| 497 | 499 | |
| 500 | +void OPPROTO op_addl_A0_im(void) | |
| 501 | +{ | |
| 502 | + A0 += PARAM1; | |
| 503 | +} | |
| 504 | + | |
| 505 | +void OPPROTO op_andl_A0_ffff(void) | |
| 506 | +{ | |
| 507 | + A0 = A0 & 0xffff; | |
| 508 | +} | |
| 509 | + | |
| 498 | 510 | /* memory access */ |
| 499 | 511 | |
| 500 | 512 | void OPPROTO op_ldub_T0_A0(void) |
| ... | ... | @@ -562,7 +574,17 @@ void OPPROTO op_stl_T0_A0(void) |
| 562 | 574 | stl((uint8_t *)A0, T0); |
| 563 | 575 | } |
| 564 | 576 | |
| 565 | -/* jumps */ | |
| 577 | +/* used for bit operations */ | |
| 578 | + | |
| 579 | +void OPPROTO op_add_bitw_A0_T1(void) | |
| 580 | +{ | |
| 581 | + A0 += ((int32_t)T1 >> 4) << 1; | |
| 582 | +} | |
| 583 | + | |
| 584 | +void OPPROTO op_add_bitl_A0_T1(void) | |
| 585 | +{ | |
| 586 | + A0 += ((int32_t)T1 >> 5) << 2; | |
| 587 | +} | |
| 566 | 588 | |
| 567 | 589 | /* indirect jump */ |
| 568 | 590 | |
| ... | ... | @@ -938,25 +960,37 @@ CCTable cc_table[CC_OP_NB] = { |
| 938 | 960 | [CC_OP_ADDW] = { compute_all_addw, compute_c_addw }, |
| 939 | 961 | [CC_OP_ADDL] = { compute_all_addl, compute_c_addl }, |
| 940 | 962 | |
| 963 | + [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb }, | |
| 964 | + [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw }, | |
| 965 | + [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl }, | |
| 966 | + | |
| 941 | 967 | [CC_OP_SUBB] = { compute_all_subb, compute_c_subb }, |
| 942 | 968 | [CC_OP_SUBW] = { compute_all_subw, compute_c_subw }, |
| 943 | 969 | [CC_OP_SUBL] = { compute_all_subl, compute_c_subl }, |
| 944 | 970 | |
| 971 | + [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb }, | |
| 972 | + [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw }, | |
| 973 | + [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl }, | |
| 974 | + | |
| 945 | 975 | [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb }, |
| 946 | 976 | [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw }, |
| 947 | 977 | [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl }, |
| 948 | 978 | |
| 949 | - [CC_OP_INCB] = { compute_all_incb, compute_c_incb }, | |
| 950 | - [CC_OP_INCW] = { compute_all_incw, compute_c_incw }, | |
| 979 | + [CC_OP_INCB] = { compute_all_incb, compute_c_incl }, | |
| 980 | + [CC_OP_INCW] = { compute_all_incw, compute_c_incl }, | |
| 951 | 981 | [CC_OP_INCL] = { compute_all_incl, compute_c_incl }, |
| 952 | 982 | |
| 953 | - [CC_OP_DECB] = { compute_all_decb, compute_c_incb }, | |
| 954 | - [CC_OP_DECW] = { compute_all_decw, compute_c_incw }, | |
| 983 | + [CC_OP_DECB] = { compute_all_decb, compute_c_incl }, | |
| 984 | + [CC_OP_DECW] = { compute_all_decw, compute_c_incl }, | |
| 955 | 985 | [CC_OP_DECL] = { compute_all_decl, compute_c_incl }, |
| 956 | 986 | |
| 957 | - [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb }, | |
| 958 | - [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw }, | |
| 987 | + [CC_OP_SHLB] = { compute_all_shlb, compute_c_shll }, | |
| 988 | + [CC_OP_SHLW] = { compute_all_shlw, compute_c_shll }, | |
| 959 | 989 | [CC_OP_SHLL] = { compute_all_shll, compute_c_shll }, |
| 990 | + | |
| 991 | + [CC_OP_SARB] = { compute_all_sarb, compute_c_shll }, | |
| 992 | + [CC_OP_SARW] = { compute_all_sarw, compute_c_shll }, | |
| 993 | + [CC_OP_SARL] = { compute_all_sarl, compute_c_shll }, | |
| 960 | 994 | }; |
| 961 | 995 | |
| 962 | 996 | /* floating point support */ |
| ... | ... | @@ -1640,6 +1674,41 @@ void OPPROTO op_fcos(void) |
| 1640 | 1674 | helper_fcos(); |
| 1641 | 1675 | } |
| 1642 | 1676 | |
| 1677 | +void OPPROTO op_fnstsw_A0(void) | |
| 1678 | +{ | |
| 1679 | + int fpus; | |
| 1680 | + fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; | |
| 1681 | + stw((void *)A0, fpus); | |
| 1682 | +} | |
| 1683 | + | |
| 1684 | +void OPPROTO op_fnstcw_A0(void) | |
| 1685 | +{ | |
| 1686 | + stw((void *)A0, env->fpuc); | |
| 1687 | +} | |
| 1688 | + | |
| 1689 | +void OPPROTO op_fldcw_A0(void) | |
| 1690 | +{ | |
| 1691 | + int rnd_type; | |
| 1692 | + env->fpuc = lduw((void *)A0); | |
| 1693 | + /* set rounding mode */ | |
| 1694 | + switch(env->fpuc & RC_MASK) { | |
| 1695 | + default: | |
| 1696 | + case RC_NEAR: | |
| 1697 | + rnd_type = FE_TONEAREST; | |
| 1698 | + break; | |
| 1699 | + case RC_DOWN: | |
| 1700 | + rnd_type = FE_DOWNWARD; | |
| 1701 | + break; | |
| 1702 | + case RC_UP: | |
| 1703 | + rnd_type = FE_UPWARD; | |
| 1704 | + break; | |
| 1705 | + case RC_CHOP: | |
| 1706 | + rnd_type = FE_TOWARDZERO; | |
| 1707 | + break; | |
| 1708 | + } | |
| 1709 | + fesetround(rnd_type); | |
| 1710 | +} | |
| 1711 | + | |
| 1643 | 1712 | /* main execution loop */ |
| 1644 | 1713 | uint8_t code_gen_buffer[65536]; |
| 1645 | 1714 | |
| ... | ... | @@ -1651,9 +1720,15 @@ static const char *cc_op_str[] = { |
| 1651 | 1720 | "ADDB", |
| 1652 | 1721 | "ADDW", |
| 1653 | 1722 | "ADDL", |
| 1723 | + "ADCB", | |
| 1724 | + "ADCW", | |
| 1725 | + "ADCL", | |
| 1654 | 1726 | "SUBB", |
| 1655 | 1727 | "SUBW", |
| 1656 | 1728 | "SUBL", |
| 1729 | + "SBBB", | |
| 1730 | + "SBBW", | |
| 1731 | + "SBBL", | |
| 1657 | 1732 | "LOGICB", |
| 1658 | 1733 | "LOGICW", |
| 1659 | 1734 | "LOGICL", |
| ... | ... | @@ -1666,6 +1741,9 @@ static const char *cc_op_str[] = { |
| 1666 | 1741 | "SHLB", |
| 1667 | 1742 | "SHLW", |
| 1668 | 1743 | "SHLL", |
| 1744 | + "SARB", | |
| 1745 | + "SARW", | |
| 1746 | + "SARL", | |
| 1669 | 1747 | }; |
| 1670 | 1748 | #endif |
| 1671 | 1749 | |
| ... | ... | @@ -1688,13 +1766,24 @@ int cpu_x86_exec(CPUX86State *env1) |
| 1688 | 1766 | for(;;) { |
| 1689 | 1767 | #ifdef DEBUG_EXEC |
| 1690 | 1768 | if (loglevel) { |
| 1769 | + int eflags; | |
| 1770 | + eflags = cc_table[CC_OP].compute_all(); | |
| 1771 | + eflags |= (DF & DIRECTION_FLAG); | |
| 1691 | 1772 | fprintf(logfile, |
| 1692 | 1773 | "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" |
| 1693 | - "ESI=%08x ESI=%08X EBP=%08x ESP=%08x\n" | |
| 1694 | - "CCS=%08x CCD=%08x CCOP=%s\n", | |
| 1774 | + "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" | |
| 1775 | + "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", | |
| 1695 | 1776 | env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |
| 1696 | 1777 | env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], |
| 1697 | - env->cc_src, env->cc_dst, cc_op_str[env->cc_op]); | |
| 1778 | + env->cc_src, env->cc_dst, cc_op_str[env->cc_op], | |
| 1779 | + eflags & DIRECTION_FLAG ? 'D' : '-', | |
| 1780 | + eflags & CC_O ? 'O' : '-', | |
| 1781 | + eflags & CC_S ? 'S' : '-', | |
| 1782 | + eflags & CC_Z ? 'Z' : '-', | |
| 1783 | + eflags & CC_A ? 'A' : '-', | |
| 1784 | + eflags & CC_P ? 'P' : '-', | |
| 1785 | + eflags & CC_C ? 'C' : '-' | |
| 1786 | + ); | |
| 1698 | 1787 | } |
| 1699 | 1788 | #endif |
| 1700 | 1789 | cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc); | ... | ... |
ops_template.h
| ... | ... | @@ -33,7 +33,7 @@ static int glue(compute_all_add, SUFFIX)(void) |
| 33 | 33 | cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; |
| 34 | 34 | pf = parity_table[(uint8_t)CC_DST]; |
| 35 | 35 | af = (CC_DST ^ src1 ^ src2) & 0x10; |
| 36 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 36 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 37 | 37 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 38 | 38 | of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; |
| 39 | 39 | return cf | pf | af | zf | sf | of; |
| ... | ... | @@ -47,6 +47,29 @@ static int glue(compute_c_add, SUFFIX)(void) |
| 47 | 47 | return cf; |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | +static int glue(compute_all_adc, SUFFIX)(void) | |
| 51 | +{ | |
| 52 | + int cf, pf, af, zf, sf, of; | |
| 53 | + int src1, src2; | |
| 54 | + src1 = CC_SRC; | |
| 55 | + src2 = CC_DST - CC_SRC - 1; | |
| 56 | + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; | |
| 57 | + pf = parity_table[(uint8_t)CC_DST]; | |
| 58 | + af = (CC_DST ^ src1 ^ src2) & 0x10; | |
| 59 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 60 | + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
| 61 | + of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 62 | + return cf | pf | af | zf | sf | of; | |
| 63 | +} | |
| 64 | + | |
| 65 | +static int glue(compute_c_adc, SUFFIX)(void) | |
| 66 | +{ | |
| 67 | + int src1, cf; | |
| 68 | + src1 = CC_SRC; | |
| 69 | + cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; | |
| 70 | + return cf; | |
| 71 | +} | |
| 72 | + | |
| 50 | 73 | static int glue(compute_all_sub, SUFFIX)(void) |
| 51 | 74 | { |
| 52 | 75 | int cf, pf, af, zf, sf, of; |
| ... | ... | @@ -56,9 +79,9 @@ static int glue(compute_all_sub, SUFFIX)(void) |
| 56 | 79 | cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; |
| 57 | 80 | pf = parity_table[(uint8_t)CC_DST]; |
| 58 | 81 | af = (CC_DST ^ src1 ^ src2) & 0x10; |
| 59 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 82 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 60 | 83 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 61 | - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 84 | + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 62 | 85 | return cf | pf | af | zf | sf | of; |
| 63 | 86 | } |
| 64 | 87 | |
| ... | ... | @@ -67,7 +90,31 @@ static int glue(compute_c_sub, SUFFIX)(void) |
| 67 | 90 | int src1, src2, cf; |
| 68 | 91 | src1 = CC_SRC; |
| 69 | 92 | src2 = CC_SRC - CC_DST; |
| 70 | - cf = (DATA_TYPE)src1 < (DATA_TYPE)src1; | |
| 93 | + cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; | |
| 94 | + return cf; | |
| 95 | +} | |
| 96 | + | |
| 97 | +static int glue(compute_all_sbb, SUFFIX)(void) | |
| 98 | +{ | |
| 99 | + int cf, pf, af, zf, sf, of; | |
| 100 | + int src1, src2; | |
| 101 | + src1 = CC_SRC; | |
| 102 | + src2 = CC_SRC - CC_DST - 1; | |
| 103 | + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; | |
| 104 | + pf = parity_table[(uint8_t)CC_DST]; | |
| 105 | + af = (CC_DST ^ src1 ^ src2) & 0x10; | |
| 106 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 107 | + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
| 108 | + of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 109 | + return cf | pf | af | zf | sf | of; | |
| 110 | +} | |
| 111 | + | |
| 112 | +static int glue(compute_c_sbb, SUFFIX)(void) | |
| 113 | +{ | |
| 114 | + int src1, src2, cf; | |
| 115 | + src1 = CC_SRC; | |
| 116 | + src2 = CC_SRC - CC_DST - 1; | |
| 117 | + cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; | |
| 71 | 118 | return cf; |
| 72 | 119 | } |
| 73 | 120 | |
| ... | ... | @@ -77,7 +124,7 @@ static int glue(compute_all_logic, SUFFIX)(void) |
| 77 | 124 | cf = 0; |
| 78 | 125 | pf = parity_table[(uint8_t)CC_DST]; |
| 79 | 126 | af = 0; |
| 80 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 127 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 81 | 128 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 82 | 129 | of = 0; |
| 83 | 130 | return cf | pf | af | zf | sf | of; |
| ... | ... | @@ -97,16 +144,18 @@ static int glue(compute_all_inc, SUFFIX)(void) |
| 97 | 144 | cf = CC_SRC; |
| 98 | 145 | pf = parity_table[(uint8_t)CC_DST]; |
| 99 | 146 | af = (CC_DST ^ src1 ^ src2) & 0x10; |
| 100 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 147 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 101 | 148 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 102 | - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 149 | + of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; | |
| 103 | 150 | return cf | pf | af | zf | sf | of; |
| 104 | 151 | } |
| 105 | 152 | |
| 153 | +#if DATA_BITS == 32 | |
| 106 | 154 | static int glue(compute_c_inc, SUFFIX)(void) |
| 107 | 155 | { |
| 108 | 156 | return CC_SRC; |
| 109 | 157 | } |
| 158 | +#endif | |
| 110 | 159 | |
| 111 | 160 | static int glue(compute_all_dec, SUFFIX)(void) |
| 112 | 161 | { |
| ... | ... | @@ -117,9 +166,9 @@ static int glue(compute_all_dec, SUFFIX)(void) |
| 117 | 166 | cf = CC_SRC; |
| 118 | 167 | pf = parity_table[(uint8_t)CC_DST]; |
| 119 | 168 | af = (CC_DST ^ src1 ^ src2) & 0x10; |
| 120 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 169 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 121 | 170 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 122 | - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
| 171 | + of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; | |
| 123 | 172 | return cf | pf | af | zf | sf | of; |
| 124 | 173 | } |
| 125 | 174 | |
| ... | ... | @@ -129,16 +178,30 @@ static int glue(compute_all_shl, SUFFIX)(void) |
| 129 | 178 | cf = CC_SRC & 1; |
| 130 | 179 | pf = parity_table[(uint8_t)CC_DST]; |
| 131 | 180 | af = 0; /* undefined */ |
| 132 | - zf = ((DATA_TYPE)CC_DST != 0) << 6; | |
| 181 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 133 | 182 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
| 134 | - of = sf << 4; /* only meaniful for shr with count == 1 */ | |
| 183 | + of = lshift(CC_SRC, 12 - DATA_BITS) & CC_O; /* only meaniful for shr with count == 1 */ | |
| 135 | 184 | return cf | pf | af | zf | sf | of; |
| 136 | 185 | } |
| 137 | 186 | |
| 187 | +#if DATA_BITS == 32 | |
| 138 | 188 | static int glue(compute_c_shl, SUFFIX)(void) |
| 139 | 189 | { |
| 140 | 190 | return CC_SRC & 1; |
| 141 | 191 | } |
| 192 | +#endif | |
| 193 | + | |
| 194 | +static int glue(compute_all_sar, SUFFIX)(void) | |
| 195 | +{ | |
| 196 | + int cf, pf, af, zf, sf, of; | |
| 197 | + cf = CC_SRC & 1; | |
| 198 | + pf = parity_table[(uint8_t)CC_DST]; | |
| 199 | + af = 0; /* undefined */ | |
| 200 | + zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
| 201 | + sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
| 202 | + of = 0; /* only meaniful for shr with count == 1 */ | |
| 203 | + return cf | pf | af | zf | sf | of; | |
| 204 | +} | |
| 142 | 205 | |
| 143 | 206 | /* various optimized jumps cases */ |
| 144 | 207 | |
| ... | ... | @@ -157,7 +220,7 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void) |
| 157 | 220 | |
| 158 | 221 | void OPPROTO glue(op_jz_sub, SUFFIX)(void) |
| 159 | 222 | { |
| 160 | - if ((DATA_TYPE)CC_DST != 0) | |
| 223 | + if ((DATA_TYPE)CC_DST == 0) | |
| 161 | 224 | PC = PARAM1; |
| 162 | 225 | else |
| 163 | 226 | PC = PARAM2; |
| ... | ... | @@ -225,7 +288,7 @@ void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) |
| 225 | 288 | |
| 226 | 289 | void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) |
| 227 | 290 | { |
| 228 | - T0 = ((DATA_TYPE)CC_DST != 0); | |
| 291 | + T0 = ((DATA_TYPE)CC_DST == 0); | |
| 229 | 292 | } |
| 230 | 293 | |
| 231 | 294 | void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) |
| ... | ... | @@ -275,6 +338,7 @@ void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) |
| 275 | 338 | (T0 & CC_C); |
| 276 | 339 | CC_OP = CC_OP_EFLAGS; |
| 277 | 340 | } |
| 341 | + FORCE_RET(); | |
| 278 | 342 | } |
| 279 | 343 | |
| 280 | 344 | void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -290,6 +354,7 @@ void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) |
| 290 | 354 | ((T0 >> (DATA_BITS - 1)) & CC_C); |
| 291 | 355 | CC_OP = CC_OP_EFLAGS; |
| 292 | 356 | } |
| 357 | + FORCE_RET(); | |
| 293 | 358 | } |
| 294 | 359 | |
| 295 | 360 | void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -305,6 +370,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) |
| 305 | 370 | #endif |
| 306 | 371 | if (count) { |
| 307 | 372 | eflags = cc_table[CC_OP].compute_all(); |
| 373 | + T0 &= DATA_MASK; | |
| 308 | 374 | src = T0; |
| 309 | 375 | res = (T0 << count) | ((eflags & CC_C) << (count - 1)); |
| 310 | 376 | if (count > 1) |
| ... | ... | @@ -315,6 +381,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) |
| 315 | 381 | ((src >> (DATA_BITS - count)) & CC_C); |
| 316 | 382 | CC_OP = CC_OP_EFLAGS; |
| 317 | 383 | } |
| 384 | + FORCE_RET(); | |
| 318 | 385 | } |
| 319 | 386 | |
| 320 | 387 | void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -330,6 +397,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) |
| 330 | 397 | #endif |
| 331 | 398 | if (count) { |
| 332 | 399 | eflags = cc_table[CC_OP].compute_all(); |
| 400 | + T0 &= DATA_MASK; | |
| 333 | 401 | src = T0; |
| 334 | 402 | res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); |
| 335 | 403 | if (count > 1) |
| ... | ... | @@ -340,6 +408,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) |
| 340 | 408 | ((src >> (count - 1)) & CC_C); |
| 341 | 409 | CC_OP = CC_OP_EFLAGS; |
| 342 | 410 | } |
| 411 | + FORCE_RET(); | |
| 343 | 412 | } |
| 344 | 413 | |
| 345 | 414 | void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -352,11 +421,12 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) |
| 352 | 421 | CC_DST = T0; |
| 353 | 422 | CC_OP = CC_OP_ADDB + SHIFT; |
| 354 | 423 | } else if (count) { |
| 355 | - CC_SRC = T0 >> (DATA_BITS - count); | |
| 424 | + CC_SRC = (DATA_TYPE)T0 >> (DATA_BITS - count); | |
| 356 | 425 | T0 = T0 << count; |
| 357 | 426 | CC_DST = T0; |
| 358 | 427 | CC_OP = CC_OP_SHLB + SHIFT; |
| 359 | 428 | } |
| 429 | + FORCE_RET(); | |
| 360 | 430 | } |
| 361 | 431 | |
| 362 | 432 | void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -370,6 +440,7 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) |
| 370 | 440 | CC_DST = T0; |
| 371 | 441 | CC_OP = CC_OP_SHLB + SHIFT; |
| 372 | 442 | } |
| 443 | + FORCE_RET(); | |
| 373 | 444 | } |
| 374 | 445 | |
| 375 | 446 | void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) |
| ... | ... | @@ -381,10 +452,69 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) |
| 381 | 452 | CC_SRC = src >> (count - 1); |
| 382 | 453 | T0 = src >> count; |
| 383 | 454 | CC_DST = T0; |
| 384 | - CC_OP = CC_OP_SHLB + SHIFT; | |
| 455 | + CC_OP = CC_OP_SARB + SHIFT; | |
| 385 | 456 | } |
| 457 | + FORCE_RET(); | |
| 386 | 458 | } |
| 387 | 459 | |
| 460 | +/* carry add/sub (we only need to set CC_OP differently) */ | |
| 461 | + | |
| 462 | +void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) | |
| 463 | +{ | |
| 464 | + int cf; | |
| 465 | + cf = cc_table[CC_OP].compute_c(); | |
| 466 | + CC_SRC = T0; | |
| 467 | + T0 = T0 + T1 + cf; | |
| 468 | + CC_DST = T0; | |
| 469 | + CC_OP = CC_OP_ADDB + SHIFT + cf * 3; | |
| 470 | +} | |
| 471 | + | |
| 472 | +void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) | |
| 473 | +{ | |
| 474 | + int cf; | |
| 475 | + cf = cc_table[CC_OP].compute_c(); | |
| 476 | + CC_SRC = T0; | |
| 477 | + T0 = T0 - T1 - cf; | |
| 478 | + CC_DST = T0; | |
| 479 | + CC_OP = CC_OP_SUBB + SHIFT + cf * 3; | |
| 480 | +} | |
| 481 | + | |
| 482 | +/* bit operations */ | |
| 483 | +#if DATA_BITS >= 16 | |
| 484 | + | |
| 485 | +void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) | |
| 486 | +{ | |
| 487 | + int count; | |
| 488 | + count = T1 & SHIFT_MASK; | |
| 489 | + CC_SRC = T0 >> count; | |
| 490 | +} | |
| 491 | + | |
| 492 | +void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) | |
| 493 | +{ | |
| 494 | + int count; | |
| 495 | + count = T1 & SHIFT_MASK; | |
| 496 | + CC_SRC = T0 >> count; | |
| 497 | + T0 |= (1 << count); | |
| 498 | +} | |
| 499 | + | |
| 500 | +void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) | |
| 501 | +{ | |
| 502 | + int count; | |
| 503 | + count = T1 & SHIFT_MASK; | |
| 504 | + CC_SRC = T0 >> count; | |
| 505 | + T0 &= ~(1 << count); | |
| 506 | +} | |
| 507 | + | |
| 508 | +void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) | |
| 509 | +{ | |
| 510 | + int count; | |
| 511 | + count = T1 & SHIFT_MASK; | |
| 512 | + CC_SRC = T0 >> count; | |
| 513 | + T0 ^= (1 << count); | |
| 514 | +} | |
| 515 | + | |
| 516 | +#endif | |
| 517 | + | |
| 388 | 518 | /* string operations */ |
| 389 | 519 | /* XXX: maybe use lower level instructions to ease exception handling */ |
| 390 | 520 | |
| ... | ... | @@ -464,8 +594,8 @@ void OPPROTO glue(op_scas, SUFFIX)(void) |
| 464 | 594 | { |
| 465 | 595 | int v; |
| 466 | 596 | |
| 467 | - v = glue(ldu, SUFFIX)((void *)ESI); | |
| 468 | - ESI += (DF << SHIFT); | |
| 597 | + v = glue(ldu, SUFFIX)((void *)EDI); | |
| 598 | + EDI += (DF << SHIFT); | |
| 469 | 599 | CC_SRC = EAX; |
| 470 | 600 | CC_DST = EAX - v; |
| 471 | 601 | } |
| ... | ... | @@ -476,20 +606,14 @@ void OPPROTO glue(op_repz_scas, SUFFIX)(void) |
| 476 | 606 | |
| 477 | 607 | if (ECX != 0) { |
| 478 | 608 | /* NOTE: the flags are not modified if ECX == 0 */ |
| 479 | -#if SHIFT == 0 | |
| 480 | - v1 = EAX & 0xff; | |
| 481 | -#elif SHIFT == 1 | |
| 482 | - v1 = EAX & 0xffff; | |
| 483 | -#else | |
| 484 | - v1 = EAX; | |
| 485 | -#endif | |
| 609 | + v1 = EAX & DATA_MASK; | |
| 486 | 610 | inc = (DF << SHIFT); |
| 487 | 611 | do { |
| 488 | - v2 = glue(ldu, SUFFIX)((void *)ESI); | |
| 612 | + v2 = glue(ldu, SUFFIX)((void *)EDI); | |
| 613 | + EDI += inc; | |
| 614 | + ECX--; | |
| 489 | 615 | if (v1 != v2) |
| 490 | 616 | break; |
| 491 | - ESI += inc; | |
| 492 | - ECX--; | |
| 493 | 617 | } while (ECX != 0); |
| 494 | 618 | CC_SRC = v1; |
| 495 | 619 | CC_DST = v1 - v2; |
| ... | ... | @@ -503,20 +627,14 @@ void OPPROTO glue(op_repnz_scas, SUFFIX)(void) |
| 503 | 627 | |
| 504 | 628 | if (ECX != 0) { |
| 505 | 629 | /* NOTE: the flags are not modified if ECX == 0 */ |
| 506 | -#if SHIFT == 0 | |
| 507 | - v1 = EAX & 0xff; | |
| 508 | -#elif SHIFT == 1 | |
| 509 | - v1 = EAX & 0xffff; | |
| 510 | -#else | |
| 511 | - v1 = EAX; | |
| 512 | -#endif | |
| 630 | + v1 = EAX & DATA_MASK; | |
| 513 | 631 | inc = (DF << SHIFT); |
| 514 | 632 | do { |
| 515 | - v2 = glue(ldu, SUFFIX)((void *)ESI); | |
| 633 | + v2 = glue(ldu, SUFFIX)((void *)EDI); | |
| 634 | + EDI += inc; | |
| 635 | + ECX--; | |
| 516 | 636 | if (v1 == v2) |
| 517 | 637 | break; |
| 518 | - ESI += inc; | |
| 519 | - ECX--; | |
| 520 | 638 | } while (ECX != 0); |
| 521 | 639 | CC_SRC = v1; |
| 522 | 640 | CC_DST = v1 - v2; |
| ... | ... | @@ -543,11 +661,11 @@ void OPPROTO glue(op_repz_cmps, SUFFIX)(void) |
| 543 | 661 | do { |
| 544 | 662 | v1 = glue(ldu, SUFFIX)((void *)ESI); |
| 545 | 663 | v2 = glue(ldu, SUFFIX)((void *)EDI); |
| 546 | - if (v1 != v2) | |
| 547 | - break; | |
| 548 | 664 | ESI += inc; |
| 549 | 665 | EDI += inc; |
| 550 | 666 | ECX--; |
| 667 | + if (v1 != v2) | |
| 668 | + break; | |
| 551 | 669 | } while (ECX != 0); |
| 552 | 670 | CC_SRC = v1; |
| 553 | 671 | CC_DST = v1 - v2; |
| ... | ... | @@ -563,11 +681,11 @@ void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) |
| 563 | 681 | do { |
| 564 | 682 | v1 = glue(ldu, SUFFIX)((void *)ESI); |
| 565 | 683 | v2 = glue(ldu, SUFFIX)((void *)EDI); |
| 566 | - if (v1 == v2) | |
| 567 | - break; | |
| 568 | 684 | ESI += inc; |
| 569 | 685 | EDI += inc; |
| 570 | 686 | ECX--; |
| 687 | + if (v1 == v2) | |
| 688 | + break; | |
| 571 | 689 | } while (ECX != 0); |
| 572 | 690 | CC_SRC = v1; |
| 573 | 691 | CC_DST = v1 - v2; | ... | ... |
tests/Makefile
| ... | ... | @@ -20,7 +20,7 @@ test2: test2.c |
| 20 | 20 | |
| 21 | 21 | # i386 emulation test (dump various opcodes) */ |
| 22 | 22 | test-i386: test-i386.c test-i386.h test-i386-shift.h |
| 23 | - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< | |
| 23 | + $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $< | |
| 24 | 24 | |
| 25 | 25 | test: test-i386 |
| 26 | 26 | ./test-i386 > test-i386.ref | ... | ... |
tests/test-i386.c
| ... | ... | @@ -14,13 +14,12 @@ |
| 14 | 14 | #define CC_S 0x0080 |
| 15 | 15 | #define CC_O 0x0800 |
| 16 | 16 | |
| 17 | -/* XXX: currently no A flag */ | |
| 18 | -#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) | |
| 19 | - | |
| 20 | 17 | #define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) |
| 21 | 18 | |
| 22 | 19 | static void *call_start __init_call = NULL; |
| 23 | 20 | |
| 21 | +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A) | |
| 22 | + | |
| 24 | 23 | #define OP add |
| 25 | 24 | #include "test-i386.h" |
| 26 | 25 | |
| ... | ... | @@ -67,6 +66,9 @@ static void *call_start __init_call = NULL; |
| 67 | 66 | #define OP1 |
| 68 | 67 | #include "test-i386.h" |
| 69 | 68 | |
| 69 | +#undef CC_MASK | |
| 70 | +#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O) | |
| 71 | + | |
| 70 | 72 | #define OP shl |
| 71 | 73 | #include "test-i386-shift.h" |
| 72 | 74 | |
| ... | ... | @@ -268,18 +270,148 @@ void test_jcc(void) |
| 268 | 270 | TEST_JCC("jns", 0, 0); |
| 269 | 271 | } |
| 270 | 272 | |
| 273 | +#undef CC_MASK | |
| 274 | +#define CC_MASK (CC_O | CC_C) | |
| 275 | + | |
| 276 | +#define OP mul | |
| 277 | +#include "test-i386-muldiv.h" | |
| 278 | + | |
| 279 | +#define OP imul | |
| 280 | +#include "test-i386-muldiv.h" | |
| 281 | + | |
| 282 | +#undef CC_MASK | |
| 283 | +#define CC_MASK (0) | |
| 284 | + | |
| 285 | +#define OP div | |
| 286 | +#include "test-i386-muldiv.h" | |
| 287 | + | |
| 288 | +#define OP idiv | |
| 289 | +#include "test-i386-muldiv.h" | |
| 290 | + | |
| 291 | +void test_imulw2(int op0, int op1) | |
| 292 | +{ | |
| 293 | + int res, s1, s0, flags; | |
| 294 | + s0 = op0; | |
| 295 | + s1 = op1; | |
| 296 | + res = s0; | |
| 297 | + flags = 0; | |
| 298 | + asm ("push %4\n\t" | |
| 299 | + "popf\n\t" | |
| 300 | + "imulw %w2, %w0\n\t" | |
| 301 | + "pushf\n\t" | |
| 302 | + "popl %1\n\t" | |
| 303 | + : "=q" (res), "=g" (flags) | |
| 304 | + : "q" (s1), "0" (res), "1" (flags)); | |
| 305 | + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", | |
| 306 | + "imulw", s0, s1, res, flags & CC_MASK); | |
| 307 | +} | |
| 308 | + | |
| 309 | +void test_imull2(int op0, int op1) | |
| 310 | +{ | |
| 311 | + int res, s1, s0, flags; | |
| 312 | + s0 = op0; | |
| 313 | + s1 = op1; | |
| 314 | + res = s0; | |
| 315 | + flags = 0; | |
| 316 | + asm ("push %4\n\t" | |
| 317 | + "popf\n\t" | |
| 318 | + "imull %2, %0\n\t" | |
| 319 | + "pushf\n\t" | |
| 320 | + "popl %1\n\t" | |
| 321 | + : "=q" (res), "=g" (flags) | |
| 322 | + : "q" (s1), "0" (res), "1" (flags)); | |
| 323 | + printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n", | |
| 324 | + "imull", s0, s1, res, flags & CC_MASK); | |
| 325 | +} | |
| 326 | + | |
| 327 | +void test_mul(void) | |
| 328 | +{ | |
| 329 | + test_imulb(0x1234561d, 4); | |
| 330 | + test_imulb(3, -4); | |
| 331 | + test_imulb(0x80, 0x80); | |
| 332 | + test_imulb(0x10, 0x10); | |
| 333 | + | |
| 334 | + test_imulw(0, 0x1234001d, 45); | |
| 335 | + test_imulw(0, 23, -45); | |
| 336 | + test_imulw(0, 0x8000, 0x8000); | |
| 337 | + test_imulw(0, 0x100, 0x100); | |
| 338 | + | |
| 339 | + test_imull(0, 0x1234001d, 45); | |
| 340 | + test_imull(0, 23, -45); | |
| 341 | + test_imull(0, 0x80000000, 0x80000000); | |
| 342 | + test_imull(0, 0x10000, 0x10000); | |
| 343 | + | |
| 344 | + test_mulb(0x1234561d, 4); | |
| 345 | + test_mulb(3, -4); | |
| 346 | + test_mulb(0x80, 0x80); | |
| 347 | + test_mulb(0x10, 0x10); | |
| 348 | + | |
| 349 | + test_mulw(0, 0x1234001d, 45); | |
| 350 | + test_mulw(0, 23, -45); | |
| 351 | + test_mulw(0, 0x8000, 0x8000); | |
| 352 | + test_mulw(0, 0x100, 0x100); | |
| 353 | + | |
| 354 | + test_mull(0, 0x1234001d, 45); | |
| 355 | + test_mull(0, 23, -45); | |
| 356 | + test_mull(0, 0x80000000, 0x80000000); | |
| 357 | + test_mull(0, 0x10000, 0x10000); | |
| 358 | + | |
| 359 | + test_imulw2(0x1234001d, 45); | |
| 360 | + test_imulw2(23, -45); | |
| 361 | + test_imulw2(0x8000, 0x8000); | |
| 362 | + test_imulw2(0x100, 0x100); | |
| 363 | + | |
| 364 | + test_imull2(0x1234001d, 45); | |
| 365 | + test_imull2(23, -45); | |
| 366 | + test_imull2(0x80000000, 0x80000000); | |
| 367 | + test_imull2(0x10000, 0x10000); | |
| 368 | + | |
| 369 | + test_idivb(0x12341678, 0x127e); | |
| 370 | + test_idivb(0x43210123, -5); | |
| 371 | + test_idivb(0x12340004, -1); | |
| 372 | + | |
| 373 | + test_idivw(0, 0x12345678, 12347); | |
| 374 | + test_idivw(0, -23223, -45); | |
| 375 | + test_idivw(0, 0x12348000, -1); | |
| 376 | + test_idivw(0x12343, 0x12345678, 0x81238567); | |
| 377 | + | |
| 378 | + test_idivl(0, 0x12345678, 12347); | |
| 379 | + test_idivl(0, -233223, -45); | |
| 380 | + test_idivl(0, 0x80000000, -1); | |
| 381 | + test_idivl(0x12343, 0x12345678, 0x81234567); | |
| 382 | + | |
| 383 | + test_divb(0x12341678, 0x127e); | |
| 384 | + test_divb(0x43210123, -5); | |
| 385 | + test_divb(0x12340004, -1); | |
| 386 | + | |
| 387 | + test_divw(0, 0x12345678, 12347); | |
| 388 | + test_divw(0, -23223, -45); | |
| 389 | + test_divw(0, 0x12348000, -1); | |
| 390 | + test_divw(0x12343, 0x12345678, 0x81238567); | |
| 391 | + | |
| 392 | + test_divl(0, 0x12345678, 12347); | |
| 393 | + test_divl(0, -233223, -45); | |
| 394 | + test_divl(0, 0x80000000, -1); | |
| 395 | + test_divl(0x12343, 0x12345678, 0x81234567); | |
| 396 | +} | |
| 397 | + | |
| 398 | + | |
| 271 | 399 | static void *call_end __init_call = NULL; |
| 272 | 400 | |
| 273 | 401 | int main(int argc, char **argv) |
| 274 | 402 | { |
| 275 | 403 | void **ptr; |
| 276 | 404 | void (*func)(void); |
| 405 | + | |
| 406 | + test_mul(); | |
| 407 | +#if 0 | |
| 277 | 408 | ptr = &call_start + 1; |
| 278 | 409 | while (*ptr != NULL) { |
| 279 | 410 | func = *ptr++; |
| 280 | 411 | func(); |
| 281 | 412 | } |
| 282 | - test_lea(); | |
| 283 | 413 | test_jcc(); |
| 414 | + test_lea(); | |
| 415 | +#endif | |
| 284 | 416 | return 0; |
| 285 | 417 | } | ... | ... |
translate-i386.c
| ... | ... | @@ -27,7 +27,9 @@ static void error(const char *fmt, ...) |
| 27 | 27 | va_list ap; |
| 28 | 28 | |
| 29 | 29 | va_start(ap, fmt); |
| 30 | + fprintf(stderr, "\n"); | |
| 30 | 31 | vfprintf(stderr, fmt, ap); |
| 32 | + fprintf(stderr, "\n"); | |
| 31 | 33 | va_end(ap); |
| 32 | 34 | exit(1); |
| 33 | 35 | } |
| ... | ... | @@ -98,42 +100,13 @@ enum { |
| 98 | 100 | OR_EBP, |
| 99 | 101 | OR_ESI, |
| 100 | 102 | OR_EDI, |
| 101 | - | |
| 102 | - /* I386 float registers */ | |
| 103 | - OR_ST0, | |
| 104 | - OR_ST1, | |
| 105 | - OR_ST2, | |
| 106 | - OR_ST3, | |
| 107 | - OR_ST4, | |
| 108 | - OR_ST5, | |
| 109 | - OR_ST6, | |
| 110 | - OR_ST7, | |
| 111 | 103 | OR_TMP0, /* temporary operand register */ |
| 112 | 104 | OR_TMP1, |
| 113 | 105 | OR_A0, /* temporary register used when doing address evaluation */ |
| 114 | - OR_EFLAGS, /* cpu flags */ | |
| 115 | - OR_ITMP0, /* used for byte/word insertion */ | |
| 116 | - OR_ITMP1, /* used for byte/word insertion */ | |
| 117 | - OR_ITMP2, /* used for byte/word insertion */ | |
| 118 | - OR_FTMP0, /* float temporary */ | |
| 119 | - OR_DF, /* D flag, for string ops */ | |
| 120 | 106 | OR_ZERO, /* fixed zero register */ |
| 121 | - OR_IM, /* dummy immediate value register */ | |
| 122 | 107 | NB_OREGS, |
| 123 | 108 | }; |
| 124 | 109 | |
| 125 | -#if 0 | |
| 126 | -static const double tab_const[7] = { | |
| 127 | - 1.0, | |
| 128 | - 3.32192809488736234789, /* log2(10) */ | |
| 129 | - M_LOG2E, | |
| 130 | - M_PI, | |
| 131 | - 0.30102999566398119521, /* log10(2) */ | |
| 132 | - M_LN2, | |
| 133 | - 0.0 | |
| 134 | -}; | |
| 135 | -#endif | |
| 136 | - | |
| 137 | 110 | typedef void (GenOpFunc)(void); |
| 138 | 111 | typedef void (GenOpFunc1)(long); |
| 139 | 112 | typedef void (GenOpFunc2)(long, long); |
| ... | ... | @@ -354,14 +327,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { |
| 354 | 327 | static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { |
| 355 | 328 | gen_op_addl_T0_T1_cc, |
| 356 | 329 | gen_op_orl_T0_T1_cc, |
| 357 | - gen_op_adcl_T0_T1_cc, | |
| 358 | - gen_op_sbbl_T0_T1_cc, | |
| 330 | + NULL, | |
| 331 | + NULL, | |
| 359 | 332 | gen_op_andl_T0_T1_cc, |
| 360 | 333 | gen_op_subl_T0_T1_cc, |
| 361 | 334 | gen_op_xorl_T0_T1_cc, |
| 362 | 335 | gen_op_cmpl_T0_T1_cc, |
| 363 | 336 | }; |
| 364 | 337 | |
| 338 | +static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { | |
| 339 | + [OT_BYTE] = { | |
| 340 | + gen_op_adcb_T0_T1_cc, | |
| 341 | + gen_op_sbbb_T0_T1_cc, | |
| 342 | + }, | |
| 343 | + [OT_WORD] = { | |
| 344 | + gen_op_adcw_T0_T1_cc, | |
| 345 | + gen_op_sbbw_T0_T1_cc, | |
| 346 | + }, | |
| 347 | + [OT_LONG] = { | |
| 348 | + gen_op_adcl_T0_T1_cc, | |
| 349 | + gen_op_sbbl_T0_T1_cc, | |
| 350 | + }, | |
| 351 | +}; | |
| 352 | + | |
| 365 | 353 | static const int cc_op_arithb[8] = { |
| 366 | 354 | CC_OP_ADDB, |
| 367 | 355 | CC_OP_LOGICB, |
| ... | ... | @@ -406,6 +394,21 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { |
| 406 | 394 | }, |
| 407 | 395 | }; |
| 408 | 396 | |
| 397 | +static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { | |
| 398 | + [0] = { | |
| 399 | + gen_op_btw_T0_T1_cc, | |
| 400 | + gen_op_btsw_T0_T1_cc, | |
| 401 | + gen_op_btrw_T0_T1_cc, | |
| 402 | + gen_op_btcw_T0_T1_cc, | |
| 403 | + }, | |
| 404 | + [1] = { | |
| 405 | + gen_op_btl_T0_T1_cc, | |
| 406 | + gen_op_btsl_T0_T1_cc, | |
| 407 | + gen_op_btrl_T0_T1_cc, | |
| 408 | + gen_op_btcl_T0_T1_cc, | |
| 409 | + }, | |
| 410 | +}; | |
| 411 | + | |
| 409 | 412 | static GenOpFunc *gen_op_lds_T0_A0[3] = { |
| 410 | 413 | gen_op_ldsb_T0_A0, |
| 411 | 414 | gen_op_ldsw_T0_A0, |
| ... | ... | @@ -644,18 +647,23 @@ static void gen_op(DisasContext *s1, int op, int ot, int d, int s) |
| 644 | 647 | gen_op_mov_TN_reg[ot][0][d](); |
| 645 | 648 | if (s != OR_TMP1) |
| 646 | 649 | gen_op_mov_TN_reg[ot][1][s](); |
| 647 | - if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC) | |
| 648 | - gen_op_set_cc_op(s1->cc_op); | |
| 649 | - gen_op_arith_T0_T1_cc[op](); | |
| 650 | + if (op == OP_ADCL || op == OP_SBBL) { | |
| 651 | + if (s1->cc_op != CC_OP_DYNAMIC) | |
| 652 | + gen_op_set_cc_op(s1->cc_op); | |
| 653 | + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); | |
| 654 | + s1->cc_op = CC_OP_DYNAMIC; | |
| 655 | + } else { | |
| 656 | + gen_op_arith_T0_T1_cc[op](); | |
| 657 | + s1->cc_op = cc_op_arithb[op] + ot; | |
| 658 | + } | |
| 650 | 659 | if (d != OR_TMP0 && op != OP_CMPL) |
| 651 | 660 | gen_op_mov_reg_T0[ot][d](); |
| 652 | - s1->cc_op = cc_op_arithb[op] + ot; | |
| 653 | 661 | } |
| 654 | 662 | |
| 655 | 663 | static void gen_opi(DisasContext *s1, int op, int ot, int d, int c) |
| 656 | 664 | { |
| 657 | 665 | gen_op_movl_T1_im(c); |
| 658 | - gen_op(s1, op, ot, d, OR_TMP0); | |
| 666 | + gen_op(s1, op, ot, d, OR_TMP1); | |
| 659 | 667 | } |
| 660 | 668 | |
| 661 | 669 | static void gen_inc(DisasContext *s1, int ot, int d, int c) |
| ... | ... | @@ -664,10 +672,13 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) |
| 664 | 672 | gen_op_mov_TN_reg[ot][0][d](); |
| 665 | 673 | if (s1->cc_op != CC_OP_DYNAMIC) |
| 666 | 674 | gen_op_set_cc_op(s1->cc_op); |
| 667 | - if (c > 0) | |
| 675 | + if (c > 0) { | |
| 668 | 676 | gen_op_incl_T0_cc(); |
| 669 | - else | |
| 677 | + s1->cc_op = CC_OP_INCB + ot; | |
| 678 | + } else { | |
| 670 | 679 | gen_op_decl_T0_cc(); |
| 680 | + s1->cc_op = CC_OP_DECB + ot; | |
| 681 | + } | |
| 671 | 682 | if (d != OR_TMP0) |
| 672 | 683 | gen_op_mov_reg_T0[ot][d](); |
| 673 | 684 | } |
| ... | ... | @@ -678,20 +689,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) |
| 678 | 689 | gen_op_mov_TN_reg[ot][0][d](); |
| 679 | 690 | if (s != OR_TMP1) |
| 680 | 691 | gen_op_mov_TN_reg[ot][1][s](); |
| 681 | - switch(op) { | |
| 682 | - case OP_ROL: | |
| 683 | - case OP_ROR: | |
| 684 | - case OP_RCL: | |
| 685 | - case OP_RCR: | |
| 686 | - /* only C and O are modified, so we must update flags dynamically */ | |
| 687 | - if (s1->cc_op != CC_OP_DYNAMIC) | |
| 688 | - gen_op_set_cc_op(s1->cc_op); | |
| 689 | - gen_op_shift_T0_T1_cc[ot][op](); | |
| 690 | - break; | |
| 691 | - default: | |
| 692 | - gen_op_shift_T0_T1_cc[ot][op](); | |
| 693 | - break; | |
| 694 | - } | |
| 692 | + /* for zero counts, flags are not updated, so must do it dynamically */ | |
| 693 | + if (s1->cc_op != CC_OP_DYNAMIC) | |
| 694 | + gen_op_set_cc_op(s1->cc_op); | |
| 695 | + | |
| 696 | + gen_op_shift_T0_T1_cc[ot][op](); | |
| 697 | + | |
| 695 | 698 | if (d != OR_TMP0) |
| 696 | 699 | gen_op_mov_reg_T0[ot][d](); |
| 697 | 700 | s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ |
| ... | ... | @@ -785,12 +788,65 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ |
| 785 | 788 | } |
| 786 | 789 | gen_op_addl_A0_reg_sN[scale][reg2](); |
| 787 | 790 | } |
| 788 | - opreg = OR_A0; | |
| 789 | 791 | } else { |
| 790 | - fprintf(stderr, "16 bit addressing not supported\n"); | |
| 791 | - disp = 0; | |
| 792 | - opreg = 0; | |
| 792 | + switch (mod) { | |
| 793 | + case 0: | |
| 794 | + if (rm == 6) { | |
| 795 | + disp = lduw(s->pc); | |
| 796 | + s->pc += 2; | |
| 797 | + gen_op_movl_A0_im(disp); | |
| 798 | + goto no_rm; | |
| 799 | + } else { | |
| 800 | + disp = 0; | |
| 801 | + } | |
| 802 | + break; | |
| 803 | + case 1: | |
| 804 | + disp = (int8_t)ldub(s->pc++); | |
| 805 | + break; | |
| 806 | + default: | |
| 807 | + case 2: | |
| 808 | + disp = lduw(s->pc); | |
| 809 | + s->pc += 2; | |
| 810 | + break; | |
| 811 | + } | |
| 812 | + switch(rm) { | |
| 813 | + case 0: | |
| 814 | + gen_op_movl_A0_reg[R_EBX](); | |
| 815 | + gen_op_addl_A0_reg_sN[0][R_ESI](); | |
| 816 | + break; | |
| 817 | + case 1: | |
| 818 | + gen_op_movl_A0_reg[R_EBX](); | |
| 819 | + gen_op_addl_A0_reg_sN[0][R_EDI](); | |
| 820 | + break; | |
| 821 | + case 2: | |
| 822 | + gen_op_movl_A0_reg[R_EBP](); | |
| 823 | + gen_op_addl_A0_reg_sN[0][R_ESI](); | |
| 824 | + break; | |
| 825 | + case 3: | |
| 826 | + gen_op_movl_A0_reg[R_EBP](); | |
| 827 | + gen_op_addl_A0_reg_sN[0][R_EDI](); | |
| 828 | + break; | |
| 829 | + case 4: | |
| 830 | + gen_op_movl_A0_reg[R_ESI](); | |
| 831 | + break; | |
| 832 | + case 5: | |
| 833 | + gen_op_movl_A0_reg[R_EDI](); | |
| 834 | + break; | |
| 835 | + case 6: | |
| 836 | + gen_op_movl_A0_reg[R_EBP](); | |
| 837 | + break; | |
| 838 | + default: | |
| 839 | + case 7: | |
| 840 | + gen_op_movl_A0_reg[R_EBX](); | |
| 841 | + break; | |
| 842 | + } | |
| 843 | + if (disp != 0) | |
| 844 | + gen_op_addl_A0_im(disp); | |
| 845 | + gen_op_andl_A0_ffff(); | |
| 846 | + no_rm: ; | |
| 793 | 847 | } |
| 848 | + opreg = OR_A0; | |
| 849 | + disp = 0; | |
| 794 | 850 | *reg_ptr = opreg; |
| 795 | 851 | *offset_ptr = disp; |
| 796 | 852 | } |
| ... | ... | @@ -870,6 +926,12 @@ static void gen_jcc(DisasContext *s, int b, int val) |
| 870 | 926 | case CC_OP_ADDB: |
| 871 | 927 | case CC_OP_ADDW: |
| 872 | 928 | case CC_OP_ADDL: |
| 929 | + case CC_OP_ADCB: | |
| 930 | + case CC_OP_ADCW: | |
| 931 | + case CC_OP_ADCL: | |
| 932 | + case CC_OP_SBBB: | |
| 933 | + case CC_OP_SBBW: | |
| 934 | + case CC_OP_SBBL: | |
| 873 | 935 | case CC_OP_LOGICB: |
| 874 | 936 | case CC_OP_LOGICW: |
| 875 | 937 | case CC_OP_LOGICL: |
| ... | ... | @@ -882,6 +944,9 @@ static void gen_jcc(DisasContext *s, int b, int val) |
| 882 | 944 | case CC_OP_SHLB: |
| 883 | 945 | case CC_OP_SHLW: |
| 884 | 946 | case CC_OP_SHLL: |
| 947 | + case CC_OP_SARB: | |
| 948 | + case CC_OP_SARW: | |
| 949 | + case CC_OP_SARL: | |
| 885 | 950 | switch(jcc_op) { |
| 886 | 951 | case JCC_Z: |
| 887 | 952 | func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; |
| ... | ... | @@ -1284,11 +1349,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1284 | 1349 | gen_inc(s, ot, OR_TMP0, 1); |
| 1285 | 1350 | if (mod != 3) |
| 1286 | 1351 | gen_op_st_T0_A0[ot](); |
| 1352 | + else | |
| 1353 | + gen_op_mov_reg_T0[ot][rm](); | |
| 1287 | 1354 | break; |
| 1288 | 1355 | case 1: /* dec Ev */ |
| 1289 | 1356 | gen_inc(s, ot, OR_TMP0, -1); |
| 1290 | 1357 | if (mod != 3) |
| 1291 | 1358 | gen_op_st_T0_A0[ot](); |
| 1359 | + else | |
| 1360 | + gen_op_mov_reg_T0[ot][rm](); | |
| 1292 | 1361 | break; |
| 1293 | 1362 | case 2: /* call Ev */ |
| 1294 | 1363 | gen_op_movl_T1_im((long)s->pc); |
| ... | ... | @@ -1359,7 +1428,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1359 | 1428 | ot = dflag ? OT_LONG : OT_WORD; |
| 1360 | 1429 | modrm = ldub(s->pc++); |
| 1361 | 1430 | reg = ((modrm >> 3) & 7) + OR_EAX; |
| 1362 | - | |
| 1363 | 1431 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); |
| 1364 | 1432 | if (b == 0x69) { |
| 1365 | 1433 | val = insn_get(s, ot); |
| ... | ... | @@ -1372,9 +1440,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1372 | 1440 | } |
| 1373 | 1441 | |
| 1374 | 1442 | if (ot == OT_LONG) { |
| 1375 | - op_imull_T0_T1(); | |
| 1443 | + gen_op_imull_T0_T1(); | |
| 1376 | 1444 | } else { |
| 1377 | - op_imulw_T0_T1(); | |
| 1445 | + gen_op_imulw_T0_T1(); | |
| 1378 | 1446 | } |
| 1379 | 1447 | gen_op_mov_reg_T0[ot][reg](); |
| 1380 | 1448 | s->cc_op = CC_OP_MUL; |
| ... | ... | @@ -1522,7 +1590,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1522 | 1590 | offset_addr = insn_get(s, OT_LONG); |
| 1523 | 1591 | else |
| 1524 | 1592 | offset_addr = insn_get(s, OT_WORD); |
| 1525 | - | |
| 1593 | + gen_op_movl_A0_im(offset_addr); | |
| 1526 | 1594 | if ((b & 2) == 0) { |
| 1527 | 1595 | gen_op_ld_T0_A0[ot](); |
| 1528 | 1596 | gen_op_mov_reg_T0[ot][R_EAX](); |
| ... | ... | @@ -1717,17 +1785,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1717 | 1785 | break; |
| 1718 | 1786 | } |
| 1719 | 1787 | break; |
| 1720 | -#if 0 | |
| 1788 | + case 0x0d: /* fldcw mem */ | |
| 1789 | + gen_op_fldcw_A0(); | |
| 1790 | + break; | |
| 1791 | + case 0x0f: /* fnstcw mem */ | |
| 1792 | + gen_op_fnstcw_A0(); | |
| 1793 | + break; | |
| 1721 | 1794 | case 0x2f: /* fnstsw mem */ |
| 1722 | - gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO); | |
| 1723 | - gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr); | |
| 1795 | + gen_op_fnstsw_A0(); | |
| 1724 | 1796 | break; |
| 1725 | - | |
| 1726 | 1797 | case 0x3c: /* fbld */ |
| 1727 | 1798 | case 0x3e: /* fbstp */ |
| 1728 | 1799 | error("float BCD not hanlded"); |
| 1729 | 1800 | return -1; |
| 1730 | -#endif | |
| 1731 | 1801 | case 0x3d: /* fildll */ |
| 1732 | 1802 | gen_op_fpush(); |
| 1733 | 1803 | gen_op_fildll_ST0_A0(); |
| ... | ... | @@ -1737,7 +1807,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1737 | 1807 | gen_op_fpop(); |
| 1738 | 1808 | break; |
| 1739 | 1809 | default: |
| 1740 | - error("unhandled memory FP\n"); | |
| 1810 | + error("unhandled memory FP [op=0x%02x]\n", op); | |
| 1741 | 1811 | return -1; |
| 1742 | 1812 | } |
| 1743 | 1813 | } else { |
| ... | ... | @@ -1987,11 +2057,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 1987 | 2057 | else |
| 1988 | 2058 | ot = dflag ? OT_LONG : OT_WORD; |
| 1989 | 2059 | if (prefixes & PREFIX_REPNZ) { |
| 2060 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2061 | + gen_op_set_cc_op(s->cc_op); | |
| 1990 | 2062 | gen_op_scas[6 + ot](); |
| 2063 | + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | |
| 1991 | 2064 | } else if (prefixes & PREFIX_REPZ) { |
| 2065 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2066 | + gen_op_set_cc_op(s->cc_op); | |
| 1992 | 2067 | gen_op_scas[3 + ot](); |
| 2068 | + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | |
| 1993 | 2069 | } else { |
| 1994 | 2070 | gen_op_scas[ot](); |
| 2071 | + s->cc_op = CC_OP_SUBB + ot; | |
| 1995 | 2072 | } |
| 1996 | 2073 | break; |
| 1997 | 2074 | |
| ... | ... | @@ -2002,11 +2079,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 2002 | 2079 | else |
| 2003 | 2080 | ot = dflag ? OT_LONG : OT_WORD; |
| 2004 | 2081 | if (prefixes & PREFIX_REPNZ) { |
| 2082 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2083 | + gen_op_set_cc_op(s->cc_op); | |
| 2005 | 2084 | gen_op_cmps[6 + ot](); |
| 2085 | + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | |
| 2006 | 2086 | } else if (prefixes & PREFIX_REPZ) { |
| 2087 | + if (s->cc_op != CC_OP_DYNAMIC) | |
| 2088 | + gen_op_set_cc_op(s->cc_op); | |
| 2007 | 2089 | gen_op_cmps[3 + ot](); |
| 2090 | + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ | |
| 2008 | 2091 | } else { |
| 2009 | 2092 | gen_op_cmps[ot](); |
| 2093 | + s->cc_op = CC_OP_SUBB + ot; | |
| 2010 | 2094 | } |
| 2011 | 2095 | break; |
| 2012 | 2096 | |
| ... | ... | @@ -2187,6 +2271,74 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 2187 | 2271 | break; |
| 2188 | 2272 | |
| 2189 | 2273 | /************************/ |
| 2274 | + /* bit operations */ | |
| 2275 | + case 0x1ba: /* bt/bts/btr/btc Gv, im */ | |
| 2276 | + ot = dflag ? OT_LONG : OT_WORD; | |
| 2277 | + modrm = ldub(s->pc++); | |
| 2278 | + op = (modrm >> 3) & 7; | |
| 2279 | + mod = (modrm >> 6) & 3; | |
| 2280 | + rm = modrm & 7; | |
| 2281 | + if (mod != 3) { | |
| 2282 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | |
| 2283 | + gen_op_ld_T0_A0[ot](); | |
| 2284 | + } else { | |
| 2285 | + gen_op_mov_TN_reg[ot][0][rm](); | |
| 2286 | + } | |
| 2287 | + /* load shift */ | |
| 2288 | + val = ldub(s->pc++); | |
| 2289 | + gen_op_movl_T1_im(val); | |
| 2290 | + if (op < 4) | |
| 2291 | + return -1; | |
| 2292 | + op -= 4; | |
| 2293 | + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); | |
| 2294 | + s->cc_op = CC_OP_SHLB + ot; | |
| 2295 | + if (op != 0) { | |
| 2296 | + if (mod != 3) | |
| 2297 | + gen_op_st_T0_A0[ot](); | |
| 2298 | + else | |
| 2299 | + gen_op_mov_reg_T0[ot][rm](); | |
| 2300 | + } | |
| 2301 | + break; | |
| 2302 | + case 0x1a3: /* bt Gv, Ev */ | |
| 2303 | + op = 0; | |
| 2304 | + goto do_btx; | |
| 2305 | + case 0x1ab: /* bts */ | |
| 2306 | + op = 1; | |
| 2307 | + goto do_btx; | |
| 2308 | + case 0x1b3: /* btr */ | |
| 2309 | + op = 2; | |
| 2310 | + goto do_btx; | |
| 2311 | + case 0x1bb: /* btc */ | |
| 2312 | + op = 3; | |
| 2313 | + do_btx: | |
| 2314 | + ot = dflag ? OT_LONG : OT_WORD; | |
| 2315 | + modrm = ldub(s->pc++); | |
| 2316 | + reg = (modrm >> 3) & 7; | |
| 2317 | + mod = (modrm >> 6) & 3; | |
| 2318 | + rm = modrm & 7; | |
| 2319 | + gen_op_mov_TN_reg[OT_LONG][1][reg](); | |
| 2320 | + if (mod != 3) { | |
| 2321 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | |
| 2322 | + /* specific case: we need to add a displacement */ | |
| 2323 | + if (ot == OT_WORD) | |
| 2324 | + gen_op_add_bitw_A0_T1(); | |
| 2325 | + else | |
| 2326 | + gen_op_add_bitl_A0_T1(); | |
| 2327 | + gen_op_ld_T0_A0[ot](); | |
| 2328 | + } else { | |
| 2329 | + gen_op_mov_TN_reg[ot][0][rm](); | |
| 2330 | + } | |
| 2331 | + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); | |
| 2332 | + s->cc_op = CC_OP_SHLB + ot; | |
| 2333 | + if (op != 0) { | |
| 2334 | + if (mod != 3) | |
| 2335 | + gen_op_st_T0_A0[ot](); | |
| 2336 | + else | |
| 2337 | + gen_op_mov_reg_T0[ot][rm](); | |
| 2338 | + } | |
| 2339 | + break; | |
| 2340 | + | |
| 2341 | + /************************/ | |
| 2190 | 2342 | /* misc */ |
| 2191 | 2343 | case 0x90: /* nop */ |
| 2192 | 2344 | break; |
| ... | ... | @@ -2206,6 +2358,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) |
| 2206 | 2358 | gen_op_into((long)pc_start, (long)s->pc); |
| 2207 | 2359 | *is_jmp_ptr = 1; |
| 2208 | 2360 | break; |
| 2361 | + case 0x1c8 ... 0x1cf: /* bswap reg */ | |
| 2362 | + reg = b & 7; | |
| 2363 | + gen_op_mov_TN_reg[OT_LONG][0][reg](); | |
| 2364 | + gen_op_bswapl_T0(); | |
| 2365 | + gen_op_mov_reg_T0[OT_LONG][reg](); | |
| 2366 | + break; | |
| 2367 | + | |
| 2209 | 2368 | #if 0 |
| 2210 | 2369 | case 0x1a2: /* cpuid */ |
| 2211 | 2370 | gen_insn0(OP_ASM); | ... | ... |