Revision 4b74fe1f
b/cpu-i386.h | ||
---|---|---|
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 | 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 |
|
b/dyngen.c | ||
---|---|---|
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; |
b/linux-user/main.c | ||
---|---|---|
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(); |
b/op-i386.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 1741 |
"SHLB", |
1667 | 1742 |
"SHLW", |
1668 | 1743 |
"SHLL", |
1744 |
"SARB", |
|
1745 |
"SARW", |
|
1746 |
"SARL", |
|
1669 | 1747 |
}; |
1670 | 1748 |
#endif |
1671 | 1749 |
|
... | ... | |
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); |
b/ops_template.h | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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; |
b/tests/Makefile | ||
---|---|---|
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 |
b/tests/test-i386.c | ||
---|---|---|
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 | 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 | 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 |
} |
b/translate-i386.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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; |
Also available in: Unified diff