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); | ... | ... |