]> git.proxmox.com Git - qemu.git/blame - translate-i386.c
added CPL/IOPL support - fixed subtle inc/dec flag optimisation bug - added HLT instr...
[qemu.git] / translate-i386.c
CommitLineData
7d13299d
FB
1/*
2 * i386 translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
3ef693a0
FB
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
7d13299d 10 *
3ef693a0
FB
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
7d13299d 15 *
3ef693a0
FB
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
7d13299d 19 */
367e86e8
FB
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
9de5e440 25#include <signal.h>
367e86e8
FB
26#include <assert.h>
27
b9adb4a6
FB
28#include "disas.h"
29
0ecfa993 30#define DEBUG_DISAS
0ecfa993 31
586314f2
FB
32#define IN_OP_I386
33#include "cpu-i386.h"
34
6dbad63e
FB
35#ifndef offsetof
36#define offsetof(type, field) ((size_t) &((type *)0)->field)
37#endif
38
04369ff2 39/* XXX: move that elsewhere */
dc99065b
FB
40static uint16_t *gen_opc_ptr;
41static uint32_t *gen_opparam_ptr;
367e86e8
FB
42int __op_param1, __op_param2, __op_param3;
43
04369ff2
FB
44#ifdef __i386__
45static inline void flush_icache_range(unsigned long start, unsigned long stop)
46{
47}
48#endif
49
fb3e5849
FB
50#ifdef __s390__
51static inline void flush_icache_range(unsigned long start, unsigned long stop)
52{
53}
54#endif
55
efdea7bf
FB
56#ifdef __ia64__
57static inline void flush_icache_range(unsigned long start, unsigned long stop)
58{
59}
60#endif
61
04369ff2
FB
62#ifdef __powerpc__
63
64#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
65
66static void inline flush_icache_range(unsigned long start, unsigned long stop)
67{
68 unsigned long p;
69
70 p = start & ~(MIN_CACHE_LINE_SIZE - 1);
71 stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
72
73 for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
74 asm ("dcbst 0,%0;" : : "r"(p) : "memory");
75 }
76 asm ("sync");
77 for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
78 asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
79 }
80 asm ("sync");
81 asm ("isync");
82}
83#endif
84
efdea7bf
FB
85#ifdef __alpha__
86static inline void flush_icache_range(unsigned long start, unsigned long stop)
87{
88 asm ("imb");
89}
90#endif
91
d014c98c
FB
92#ifdef __sparc__
93
94static void inline flush_icache_range(unsigned long start, unsigned long stop)
95{
96 unsigned long p;
97
98 p = start & ~(8UL - 1UL);
99 stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
100
101 for (; p < stop; p += 8)
102 __asm__ __volatile__("flush\t%0" : : "r" (p));
103}
104
105#endif
106
586314f2
FB
107extern FILE *logfile;
108extern int loglevel;
0ecfa993 109
9c605cb1
FB
110#define PREFIX_REPZ 0x01
111#define PREFIX_REPNZ 0x02
112#define PREFIX_LOCK 0x04
113#define PREFIX_DATA 0x08
114#define PREFIX_ADR 0x10
115#define PREFIX_FWAIT 0x20
367e86e8
FB
116
117typedef struct DisasContext {
118 /* current insn context */
9c605cb1 119 int override; /* -1 if no override */
367e86e8
FB
120 int prefix;
121 int aflag, dflag;
dab2ed99 122 uint8_t *pc; /* pc = eip + cs_base */
6dbad63e
FB
123 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
124 static state change (stop translation) */
125 /* current block context */
dab2ed99 126 uint8_t *cs_base; /* base of CS segment */
6dbad63e 127 int code32; /* 32 bit code segment */
dab2ed99 128 int ss32; /* 32 bit stack segment */
6dbad63e
FB
129 int cc_op; /* current CC operation */
130 int addseg; /* non zero if either DS/ES/SS have a non zero base */
131 int f_st; /* currently unused */
9c605cb1 132 int vm86; /* vm86 mode */
982b4315
FB
133 int cpl;
134 int iopl;
367e86e8
FB
135} DisasContext;
136
137/* i386 arith/logic operations */
138enum {
139 OP_ADDL,
140 OP_ORL,
141 OP_ADCL,
142 OP_SBBL,
143 OP_ANDL,
144 OP_SUBL,
145 OP_XORL,
146 OP_CMPL,
147};
148
149/* i386 shift ops */
150enum {
151 OP_ROL,
152 OP_ROR,
153 OP_RCL,
154 OP_RCR,
155 OP_SHL,
156 OP_SHR,
157 OP_SHL1, /* undocumented */
158 OP_SAR = 7,
159};
160
dc99065b 161enum {
9c605cb1 162#define DEF(s, n) INDEX_op_ ## s,
dc99065b
FB
163#include "opc-i386.h"
164#undef DEF
165 NB_OPS,
166};
167
367e86e8
FB
168#include "op-i386.h"
169
170/* operand size */
171enum {
172 OT_BYTE = 0,
173 OT_WORD,
174 OT_LONG,
175 OT_QUAD,
176};
177
178enum {
179 /* I386 int registers */
180 OR_EAX, /* MUST be even numbered */
181 OR_ECX,
182 OR_EDX,
183 OR_EBX,
184 OR_ESP,
185 OR_EBP,
186 OR_ESI,
187 OR_EDI,
367e86e8
FB
188 OR_TMP0, /* temporary operand register */
189 OR_TMP1,
190 OR_A0, /* temporary register used when doing address evaluation */
367e86e8 191 OR_ZERO, /* fixed zero register */
367e86e8
FB
192 NB_OREGS,
193};
194
367e86e8
FB
195typedef void (GenOpFunc)(void);
196typedef void (GenOpFunc1)(long);
197typedef void (GenOpFunc2)(long, long);
198
199static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
200 [OT_BYTE] = {
201 gen_op_movb_EAX_T0,
202 gen_op_movb_ECX_T0,
203 gen_op_movb_EDX_T0,
204 gen_op_movb_EBX_T0,
205 gen_op_movh_EAX_T0,
206 gen_op_movh_ECX_T0,
207 gen_op_movh_EDX_T0,
208 gen_op_movh_EBX_T0,
209 },
210 [OT_WORD] = {
211 gen_op_movw_EAX_T0,
212 gen_op_movw_ECX_T0,
213 gen_op_movw_EDX_T0,
214 gen_op_movw_EBX_T0,
215 gen_op_movw_ESP_T0,
216 gen_op_movw_EBP_T0,
217 gen_op_movw_ESI_T0,
218 gen_op_movw_EDI_T0,
219 },
220 [OT_LONG] = {
221 gen_op_movl_EAX_T0,
222 gen_op_movl_ECX_T0,
223 gen_op_movl_EDX_T0,
224 gen_op_movl_EBX_T0,
225 gen_op_movl_ESP_T0,
226 gen_op_movl_EBP_T0,
227 gen_op_movl_ESI_T0,
228 gen_op_movl_EDI_T0,
229 },
230};
231
232static GenOpFunc *gen_op_mov_reg_T1[3][8] = {
233 [OT_BYTE] = {
234 gen_op_movb_EAX_T1,
235 gen_op_movb_ECX_T1,
236 gen_op_movb_EDX_T1,
237 gen_op_movb_EBX_T1,
238 gen_op_movh_EAX_T1,
239 gen_op_movh_ECX_T1,
240 gen_op_movh_EDX_T1,
241 gen_op_movh_EBX_T1,
242 },
243 [OT_WORD] = {
244 gen_op_movw_EAX_T1,
245 gen_op_movw_ECX_T1,
246 gen_op_movw_EDX_T1,
247 gen_op_movw_EBX_T1,
248 gen_op_movw_ESP_T1,
249 gen_op_movw_EBP_T1,
250 gen_op_movw_ESI_T1,
251 gen_op_movw_EDI_T1,
252 },
253 [OT_LONG] = {
254 gen_op_movl_EAX_T1,
255 gen_op_movl_ECX_T1,
256 gen_op_movl_EDX_T1,
257 gen_op_movl_EBX_T1,
258 gen_op_movl_ESP_T1,
259 gen_op_movl_EBP_T1,
260 gen_op_movl_ESI_T1,
261 gen_op_movl_EDI_T1,
262 },
263};
264
265static GenOpFunc *gen_op_mov_reg_A0[2][8] = {
266 [0] = {
267 gen_op_movw_EAX_A0,
268 gen_op_movw_ECX_A0,
269 gen_op_movw_EDX_A0,
270 gen_op_movw_EBX_A0,
271 gen_op_movw_ESP_A0,
272 gen_op_movw_EBP_A0,
273 gen_op_movw_ESI_A0,
274 gen_op_movw_EDI_A0,
275 },
276 [1] = {
277 gen_op_movl_EAX_A0,
278 gen_op_movl_ECX_A0,
279 gen_op_movl_EDX_A0,
280 gen_op_movl_EBX_A0,
281 gen_op_movl_ESP_A0,
282 gen_op_movl_EBP_A0,
283 gen_op_movl_ESI_A0,
284 gen_op_movl_EDI_A0,
285 },
286};
287
288static GenOpFunc *gen_op_mov_TN_reg[3][2][8] =
289{
290 [OT_BYTE] = {
291 {
292 gen_op_movl_T0_EAX,
293 gen_op_movl_T0_ECX,
294 gen_op_movl_T0_EDX,
295 gen_op_movl_T0_EBX,
296 gen_op_movh_T0_EAX,
297 gen_op_movh_T0_ECX,
298 gen_op_movh_T0_EDX,
299 gen_op_movh_T0_EBX,
300 },
301 {
302 gen_op_movl_T1_EAX,
303 gen_op_movl_T1_ECX,
304 gen_op_movl_T1_EDX,
305 gen_op_movl_T1_EBX,
306 gen_op_movh_T1_EAX,
307 gen_op_movh_T1_ECX,
308 gen_op_movh_T1_EDX,
309 gen_op_movh_T1_EBX,
310 },
311 },
312 [OT_WORD] = {
313 {
314 gen_op_movl_T0_EAX,
315 gen_op_movl_T0_ECX,
316 gen_op_movl_T0_EDX,
317 gen_op_movl_T0_EBX,
318 gen_op_movl_T0_ESP,
319 gen_op_movl_T0_EBP,
320 gen_op_movl_T0_ESI,
321 gen_op_movl_T0_EDI,
322 },
323 {
324 gen_op_movl_T1_EAX,
325 gen_op_movl_T1_ECX,
326 gen_op_movl_T1_EDX,
327 gen_op_movl_T1_EBX,
328 gen_op_movl_T1_ESP,
329 gen_op_movl_T1_EBP,
330 gen_op_movl_T1_ESI,
331 gen_op_movl_T1_EDI,
332 },
333 },
334 [OT_LONG] = {
335 {
336 gen_op_movl_T0_EAX,
337 gen_op_movl_T0_ECX,
338 gen_op_movl_T0_EDX,
339 gen_op_movl_T0_EBX,
340 gen_op_movl_T0_ESP,
341 gen_op_movl_T0_EBP,
342 gen_op_movl_T0_ESI,
343 gen_op_movl_T0_EDI,
344 },
345 {
346 gen_op_movl_T1_EAX,
347 gen_op_movl_T1_ECX,
348 gen_op_movl_T1_EDX,
349 gen_op_movl_T1_EBX,
350 gen_op_movl_T1_ESP,
351 gen_op_movl_T1_EBP,
352 gen_op_movl_T1_ESI,
353 gen_op_movl_T1_EDI,
354 },
355 },
356};
357
358static GenOpFunc *gen_op_movl_A0_reg[8] = {
359 gen_op_movl_A0_EAX,
360 gen_op_movl_A0_ECX,
361 gen_op_movl_A0_EDX,
362 gen_op_movl_A0_EBX,
363 gen_op_movl_A0_ESP,
364 gen_op_movl_A0_EBP,
365 gen_op_movl_A0_ESI,
366 gen_op_movl_A0_EDI,
367};
368
369static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = {
370 [0] = {
371 gen_op_addl_A0_EAX,
372 gen_op_addl_A0_ECX,
373 gen_op_addl_A0_EDX,
374 gen_op_addl_A0_EBX,
375 gen_op_addl_A0_ESP,
376 gen_op_addl_A0_EBP,
377 gen_op_addl_A0_ESI,
378 gen_op_addl_A0_EDI,
379 },
380 [1] = {
381 gen_op_addl_A0_EAX_s1,
382 gen_op_addl_A0_ECX_s1,
383 gen_op_addl_A0_EDX_s1,
384 gen_op_addl_A0_EBX_s1,
385 gen_op_addl_A0_ESP_s1,
386 gen_op_addl_A0_EBP_s1,
387 gen_op_addl_A0_ESI_s1,
388 gen_op_addl_A0_EDI_s1,
389 },
390 [2] = {
391 gen_op_addl_A0_EAX_s2,
392 gen_op_addl_A0_ECX_s2,
393 gen_op_addl_A0_EDX_s2,
394 gen_op_addl_A0_EBX_s2,
395 gen_op_addl_A0_ESP_s2,
396 gen_op_addl_A0_EBP_s2,
397 gen_op_addl_A0_ESI_s2,
398 gen_op_addl_A0_EDI_s2,
399 },
400 [3] = {
401 gen_op_addl_A0_EAX_s3,
402 gen_op_addl_A0_ECX_s3,
403 gen_op_addl_A0_EDX_s3,
404 gen_op_addl_A0_EBX_s3,
405 gen_op_addl_A0_ESP_s3,
406 gen_op_addl_A0_EBP_s3,
407 gen_op_addl_A0_ESI_s3,
408 gen_op_addl_A0_EDI_s3,
409 },
410};
411
5dd9488c
FB
412static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = {
413 [0] = {
414 gen_op_cmovw_EAX_T1_T0,
415 gen_op_cmovw_ECX_T1_T0,
416 gen_op_cmovw_EDX_T1_T0,
417 gen_op_cmovw_EBX_T1_T0,
418 gen_op_cmovw_ESP_T1_T0,
419 gen_op_cmovw_EBP_T1_T0,
420 gen_op_cmovw_ESI_T1_T0,
421 gen_op_cmovw_EDI_T1_T0,
422 },
423 [1] = {
424 gen_op_cmovl_EAX_T1_T0,
425 gen_op_cmovl_ECX_T1_T0,
426 gen_op_cmovl_EDX_T1_T0,
427 gen_op_cmovl_EBX_T1_T0,
428 gen_op_cmovl_ESP_T1_T0,
429 gen_op_cmovl_EBP_T1_T0,
430 gen_op_cmovl_ESI_T1_T0,
431 gen_op_cmovl_EDI_T1_T0,
432 },
433};
434
367e86e8
FB
435static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
436 gen_op_addl_T0_T1_cc,
437 gen_op_orl_T0_T1_cc,
4b74fe1f
FB
438 NULL,
439 NULL,
367e86e8
FB
440 gen_op_andl_T0_T1_cc,
441 gen_op_subl_T0_T1_cc,
442 gen_op_xorl_T0_T1_cc,
443 gen_op_cmpl_T0_T1_cc,
444};
445
4b74fe1f
FB
446static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
447 [OT_BYTE] = {
448 gen_op_adcb_T0_T1_cc,
449 gen_op_sbbb_T0_T1_cc,
450 },
451 [OT_WORD] = {
452 gen_op_adcw_T0_T1_cc,
453 gen_op_sbbw_T0_T1_cc,
454 },
455 [OT_LONG] = {
456 gen_op_adcl_T0_T1_cc,
457 gen_op_sbbl_T0_T1_cc,
458 },
459};
460
367e86e8
FB
461static const int cc_op_arithb[8] = {
462 CC_OP_ADDB,
463 CC_OP_LOGICB,
464 CC_OP_ADDB,
465 CC_OP_SUBB,
466 CC_OP_LOGICB,
467 CC_OP_SUBB,
468 CC_OP_LOGICB,
469 CC_OP_SUBB,
470};
471
1a9353d2
FB
472static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
473 gen_op_cmpxchgb_T0_T1_EAX_cc,
474 gen_op_cmpxchgw_T0_T1_EAX_cc,
475 gen_op_cmpxchgl_T0_T1_EAX_cc,
476};
477
367e86e8
FB
478static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
479 [OT_BYTE] = {
480 gen_op_rolb_T0_T1_cc,
481 gen_op_rorb_T0_T1_cc,
482 gen_op_rclb_T0_T1_cc,
483 gen_op_rcrb_T0_T1_cc,
484 gen_op_shlb_T0_T1_cc,
485 gen_op_shrb_T0_T1_cc,
486 gen_op_shlb_T0_T1_cc,
487 gen_op_sarb_T0_T1_cc,
488 },
489 [OT_WORD] = {
490 gen_op_rolw_T0_T1_cc,
491 gen_op_rorw_T0_T1_cc,
492 gen_op_rclw_T0_T1_cc,
493 gen_op_rcrw_T0_T1_cc,
494 gen_op_shlw_T0_T1_cc,
495 gen_op_shrw_T0_T1_cc,
496 gen_op_shlw_T0_T1_cc,
497 gen_op_sarw_T0_T1_cc,
498 },
499 [OT_LONG] = {
500 gen_op_roll_T0_T1_cc,
501 gen_op_rorl_T0_T1_cc,
502 gen_op_rcll_T0_T1_cc,
503 gen_op_rcrl_T0_T1_cc,
504 gen_op_shll_T0_T1_cc,
505 gen_op_shrl_T0_T1_cc,
506 gen_op_shll_T0_T1_cc,
507 gen_op_sarl_T0_T1_cc,
508 },
509};
510
d57c4e01
FB
511static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = {
512 [0] = {
513 gen_op_shldw_T0_T1_im_cc,
514 gen_op_shrdw_T0_T1_im_cc,
515 },
516 [1] = {
517 gen_op_shldl_T0_T1_im_cc,
518 gen_op_shrdl_T0_T1_im_cc,
519 },
520};
521
522static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = {
523 [0] = {
524 gen_op_shldw_T0_T1_ECX_cc,
525 gen_op_shrdw_T0_T1_ECX_cc,
526 },
527 [1] = {
528 gen_op_shldl_T0_T1_ECX_cc,
529 gen_op_shrdl_T0_T1_ECX_cc,
530 },
531};
532
4b74fe1f
FB
533static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
534 [0] = {
535 gen_op_btw_T0_T1_cc,
536 gen_op_btsw_T0_T1_cc,
537 gen_op_btrw_T0_T1_cc,
538 gen_op_btcw_T0_T1_cc,
539 },
540 [1] = {
541 gen_op_btl_T0_T1_cc,
542 gen_op_btsl_T0_T1_cc,
543 gen_op_btrl_T0_T1_cc,
544 gen_op_btcl_T0_T1_cc,
545 },
546};
547
77f8dd5a
FB
548static GenOpFunc *gen_op_bsx_T0_cc[2][2] = {
549 [0] = {
550 gen_op_bsfw_T0_cc,
551 gen_op_bsrw_T0_cc,
552 },
553 [1] = {
554 gen_op_bsfl_T0_cc,
555 gen_op_bsrl_T0_cc,
556 },
557};
558
367e86e8
FB
559static GenOpFunc *gen_op_lds_T0_A0[3] = {
560 gen_op_ldsb_T0_A0,
561 gen_op_ldsw_T0_A0,
562};
563
564static GenOpFunc *gen_op_ldu_T0_A0[3] = {
565 gen_op_ldub_T0_A0,
566 gen_op_lduw_T0_A0,
567};
568
569/* sign does not matter */
570static GenOpFunc *gen_op_ld_T0_A0[3] = {
571 gen_op_ldub_T0_A0,
572 gen_op_lduw_T0_A0,
573 gen_op_ldl_T0_A0,
574};
575
576static GenOpFunc *gen_op_ld_T1_A0[3] = {
577 gen_op_ldub_T1_A0,
578 gen_op_lduw_T1_A0,
579 gen_op_ldl_T1_A0,
580};
581
582static GenOpFunc *gen_op_st_T0_A0[3] = {
583 gen_op_stb_T0_A0,
584 gen_op_stw_T0_A0,
585 gen_op_stl_T0_A0,
586};
587
9c605cb1
FB
588/* the _a32 and _a16 string operations use A0 as the base register. */
589
590#define STRINGOP(x) \
591 gen_op_ ## x ## b_fast, \
592 gen_op_ ## x ## w_fast, \
593 gen_op_ ## x ## l_fast, \
594 gen_op_ ## x ## b_a32, \
595 gen_op_ ## x ## w_a32, \
596 gen_op_ ## x ## l_a32, \
597 gen_op_ ## x ## b_a16, \
598 gen_op_ ## x ## w_a16, \
599 gen_op_ ## x ## l_a16,
600
601static GenOpFunc *gen_op_movs[9 * 2] = {
602 STRINGOP(movs)
603 STRINGOP(rep_movs)
367e86e8
FB
604};
605
9c605cb1
FB
606static GenOpFunc *gen_op_stos[9 * 2] = {
607 STRINGOP(stos)
608 STRINGOP(rep_stos)
367e86e8
FB
609};
610
9c605cb1
FB
611static GenOpFunc *gen_op_lods[9 * 2] = {
612 STRINGOP(lods)
613 STRINGOP(rep_lods)
367e86e8
FB
614};
615
9c605cb1
FB
616static GenOpFunc *gen_op_scas[9 * 3] = {
617 STRINGOP(scas)
618 STRINGOP(repz_scas)
619 STRINGOP(repnz_scas)
367e86e8
FB
620};
621
9c605cb1
FB
622static GenOpFunc *gen_op_cmps[9 * 3] = {
623 STRINGOP(cmps)
624 STRINGOP(repz_cmps)
625 STRINGOP(repnz_cmps)
367e86e8
FB
626};
627
9c605cb1
FB
628static GenOpFunc *gen_op_ins[9 * 2] = {
629 STRINGOP(ins)
630 STRINGOP(rep_ins)
367e86e8
FB
631};
632
633
9c605cb1
FB
634static GenOpFunc *gen_op_outs[9 * 2] = {
635 STRINGOP(outs)
636 STRINGOP(rep_outs)
367e86e8
FB
637};
638
9c605cb1
FB
639
640static inline void gen_string_ds(DisasContext *s, int ot, GenOpFunc **func)
641{
642 int index, override;
643
644 override = s->override;
645 if (s->aflag) {
646 /* 32 bit address */
647 if (s->addseg && override < 0)
648 override = R_DS;
649 if (override >= 0) {
650 gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
651 index = 3 + ot;
652 } else {
653 index = ot;
654 }
655 } else {
656 if (override < 0)
657 override = R_DS;
658 gen_op_movl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
659 /* 16 address, always override */
660 index = 6 + ot;
661 }
662 func[index]();
663}
664
665static inline void gen_string_es(DisasContext *s, int ot, GenOpFunc **func)
666{
667 int index;
668
669 if (s->aflag) {
670 if (s->addseg) {
671 index = 3 + ot;
672 } else {
673 index = ot;
674 }
675 } else {
676 index = 6 + ot;
677 }
678 func[index]();
679}
680
681
ba1c6e37
FB
682static GenOpFunc *gen_op_in[3] = {
683 gen_op_inb_T0_T1,
684 gen_op_inw_T0_T1,
685 gen_op_inl_T0_T1,
686};
687
688static GenOpFunc *gen_op_out[3] = {
689 gen_op_outb_T0_T1,
690 gen_op_outw_T0_T1,
691 gen_op_outl_T0_T1,
692};
693
367e86e8
FB
694enum {
695 JCC_O,
696 JCC_B,
697 JCC_Z,
698 JCC_BE,
699 JCC_S,
700 JCC_P,
701 JCC_L,
702 JCC_LE,
703};
704
705static GenOpFunc2 *gen_jcc_slow[8] = {
706 gen_op_jo_cc,
707 gen_op_jb_cc,
708 gen_op_jz_cc,
709 gen_op_jbe_cc,
710 gen_op_js_cc,
711 gen_op_jp_cc,
712 gen_op_jl_cc,
713 gen_op_jle_cc,
714};
715
716static GenOpFunc2 *gen_jcc_sub[3][8] = {
717 [OT_BYTE] = {
718 NULL,
719 gen_op_jb_subb,
720 gen_op_jz_subb,
721 gen_op_jbe_subb,
722 gen_op_js_subb,
723 NULL,
724 gen_op_jl_subb,
725 gen_op_jle_subb,
726 },
727 [OT_WORD] = {
728 NULL,
729 gen_op_jb_subw,
730 gen_op_jz_subw,
731 gen_op_jbe_subw,
732 gen_op_js_subw,
733 NULL,
734 gen_op_jl_subw,
735 gen_op_jle_subw,
736 },
737 [OT_LONG] = {
738 NULL,
739 gen_op_jb_subl,
740 gen_op_jz_subl,
741 gen_op_jbe_subl,
742 gen_op_js_subl,
743 NULL,
744 gen_op_jl_subl,
745 gen_op_jle_subl,
746 },
747};
1a9353d2
FB
748static GenOpFunc2 *gen_op_loop[2][4] = {
749 [0] = {
750 gen_op_loopnzw,
751 gen_op_loopzw,
752 gen_op_loopw,
753 gen_op_jecxzw,
754 },
755 [1] = {
756 gen_op_loopnzl,
757 gen_op_loopzl,
758 gen_op_loopl,
759 gen_op_jecxzl,
760 },
761};
367e86e8
FB
762
763static GenOpFunc *gen_setcc_slow[8] = {
764 gen_op_seto_T0_cc,
765 gen_op_setb_T0_cc,
766 gen_op_setz_T0_cc,
767 gen_op_setbe_T0_cc,
768 gen_op_sets_T0_cc,
769 gen_op_setp_T0_cc,
770 gen_op_setl_T0_cc,
771 gen_op_setle_T0_cc,
772};
773
774static GenOpFunc *gen_setcc_sub[3][8] = {
775 [OT_BYTE] = {
776 NULL,
777 gen_op_setb_T0_subb,
778 gen_op_setz_T0_subb,
779 gen_op_setbe_T0_subb,
780 gen_op_sets_T0_subb,
781 NULL,
782 gen_op_setl_T0_subb,
783 gen_op_setle_T0_subb,
784 },
785 [OT_WORD] = {
786 NULL,
787 gen_op_setb_T0_subw,
788 gen_op_setz_T0_subw,
789 gen_op_setbe_T0_subw,
790 gen_op_sets_T0_subw,
791 NULL,
792 gen_op_setl_T0_subw,
793 gen_op_setle_T0_subw,
794 },
795 [OT_LONG] = {
796 NULL,
797 gen_op_setb_T0_subl,
798 gen_op_setz_T0_subl,
799 gen_op_setbe_T0_subl,
800 gen_op_sets_T0_subl,
801 NULL,
802 gen_op_setl_T0_subl,
803 gen_op_setle_T0_subl,
804 },
805};
806
927f621e
FB
807static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = {
808 gen_op_fadd_ST0_FT0,
809 gen_op_fmul_ST0_FT0,
810 gen_op_fcom_ST0_FT0,
811 gen_op_fcom_ST0_FT0,
812 gen_op_fsub_ST0_FT0,
813 gen_op_fsubr_ST0_FT0,
814 gen_op_fdiv_ST0_FT0,
815 gen_op_fdivr_ST0_FT0,
816};
817
77f8dd5a 818/* NOTE the exception in "r" op ordering */
927f621e
FB
819static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
820 gen_op_fadd_STN_ST0,
821 gen_op_fmul_STN_ST0,
822 NULL,
823 NULL,
927f621e 824 gen_op_fsubr_STN_ST0,
77f8dd5a 825 gen_op_fsub_STN_ST0,
927f621e 826 gen_op_fdivr_STN_ST0,
77f8dd5a 827 gen_op_fdiv_STN_ST0,
927f621e
FB
828};
829
367e86e8
FB
830static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
831{
832 if (d != OR_TMP0)
833 gen_op_mov_TN_reg[ot][0][d]();
834 if (s != OR_TMP1)
835 gen_op_mov_TN_reg[ot][1][s]();
4b74fe1f
FB
836 if (op == OP_ADCL || op == OP_SBBL) {
837 if (s1->cc_op != CC_OP_DYNAMIC)
838 gen_op_set_cc_op(s1->cc_op);
839 gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
840 s1->cc_op = CC_OP_DYNAMIC;
841 } else {
842 gen_op_arith_T0_T1_cc[op]();
843 s1->cc_op = cc_op_arithb[op] + ot;
844 }
367e86e8
FB
845 if (d != OR_TMP0 && op != OP_CMPL)
846 gen_op_mov_reg_T0[ot][d]();
367e86e8
FB
847}
848
849static void gen_opi(DisasContext *s1, int op, int ot, int d, int c)
850{
ba1c6e37 851 gen_op_movl_T1_im(c);
4b74fe1f 852 gen_op(s1, op, ot, d, OR_TMP1);
367e86e8
FB
853}
854
855static void gen_inc(DisasContext *s1, int ot, int d, int c)
856{
857 if (d != OR_TMP0)
858 gen_op_mov_TN_reg[ot][0][d]();
859 if (s1->cc_op != CC_OP_DYNAMIC)
860 gen_op_set_cc_op(s1->cc_op);
4b74fe1f 861 if (c > 0) {
367e86e8 862 gen_op_incl_T0_cc();
4b74fe1f
FB
863 s1->cc_op = CC_OP_INCB + ot;
864 } else {
367e86e8 865 gen_op_decl_T0_cc();
4b74fe1f
FB
866 s1->cc_op = CC_OP_DECB + ot;
867 }
367e86e8
FB
868 if (d != OR_TMP0)
869 gen_op_mov_reg_T0[ot][d]();
870}
871
872static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
873{
874 if (d != OR_TMP0)
875 gen_op_mov_TN_reg[ot][0][d]();
876 if (s != OR_TMP1)
877 gen_op_mov_TN_reg[ot][1][s]();
4b74fe1f
FB
878 /* for zero counts, flags are not updated, so must do it dynamically */
879 if (s1->cc_op != CC_OP_DYNAMIC)
880 gen_op_set_cc_op(s1->cc_op);
881
882 gen_op_shift_T0_T1_cc[ot][op]();
883
367e86e8
FB
884 if (d != OR_TMP0)
885 gen_op_mov_reg_T0[ot][d]();
886 s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
887}
888
889static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
890{
891 /* currently not optimized */
ba1c6e37 892 gen_op_movl_T1_im(c);
367e86e8
FB
893 gen_shift(s1, op, ot, d, OR_TMP1);
894}
895
896static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
897{
898 int havesib;
367e86e8 899 int base, disp;
6dbad63e
FB
900 int index;
901 int scale;
902 int opreg;
903 int mod, rm, code, override, must_add_seg;
904
9c605cb1 905 override = s->override;
6dbad63e 906 must_add_seg = s->addseg;
9c605cb1 907 if (override >= 0)
6dbad63e 908 must_add_seg = 1;
367e86e8
FB
909 mod = (modrm >> 6) & 3;
910 rm = modrm & 7;
911
912 if (s->aflag) {
913
914 havesib = 0;
367e86e8 915 base = rm;
6dbad63e
FB
916 index = 0;
917 scale = 0;
367e86e8
FB
918
919 if (base == 4) {
920 havesib = 1;
921 code = ldub(s->pc++);
922 scale = (code >> 6) & 3;
923 index = (code >> 3) & 7;
924 base = code & 7;
925 }
926
927 switch (mod) {
928 case 0:
929 if (base == 5) {
6dbad63e 930 base = -1;
367e86e8
FB
931 disp = ldl(s->pc);
932 s->pc += 4;
933 } else {
934 disp = 0;
935 }
936 break;
937 case 1:
938 disp = (int8_t)ldub(s->pc++);
939 break;
940 default:
941 case 2:
942 disp = ldl(s->pc);
943 s->pc += 4;
944 break;
945 }
6dbad63e
FB
946
947 if (base >= 0) {
948 gen_op_movl_A0_reg[base]();
949 if (disp != 0)
950 gen_op_addl_A0_im(disp);
367e86e8 951 } else {
6dbad63e
FB
952 gen_op_movl_A0_im(disp);
953 }
954 if (havesib && (index != 4 || scale != 0)) {
955 gen_op_addl_A0_reg_sN[scale][index]();
956 }
957 if (must_add_seg) {
958 if (override < 0) {
959 if (base == R_EBP || base == R_ESP)
960 override = R_SS;
961 else
962 override = R_DS;
367e86e8 963 }
6dbad63e 964 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
367e86e8 965 }
367e86e8 966 } else {
4b74fe1f
FB
967 switch (mod) {
968 case 0:
969 if (rm == 6) {
970 disp = lduw(s->pc);
971 s->pc += 2;
972 gen_op_movl_A0_im(disp);
6dbad63e 973 rm = 0; /* avoid SS override */
4b74fe1f
FB
974 goto no_rm;
975 } else {
976 disp = 0;
977 }
978 break;
979 case 1:
980 disp = (int8_t)ldub(s->pc++);
981 break;
982 default:
983 case 2:
984 disp = lduw(s->pc);
985 s->pc += 2;
986 break;
987 }
988 switch(rm) {
989 case 0:
990 gen_op_movl_A0_reg[R_EBX]();
991 gen_op_addl_A0_reg_sN[0][R_ESI]();
992 break;
993 case 1:
994 gen_op_movl_A0_reg[R_EBX]();
995 gen_op_addl_A0_reg_sN[0][R_EDI]();
996 break;
997 case 2:
998 gen_op_movl_A0_reg[R_EBP]();
999 gen_op_addl_A0_reg_sN[0][R_ESI]();
1000 break;
1001 case 3:
1002 gen_op_movl_A0_reg[R_EBP]();
1003 gen_op_addl_A0_reg_sN[0][R_EDI]();
1004 break;
1005 case 4:
1006 gen_op_movl_A0_reg[R_ESI]();
1007 break;
1008 case 5:
1009 gen_op_movl_A0_reg[R_EDI]();
1010 break;
1011 case 6:
1012 gen_op_movl_A0_reg[R_EBP]();
1013 break;
1014 default:
1015 case 7:
1016 gen_op_movl_A0_reg[R_EBX]();
1017 break;
1018 }
1019 if (disp != 0)
1020 gen_op_addl_A0_im(disp);
1021 gen_op_andl_A0_ffff();
6dbad63e
FB
1022 no_rm:
1023 if (must_add_seg) {
1024 if (override < 0) {
1025 if (rm == 2 || rm == 3 || rm == 6)
1026 override = R_SS;
1027 else
1028 override = R_DS;
1029 }
1030 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
1031 }
367e86e8 1032 }
6dbad63e 1033
4b74fe1f
FB
1034 opreg = OR_A0;
1035 disp = 0;
367e86e8
FB
1036 *reg_ptr = opreg;
1037 *offset_ptr = disp;
1038}
1039
1040/* generate modrm memory load or store of 'reg'. TMP0 is used if reg !=
1041 OR_TMP0 */
1042static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
1043{
1044 int mod, rm, opreg, disp;
1045
1046 mod = (modrm >> 6) & 3;
1047 rm = modrm & 7;
1048 if (mod == 3) {
1049 if (is_store) {
1050 if (reg != OR_TMP0)
1051 gen_op_mov_TN_reg[ot][0][reg]();
1052 gen_op_mov_reg_T0[ot][rm]();
1053 } else {
1054 gen_op_mov_TN_reg[ot][0][rm]();
1055 if (reg != OR_TMP0)
1056 gen_op_mov_reg_T0[ot][reg]();
1057 }
1058 } else {
1059 gen_lea_modrm(s, modrm, &opreg, &disp);
1060 if (is_store) {
1061 if (reg != OR_TMP0)
1062 gen_op_mov_TN_reg[ot][0][reg]();
1063 gen_op_st_T0_A0[ot]();
1064 } else {
1065 gen_op_ld_T0_A0[ot]();
1066 if (reg != OR_TMP0)
1067 gen_op_mov_reg_T0[ot][reg]();
1068 }
1069 }
1070}
1071
1072static inline uint32_t insn_get(DisasContext *s, int ot)
1073{
1074 uint32_t ret;
1075
1076 switch(ot) {
1077 case OT_BYTE:
1078 ret = ldub(s->pc);
1079 s->pc++;
1080 break;
1081 case OT_WORD:
1082 ret = lduw(s->pc);
1083 s->pc += 2;
1084 break;
1085 default:
1086 case OT_LONG:
1087 ret = ldl(s->pc);
1088 s->pc += 4;
1089 break;
1090 }
1091 return ret;
1092}
1093
dab2ed99 1094static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
367e86e8
FB
1095{
1096 int inv, jcc_op;
1097 GenOpFunc2 *func;
1098
1099 inv = b & 1;
1100 jcc_op = (b >> 1) & 7;
1101 switch(s->cc_op) {
1102 /* we optimize the cmp/jcc case */
1103 case CC_OP_SUBB:
1104 case CC_OP_SUBW:
1105 case CC_OP_SUBL:
1106 func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
1107 if (!func)
1108 goto slow_jcc;
1109 break;
1110
1111 /* some jumps are easy to compute */
1112 case CC_OP_ADDB:
1113 case CC_OP_ADDW:
1114 case CC_OP_ADDL:
4b74fe1f
FB
1115 case CC_OP_ADCB:
1116 case CC_OP_ADCW:
1117 case CC_OP_ADCL:
1118 case CC_OP_SBBB:
1119 case CC_OP_SBBW:
1120 case CC_OP_SBBL:
367e86e8
FB
1121 case CC_OP_LOGICB:
1122 case CC_OP_LOGICW:
1123 case CC_OP_LOGICL:
1124 case CC_OP_INCB:
1125 case CC_OP_INCW:
1126 case CC_OP_INCL:
1127 case CC_OP_DECB:
1128 case CC_OP_DECW:
1129 case CC_OP_DECL:
1130 case CC_OP_SHLB:
1131 case CC_OP_SHLW:
1132 case CC_OP_SHLL:
4b74fe1f
FB
1133 case CC_OP_SARB:
1134 case CC_OP_SARW:
1135 case CC_OP_SARL:
367e86e8
FB
1136 switch(jcc_op) {
1137 case JCC_Z:
1138 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1139 break;
1140 case JCC_S:
1141 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1142 break;
1143 default:
1144 goto slow_jcc;
1145 }
1146 break;
1147 default:
1148 slow_jcc:
1149 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 1150 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
1151 func = gen_jcc_slow[jcc_op];
1152 break;
1153 }
1154 if (!inv) {
dab2ed99 1155 func(val, next_eip);
367e86e8 1156 } else {
dab2ed99 1157 func(next_eip, val);
367e86e8
FB
1158 }
1159}
1160
1161static void gen_setcc(DisasContext *s, int b)
1162{
1163 int inv, jcc_op;
1164 GenOpFunc *func;
1165
1166 inv = b & 1;
1167 jcc_op = (b >> 1) & 7;
1168 switch(s->cc_op) {
1169 /* we optimize the cmp/jcc case */
1170 case CC_OP_SUBB:
1171 case CC_OP_SUBW:
1172 case CC_OP_SUBL:
1173 func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
1174 if (!func)
1175 goto slow_jcc;
1176 break;
1177
1178 /* some jumps are easy to compute */
1179 case CC_OP_ADDB:
1180 case CC_OP_ADDW:
1181 case CC_OP_ADDL:
1182 case CC_OP_LOGICB:
1183 case CC_OP_LOGICW:
1184 case CC_OP_LOGICL:
1185 case CC_OP_INCB:
1186 case CC_OP_INCW:
1187 case CC_OP_INCL:
1188 case CC_OP_DECB:
1189 case CC_OP_DECW:
1190 case CC_OP_DECL:
1191 case CC_OP_SHLB:
1192 case CC_OP_SHLW:
1193 case CC_OP_SHLL:
1194 switch(jcc_op) {
1195 case JCC_Z:
1017ebe9 1196 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
367e86e8
FB
1197 break;
1198 case JCC_S:
1017ebe9 1199 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
367e86e8
FB
1200 break;
1201 default:
1202 goto slow_jcc;
1203 }
1204 break;
1205 default:
1206 slow_jcc:
1207 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 1208 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
1209 func = gen_setcc_slow[jcc_op];
1210 break;
1211 }
1212 func();
1213 if (inv) {
1214 gen_op_xor_T0_1();
1215 }
1216}
1217
6dbad63e 1218/* move T0 to seg_reg and compute if the CPU state may change */
dab2ed99 1219static void gen_movl_seg_T0(DisasContext *s, int seg_reg)
6dbad63e
FB
1220{
1221 gen_op_movl_seg_T0(seg_reg);
1222 if (!s->addseg && seg_reg < R_FS)
1223 s->is_jmp = 2; /* abort translation because the register may
1224 have a non zero base */
1225}
1226
dab2ed99
FB
1227/* generate a push. It depends on ss32, addseg and dflag */
1228static void gen_push_T0(DisasContext *s)
1229{
1230 if (s->ss32) {
1231 if (!s->addseg) {
1232 if (s->dflag)
1233 gen_op_pushl_T0();
1234 else
1235 gen_op_pushw_T0();
1236 } else {
1237 if (s->dflag)
1238 gen_op_pushl_ss32_T0();
1239 else
1240 gen_op_pushw_ss32_T0();
1241 }
1242 } else {
1243 if (s->dflag)
1244 gen_op_pushl_ss16_T0();
1245 else
1246 gen_op_pushw_ss16_T0();
1247 }
1248}
1249
1250/* two step pop is necessary for precise exceptions */
1251static void gen_pop_T0(DisasContext *s)
1252{
1253 if (s->ss32) {
1254 if (!s->addseg) {
1255 if (s->dflag)
1256 gen_op_popl_T0();
1257 else
1258 gen_op_popw_T0();
1259 } else {
1260 if (s->dflag)
1261 gen_op_popl_ss32_T0();
1262 else
1263 gen_op_popw_ss32_T0();
1264 }
1265 } else {
1266 if (s->dflag)
1267 gen_op_popl_ss16_T0();
1268 else
1269 gen_op_popw_ss16_T0();
1270 }
1271}
1272
1273static void gen_pop_update(DisasContext *s)
1274{
1275 if (s->ss32) {
1276 if (s->dflag)
1277 gen_op_addl_ESP_4();
1278 else
1279 gen_op_addl_ESP_2();
1280 } else {
1281 if (s->dflag)
1282 gen_op_addw_ESP_4();
1283 else
1284 gen_op_addw_ESP_2();
1285 }
1286}
1287
1288/* NOTE: wrap around in 16 bit not fully handled */
1289static void gen_pusha(DisasContext *s)
1290{
1291 int i;
1292 gen_op_movl_A0_ESP();
1293 gen_op_addl_A0_im(-16 << s->dflag);
1294 if (!s->ss32)
1295 gen_op_andl_A0_ffff();
1296 gen_op_movl_T1_A0();
1297 if (s->addseg)
1298 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
1299 for(i = 0;i < 8; i++) {
1300 gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
1301 gen_op_st_T0_A0[OT_WORD + s->dflag]();
1302 gen_op_addl_A0_im(2 << s->dflag);
1303 }
1304 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1305}
1306
1307/* NOTE: wrap around in 16 bit not fully handled */
1308static void gen_popa(DisasContext *s)
1309{
1310 int i;
1311 gen_op_movl_A0_ESP();
1312 if (!s->ss32)
1313 gen_op_andl_A0_ffff();
1314 gen_op_movl_T1_A0();
1315 gen_op_addl_T1_im(16 << s->dflag);
1316 if (s->addseg)
1317 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
1318 for(i = 0;i < 8; i++) {
1319 /* ESP is not reloaded */
1320 if (i != 3) {
1321 gen_op_ld_T0_A0[OT_WORD + s->dflag]();
1322 gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i]();
1323 }
1324 gen_op_addl_A0_im(2 << s->dflag);
1325 }
1326 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1327}
1328
1329/* NOTE: wrap around in 16 bit not fully handled */
1330/* XXX: check this */
1331static void gen_enter(DisasContext *s, int esp_addend, int level)
1332{
1333 int ot, level1, addend, opsize;
1334
1335 ot = s->dflag + OT_WORD;
1336 level &= 0x1f;
1337 level1 = level;
1338 opsize = 2 << s->dflag;
1339
1340 gen_op_movl_A0_ESP();
1341 gen_op_addl_A0_im(-opsize);
1342 if (!s->ss32)
1343 gen_op_andl_A0_ffff();
1344 gen_op_movl_T1_A0();
1345 if (s->addseg)
1346 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
1347 /* push bp */
1348 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
1349 gen_op_st_T0_A0[ot]();
1350 if (level) {
1351 while (level--) {
1352 gen_op_addl_A0_im(-opsize);
1353 gen_op_addl_T0_im(-opsize);
1354 gen_op_st_T0_A0[ot]();
1355 }
1356 gen_op_addl_A0_im(-opsize);
1357 /* XXX: add st_T1_A0 ? */
1358 gen_op_movl_T0_T1();
1359 gen_op_st_T0_A0[ot]();
1360 }
1361 gen_op_mov_reg_T1[ot][R_EBP]();
1362 addend = -esp_addend;
1363 if (level1)
1364 addend -= opsize * (level1 + 1);
1365 gen_op_addl_T1_im(addend);
1366 gen_op_mov_reg_T1[ot][R_ESP]();
1367}
1368
0ecfa993
FB
1369/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
1370 is set to true if the instruction sets the PC (last instruction of
1371 a basic block) */
6dbad63e 1372long disas_insn(DisasContext *s, uint8_t *pc_start)
367e86e8
FB
1373{
1374 int b, prefixes, aflag, dflag;
1375 int shift, ot;
1376 int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
dab2ed99 1377 unsigned int next_eip;
367e86e8
FB
1378
1379 s->pc = pc_start;
1380 prefixes = 0;
6dbad63e
FB
1381 aflag = s->code32;
1382 dflag = s->code32;
9c605cb1 1383 s->override = -1;
367e86e8
FB
1384 next_byte:
1385 b = ldub(s->pc);
367e86e8
FB
1386 s->pc++;
1387 /* check prefixes */
1388 switch (b) {
1389 case 0xf3:
1390 prefixes |= PREFIX_REPZ;
1391 goto next_byte;
1392 case 0xf2:
1393 prefixes |= PREFIX_REPNZ;
1394 goto next_byte;
1395 case 0xf0:
1396 prefixes |= PREFIX_LOCK;
1397 goto next_byte;
1398 case 0x2e:
9c605cb1 1399 s->override = R_CS;
367e86e8
FB
1400 goto next_byte;
1401 case 0x36:
9c605cb1 1402 s->override = R_SS;
367e86e8
FB
1403 goto next_byte;
1404 case 0x3e:
9c605cb1 1405 s->override = R_DS;
367e86e8
FB
1406 goto next_byte;
1407 case 0x26:
9c605cb1 1408 s->override = R_ES;
367e86e8
FB
1409 goto next_byte;
1410 case 0x64:
9c605cb1 1411 s->override = R_FS;
367e86e8
FB
1412 goto next_byte;
1413 case 0x65:
9c605cb1 1414 s->override = R_GS;
367e86e8
FB
1415 goto next_byte;
1416 case 0x66:
1417 prefixes |= PREFIX_DATA;
1418 goto next_byte;
1419 case 0x67:
1420 prefixes |= PREFIX_ADR;
1421 goto next_byte;
1422 case 0x9b:
1423 prefixes |= PREFIX_FWAIT;
1424 goto next_byte;
1425 }
1426
1427 if (prefixes & PREFIX_DATA)
1428 dflag ^= 1;
1429 if (prefixes & PREFIX_ADR)
1430 aflag ^= 1;
1431
1432 s->prefix = prefixes;
1433 s->aflag = aflag;
1434 s->dflag = dflag;
1435
1b6b029e
FB
1436 /* lock generation */
1437 if (prefixes & PREFIX_LOCK)
1438 gen_op_lock();
1439
367e86e8
FB
1440 /* now check op code */
1441 reswitch:
1442 switch(b) {
1443 case 0x0f:
1444 /**************************/
1445 /* extended op code */
1446 b = ldub(s->pc++) | 0x100;
1447 goto reswitch;
1448
1449 /**************************/
1450 /* arith & logic */
1451 case 0x00 ... 0x05:
1452 case 0x08 ... 0x0d:
1453 case 0x10 ... 0x15:
1454 case 0x18 ... 0x1d:
1455 case 0x20 ... 0x25:
1456 case 0x28 ... 0x2d:
1457 case 0x30 ... 0x35:
1458 case 0x38 ... 0x3d:
1459 {
1460 int op, f, val;
1461 op = (b >> 3) & 7;
1462 f = (b >> 1) & 3;
1463
1464 if ((b & 1) == 0)
1465 ot = OT_BYTE;
1466 else
1467 ot = dflag ? OT_LONG : OT_WORD;
1468
1469 switch(f) {
1470 case 0: /* OP Ev, Gv */
1471 modrm = ldub(s->pc++);
1472 reg = ((modrm >> 3) & 7) + OR_EAX;
1473 mod = (modrm >> 6) & 3;
1474 rm = modrm & 7;
1475 if (mod != 3) {
1476 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1477 gen_op_ld_T0_A0[ot]();
1478 opreg = OR_TMP0;
1479 } else {
1480 opreg = OR_EAX + rm;
1481 }
1482 gen_op(s, op, ot, opreg, reg);
1483 if (mod != 3 && op != 7) {
1484 gen_op_st_T0_A0[ot]();
1485 }
1486 break;
1487 case 1: /* OP Gv, Ev */
1488 modrm = ldub(s->pc++);
1489 mod = (modrm >> 6) & 3;
1490 reg = ((modrm >> 3) & 7) + OR_EAX;
1491 rm = modrm & 7;
1492 if (mod != 3) {
1493 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1494 gen_op_ld_T1_A0[ot]();
1495 opreg = OR_TMP1;
1496 } else {
1497 opreg = OR_EAX + rm;
1498 }
1499 gen_op(s, op, ot, reg, opreg);
1500 break;
1501 case 2: /* OP A, Iv */
1502 val = insn_get(s, ot);
1503 gen_opi(s, op, ot, OR_EAX, val);
1504 break;
1505 }
1506 }
1507 break;
1508
1509 case 0x80: /* GRP1 */
1510 case 0x81:
1511 case 0x83:
1512 {
1513 int val;
1514
1515 if ((b & 1) == 0)
1516 ot = OT_BYTE;
1517 else
1518 ot = dflag ? OT_LONG : OT_WORD;
1519
1520 modrm = ldub(s->pc++);
1521 mod = (modrm >> 6) & 3;
1522 rm = modrm & 7;
1523 op = (modrm >> 3) & 7;
1524
1525 if (mod != 3) {
1526 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1527 gen_op_ld_T0_A0[ot]();
1528 opreg = OR_TMP0;
1529 } else {
1530 opreg = rm + OR_EAX;
1531 }
1532
1533 switch(b) {
1534 default:
1535 case 0x80:
1536 case 0x81:
1537 val = insn_get(s, ot);
1538 break;
1539 case 0x83:
1540 val = (int8_t)insn_get(s, OT_BYTE);
1541 break;
1542 }
1543
1544 gen_opi(s, op, ot, opreg, val);
1545 if (op != 7 && mod != 3) {
1546 gen_op_st_T0_A0[ot]();
1547 }
1548 }
1549 break;
1550
1551 /**************************/
1552 /* inc, dec, and other misc arith */
1553 case 0x40 ... 0x47: /* inc Gv */
1554 ot = dflag ? OT_LONG : OT_WORD;
1555 gen_inc(s, ot, OR_EAX + (b & 7), 1);
1556 break;
1557 case 0x48 ... 0x4f: /* dec Gv */
1558 ot = dflag ? OT_LONG : OT_WORD;
1559 gen_inc(s, ot, OR_EAX + (b & 7), -1);
1560 break;
1561 case 0xf6: /* GRP3 */
1562 case 0xf7:
1563 if ((b & 1) == 0)
1564 ot = OT_BYTE;
1565 else
1566 ot = dflag ? OT_LONG : OT_WORD;
1567
1568 modrm = ldub(s->pc++);
1569 mod = (modrm >> 6) & 3;
1570 rm = modrm & 7;
1571 op = (modrm >> 3) & 7;
1572 if (mod != 3) {
1573 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1574 gen_op_ld_T0_A0[ot]();
1575 } else {
1576 gen_op_mov_TN_reg[ot][0][rm]();
1577 }
1578
1579 switch(op) {
1580 case 0: /* test */
1581 val = insn_get(s, ot);
ba1c6e37 1582 gen_op_movl_T1_im(val);
367e86e8
FB
1583 gen_op_testl_T0_T1_cc();
1584 s->cc_op = CC_OP_LOGICB + ot;
1585 break;
1586 case 2: /* not */
1587 gen_op_notl_T0();
1588 if (mod != 3) {
1589 gen_op_st_T0_A0[ot]();
1590 } else {
1591 gen_op_mov_reg_T0[ot][rm]();
1592 }
1593 break;
1594 case 3: /* neg */
1595 gen_op_negl_T0_cc();
1596 if (mod != 3) {
1597 gen_op_st_T0_A0[ot]();
1598 } else {
1599 gen_op_mov_reg_T0[ot][rm]();
1600 }
1601 s->cc_op = CC_OP_SUBB + ot;
1602 break;
1603 case 4: /* mul */
1604 switch(ot) {
1605 case OT_BYTE:
1606 gen_op_mulb_AL_T0();
1607 break;
1608 case OT_WORD:
1609 gen_op_mulw_AX_T0();
1610 break;
1611 default:
1612 case OT_LONG:
1613 gen_op_mull_EAX_T0();
1614 break;
1615 }
0ecfa993 1616 s->cc_op = CC_OP_MUL;
367e86e8
FB
1617 break;
1618 case 5: /* imul */
1619 switch(ot) {
1620 case OT_BYTE:
1621 gen_op_imulb_AL_T0();
1622 break;
1623 case OT_WORD:
1624 gen_op_imulw_AX_T0();
1625 break;
1626 default:
1627 case OT_LONG:
1628 gen_op_imull_EAX_T0();
1629 break;
1630 }
0ecfa993 1631 s->cc_op = CC_OP_MUL;
367e86e8
FB
1632 break;
1633 case 6: /* div */
1634 switch(ot) {
1635 case OT_BYTE:
1636 gen_op_divb_AL_T0();
1637 break;
1638 case OT_WORD:
1639 gen_op_divw_AX_T0();
1640 break;
1641 default:
1642 case OT_LONG:
1643 gen_op_divl_EAX_T0();
1644 break;
1645 }
1646 break;
1647 case 7: /* idiv */
1648 switch(ot) {
1649 case OT_BYTE:
1650 gen_op_idivb_AL_T0();
1651 break;
1652 case OT_WORD:
1653 gen_op_idivw_AX_T0();
1654 break;
1655 default:
1656 case OT_LONG:
1657 gen_op_idivl_EAX_T0();
1658 break;
1659 }
1660 break;
1661 default:
1a9353d2 1662 goto illegal_op;
367e86e8
FB
1663 }
1664 break;
1665
1666 case 0xfe: /* GRP4 */
1667 case 0xff: /* GRP5 */
1668 if ((b & 1) == 0)
1669 ot = OT_BYTE;
1670 else
1671 ot = dflag ? OT_LONG : OT_WORD;
1672
1673 modrm = ldub(s->pc++);
1674 mod = (modrm >> 6) & 3;
1675 rm = modrm & 7;
1676 op = (modrm >> 3) & 7;
1677 if (op >= 2 && b == 0xfe) {
1a9353d2 1678 goto illegal_op;
367e86e8
FB
1679 }
1680 if (mod != 3) {
1681 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
dab2ed99
FB
1682 if (op != 3 && op != 5)
1683 gen_op_ld_T0_A0[ot]();
367e86e8
FB
1684 } else {
1685 gen_op_mov_TN_reg[ot][0][rm]();
1686 }
1687
1688 switch(op) {
1689 case 0: /* inc Ev */
1690 gen_inc(s, ot, OR_TMP0, 1);
1691 if (mod != 3)
1692 gen_op_st_T0_A0[ot]();
4b74fe1f
FB
1693 else
1694 gen_op_mov_reg_T0[ot][rm]();
367e86e8
FB
1695 break;
1696 case 1: /* dec Ev */
1697 gen_inc(s, ot, OR_TMP0, -1);
1698 if (mod != 3)
1699 gen_op_st_T0_A0[ot]();
4b74fe1f
FB
1700 else
1701 gen_op_mov_reg_T0[ot][rm]();
367e86e8
FB
1702 break;
1703 case 2: /* call Ev */
dab2ed99
FB
1704 /* XXX: optimize if memory (no and is necessary) */
1705 if (s->dflag == 0)
1706 gen_op_andl_T0_ffff();
1707 gen_op_jmp_T0();
1708 next_eip = s->pc - s->cs_base;
1709 gen_op_movl_T0_im(next_eip);
1710 gen_push_T0(s);
1711 s->is_jmp = 1;
1712 break;
1713 case 3: /* lcall Ev */
1714 /* push return segment + offset */
1715 gen_op_movl_T0_seg(R_CS);
1716 gen_push_T0(s);
1717 next_eip = s->pc - s->cs_base;
1718 gen_op_movl_T0_im(next_eip);
1719 gen_push_T0(s);
1720
1721 gen_op_ld_T1_A0[ot]();
1722 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1723 gen_op_lduw_T0_A0();
1724 gen_movl_seg_T0(s, R_CS);
1725 gen_op_movl_T0_T1();
367e86e8 1726 gen_op_jmp_T0();
6dbad63e 1727 s->is_jmp = 1;
367e86e8
FB
1728 break;
1729 case 4: /* jmp Ev */
dab2ed99
FB
1730 if (s->dflag == 0)
1731 gen_op_andl_T0_ffff();
1732 gen_op_jmp_T0();
1733 s->is_jmp = 1;
1734 break;
1735 case 5: /* ljmp Ev */
1736 gen_op_ld_T1_A0[ot]();
1737 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
1738 gen_op_lduw_T0_A0();
1739 gen_movl_seg_T0(s, R_CS);
1740 gen_op_movl_T0_T1();
367e86e8 1741 gen_op_jmp_T0();
6dbad63e 1742 s->is_jmp = 1;
367e86e8
FB
1743 break;
1744 case 6: /* push Ev */
dab2ed99 1745 gen_push_T0(s);
367e86e8
FB
1746 break;
1747 default:
1a9353d2 1748 goto illegal_op;
367e86e8
FB
1749 }
1750 break;
1751
1752 case 0x84: /* test Ev, Gv */
1753 case 0x85:
1754 if ((b & 1) == 0)
1755 ot = OT_BYTE;
1756 else
1757 ot = dflag ? OT_LONG : OT_WORD;
1758
1759 modrm = ldub(s->pc++);
1760 mod = (modrm >> 6) & 3;
1761 rm = modrm & 7;
1762 reg = (modrm >> 3) & 7;
1763
1764 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1765 gen_op_mov_TN_reg[ot][1][reg + OR_EAX]();
1766 gen_op_testl_T0_T1_cc();
1767 s->cc_op = CC_OP_LOGICB + ot;
1768 break;
1769
1770 case 0xa8: /* test eAX, Iv */
1771 case 0xa9:
1772 if ((b & 1) == 0)
1773 ot = OT_BYTE;
1774 else
1775 ot = dflag ? OT_LONG : OT_WORD;
1776 val = insn_get(s, ot);
1777
1778 gen_op_mov_TN_reg[ot][0][OR_EAX]();
ba1c6e37 1779 gen_op_movl_T1_im(val);
367e86e8
FB
1780 gen_op_testl_T0_T1_cc();
1781 s->cc_op = CC_OP_LOGICB + ot;
1782 break;
1783
1784 case 0x98: /* CWDE/CBW */
1785 if (dflag)
1786 gen_op_movswl_EAX_AX();
1787 else
1788 gen_op_movsbw_AX_AL();
1789 break;
1790 case 0x99: /* CDQ/CWD */
1791 if (dflag)
1792 gen_op_movslq_EDX_EAX();
1793 else
1794 gen_op_movswl_DX_AX();
1795 break;
1796 case 0x1af: /* imul Gv, Ev */
1797 case 0x69: /* imul Gv, Ev, I */
1798 case 0x6b:
1799 ot = dflag ? OT_LONG : OT_WORD;
1800 modrm = ldub(s->pc++);
1801 reg = ((modrm >> 3) & 7) + OR_EAX;
367e86e8
FB
1802 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1803 if (b == 0x69) {
1804 val = insn_get(s, ot);
ba1c6e37 1805 gen_op_movl_T1_im(val);
367e86e8
FB
1806 } else if (b == 0x6b) {
1807 val = insn_get(s, OT_BYTE);
ba1c6e37 1808 gen_op_movl_T1_im(val);
367e86e8
FB
1809 } else {
1810 gen_op_mov_TN_reg[ot][1][reg]();
1811 }
1812
1813 if (ot == OT_LONG) {
4b74fe1f 1814 gen_op_imull_T0_T1();
367e86e8 1815 } else {
4b74fe1f 1816 gen_op_imulw_T0_T1();
367e86e8
FB
1817 }
1818 gen_op_mov_reg_T0[ot][reg]();
0ecfa993 1819 s->cc_op = CC_OP_MUL;
367e86e8 1820 break;
1a9353d2
FB
1821 case 0x1c0:
1822 case 0x1c1: /* xadd Ev, Gv */
1823 if ((b & 1) == 0)
1824 ot = OT_BYTE;
1825 else
1826 ot = dflag ? OT_LONG : OT_WORD;
1827 modrm = ldub(s->pc++);
1828 reg = (modrm >> 3) & 7;
1829 mod = (modrm >> 6) & 3;
1830 if (mod == 3) {
1831 rm = modrm & 7;
1832 gen_op_mov_TN_reg[ot][0][reg]();
1833 gen_op_mov_TN_reg[ot][1][rm]();
1834 gen_op_addl_T0_T1_cc();
1835 gen_op_mov_reg_T0[ot][rm]();
1836 gen_op_mov_reg_T1[ot][reg]();
1837 } else {
1838 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1839 gen_op_mov_TN_reg[ot][0][reg]();
1840 gen_op_ld_T1_A0[ot]();
1841 gen_op_addl_T0_T1_cc();
1842 gen_op_st_T0_A0[ot]();
1843 gen_op_mov_reg_T1[ot][reg]();
1844 }
1845 s->cc_op = CC_OP_ADDB + ot;
1846 break;
1847 case 0x1b0:
1848 case 0x1b1: /* cmpxchg Ev, Gv */
1849 if ((b & 1) == 0)
1850 ot = OT_BYTE;
1851 else
1852 ot = dflag ? OT_LONG : OT_WORD;
1853 modrm = ldub(s->pc++);
1854 reg = (modrm >> 3) & 7;
1855 mod = (modrm >> 6) & 3;
1856 gen_op_mov_TN_reg[ot][1][reg]();
1857 if (mod == 3) {
1858 rm = modrm & 7;
1859 gen_op_mov_TN_reg[ot][0][rm]();
1860 gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
1861 gen_op_mov_reg_T0[ot][rm]();
1862 } else {
1863 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1864 gen_op_ld_T0_A0[ot]();
1865 gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
1866 gen_op_st_T0_A0[ot]();
1867 }
1868 s->cc_op = CC_OP_SUBB + ot;
1869 break;
9c605cb1
FB
1870 case 0x1c7: /* cmpxchg8b */
1871 modrm = ldub(s->pc++);
1872 mod = (modrm >> 6) & 3;
1873 if (mod == 3)
1874 goto illegal_op;
1875 if (s->cc_op != CC_OP_DYNAMIC)
1876 gen_op_set_cc_op(s->cc_op);
1877 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1878 gen_op_cmpxchg8b();
1879 s->cc_op = CC_OP_EFLAGS;
1880 break;
367e86e8
FB
1881
1882 /**************************/
1883 /* push/pop */
1884 case 0x50 ... 0x57: /* push */
927f621e 1885 gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
dab2ed99 1886 gen_push_T0(s);
367e86e8
FB
1887 break;
1888 case 0x58 ... 0x5f: /* pop */
dab2ed99
FB
1889 ot = dflag ? OT_LONG : OT_WORD;
1890 gen_pop_T0(s);
1891 gen_op_mov_reg_T0[ot][b & 7]();
1892 gen_pop_update(s);
367e86e8 1893 break;
27362c82 1894 case 0x60: /* pusha */
dab2ed99 1895 gen_pusha(s);
27362c82
FB
1896 break;
1897 case 0x61: /* popa */
dab2ed99 1898 gen_popa(s);
27362c82 1899 break;
367e86e8
FB
1900 case 0x68: /* push Iv */
1901 case 0x6a:
1902 ot = dflag ? OT_LONG : OT_WORD;
1903 if (b == 0x68)
1904 val = insn_get(s, ot);
1905 else
1906 val = (int8_t)insn_get(s, OT_BYTE);
ba1c6e37 1907 gen_op_movl_T0_im(val);
dab2ed99 1908 gen_push_T0(s);
367e86e8
FB
1909 break;
1910 case 0x8f: /* pop Ev */
1911 ot = dflag ? OT_LONG : OT_WORD;
1912 modrm = ldub(s->pc++);
dab2ed99 1913 gen_pop_T0(s);
367e86e8 1914 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
dab2ed99 1915 gen_pop_update(s);
367e86e8 1916 break;
27362c82
FB
1917 case 0xc8: /* enter */
1918 {
1919 int level;
1920 val = lduw(s->pc);
1921 s->pc += 2;
1922 level = ldub(s->pc++);
dab2ed99 1923 gen_enter(s, val, level);
27362c82
FB
1924 }
1925 break;
367e86e8 1926 case 0xc9: /* leave */
dab2ed99
FB
1927 /* XXX: exception not precise (ESP is update before potential exception) */
1928 if (s->ss32) {
1929 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
1930 gen_op_mov_reg_T0[OT_LONG][R_ESP]();
1931 } else {
1932 gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();
1933 gen_op_mov_reg_T0[OT_WORD][R_ESP]();
1934 }
1935 gen_pop_T0(s);
1936 ot = dflag ? OT_LONG : OT_WORD;
1937 gen_op_mov_reg_T0[ot][R_EBP]();
1938 gen_pop_update(s);
367e86e8 1939 break;
6dbad63e
FB
1940 case 0x06: /* push es */
1941 case 0x0e: /* push cs */
1942 case 0x16: /* push ss */
1943 case 0x1e: /* push ds */
1944 gen_op_movl_T0_seg(b >> 3);
dab2ed99 1945 gen_push_T0(s);
6dbad63e
FB
1946 break;
1947 case 0x1a0: /* push fs */
1948 case 0x1a8: /* push gs */
f631ef9b 1949 gen_op_movl_T0_seg((b >> 3) & 7);
dab2ed99 1950 gen_push_T0(s);
6dbad63e
FB
1951 break;
1952 case 0x07: /* pop es */
1953 case 0x17: /* pop ss */
1954 case 0x1f: /* pop ds */
dab2ed99 1955 gen_pop_T0(s);
6dbad63e 1956 gen_movl_seg_T0(s, b >> 3);
dab2ed99 1957 gen_pop_update(s);
6dbad63e
FB
1958 break;
1959 case 0x1a1: /* pop fs */
1960 case 0x1a9: /* pop gs */
dab2ed99 1961 gen_pop_T0(s);
f631ef9b 1962 gen_movl_seg_T0(s, (b >> 3) & 7);
dab2ed99 1963 gen_pop_update(s);
6dbad63e
FB
1964 break;
1965
367e86e8
FB
1966 /**************************/
1967 /* mov */
1968 case 0x88:
1969 case 0x89: /* mov Gv, Ev */
1970 if ((b & 1) == 0)
1971 ot = OT_BYTE;
1972 else
1973 ot = dflag ? OT_LONG : OT_WORD;
1974 modrm = ldub(s->pc++);
1975 reg = (modrm >> 3) & 7;
1976
1977 /* generate a generic store */
1978 gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1);
1979 break;
1980 case 0xc6:
1981 case 0xc7: /* mov Ev, Iv */
1982 if ((b & 1) == 0)
1983 ot = OT_BYTE;
1984 else
1985 ot = dflag ? OT_LONG : OT_WORD;
1986 modrm = ldub(s->pc++);
1987 mod = (modrm >> 6) & 3;
0ecfa993
FB
1988 if (mod != 3)
1989 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
367e86e8 1990 val = insn_get(s, ot);
ba1c6e37 1991 gen_op_movl_T0_im(val);
0ecfa993
FB
1992 if (mod != 3)
1993 gen_op_st_T0_A0[ot]();
1994 else
1995 gen_op_mov_reg_T0[ot][modrm & 7]();
367e86e8
FB
1996 break;
1997 case 0x8a:
1998 case 0x8b: /* mov Ev, Gv */
1999 if ((b & 1) == 0)
2000 ot = OT_BYTE;
2001 else
2002 ot = dflag ? OT_LONG : OT_WORD;
2003 modrm = ldub(s->pc++);
2004 reg = (modrm >> 3) & 7;
2005
2006 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2007 gen_op_mov_reg_T0[ot][reg]();
2008 break;
6dbad63e
FB
2009 case 0x8e: /* mov seg, Gv */
2010 ot = dflag ? OT_LONG : OT_WORD;
2011 modrm = ldub(s->pc++);
2012 reg = (modrm >> 3) & 7;
2013 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
dab2ed99 2014 if (reg >= 6 || reg == R_CS)
6dbad63e
FB
2015 goto illegal_op;
2016 gen_movl_seg_T0(s, reg);
2017 break;
2018 case 0x8c: /* mov Gv, seg */
2019 ot = dflag ? OT_LONG : OT_WORD;
2020 modrm = ldub(s->pc++);
2021 reg = (modrm >> 3) & 7;
2022 if (reg >= 6)
2023 goto illegal_op;
2024 gen_op_movl_T0_seg(reg);
2025 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
2026 break;
367e86e8
FB
2027
2028 case 0x1b6: /* movzbS Gv, Eb */
2029 case 0x1b7: /* movzwS Gv, Eb */
2030 case 0x1be: /* movsbS Gv, Eb */
2031 case 0x1bf: /* movswS Gv, Eb */
2032 {
2033 int d_ot;
2034 /* d_ot is the size of destination */
2035 d_ot = dflag + OT_WORD;
2036 /* ot is the size of source */
2037 ot = (b & 1) + OT_BYTE;
2038 modrm = ldub(s->pc++);
2039 reg = ((modrm >> 3) & 7) + OR_EAX;
2040 mod = (modrm >> 6) & 3;
2041 rm = modrm & 7;
2042
2043 if (mod == 3) {
2044 gen_op_mov_TN_reg[ot][0][rm]();
2045 switch(ot | (b & 8)) {
2046 case OT_BYTE:
2047 gen_op_movzbl_T0_T0();
2048 break;
2049 case OT_BYTE | 8:
2050 gen_op_movsbl_T0_T0();
2051 break;
2052 case OT_WORD:
2053 gen_op_movzwl_T0_T0();
2054 break;
2055 default:
2056 case OT_WORD | 8:
2057 gen_op_movswl_T0_T0();
2058 break;
2059 }
2060 gen_op_mov_reg_T0[d_ot][reg]();
2061 } else {
2062 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2063 if (b & 8) {
2064 gen_op_lds_T0_A0[ot]();
2065 } else {
2066 gen_op_ldu_T0_A0[ot]();
2067 }
2068 gen_op_mov_reg_T0[d_ot][reg]();
2069 }
2070 }
2071 break;
2072
2073 case 0x8d: /* lea */
2074 ot = dflag ? OT_LONG : OT_WORD;
2075 modrm = ldub(s->pc++);
2076 reg = (modrm >> 3) & 7;
6dbad63e 2077 /* we must ensure that no segment is added */
9c605cb1 2078 s->override = -1;
6dbad63e
FB
2079 val = s->addseg;
2080 s->addseg = 0;
367e86e8 2081 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
6dbad63e 2082 s->addseg = val;
367e86e8
FB
2083 gen_op_mov_reg_A0[ot - OT_WORD][reg]();
2084 break;
2085
2086 case 0xa0: /* mov EAX, Ov */
2087 case 0xa1:
2088 case 0xa2: /* mov Ov, EAX */
2089 case 0xa3:
2090 if ((b & 1) == 0)
2091 ot = OT_BYTE;
2092 else
2093 ot = dflag ? OT_LONG : OT_WORD;
2094 if (s->aflag)
2095 offset_addr = insn_get(s, OT_LONG);
2096 else
2097 offset_addr = insn_get(s, OT_WORD);
4b74fe1f 2098 gen_op_movl_A0_im(offset_addr);
1a9353d2 2099 /* handle override */
1a9353d2
FB
2100 {
2101 int override, must_add_seg;
1a9353d2 2102 must_add_seg = s->addseg;
9c605cb1
FB
2103 if (s->override >= 0) {
2104 override = s->override;
1a9353d2 2105 must_add_seg = 1;
9c605cb1
FB
2106 } else {
2107 override = R_DS;
1a9353d2
FB
2108 }
2109 if (must_add_seg) {
2110 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
2111 }
2112 }
367e86e8
FB
2113 if ((b & 2) == 0) {
2114 gen_op_ld_T0_A0[ot]();
2115 gen_op_mov_reg_T0[ot][R_EAX]();
2116 } else {
2117 gen_op_mov_TN_reg[ot][0][R_EAX]();
2118 gen_op_st_T0_A0[ot]();
2119 }
2120 break;
31bb950b 2121 case 0xd7: /* xlat */
31bb950b
FB
2122 gen_op_movl_A0_reg[R_EBX]();
2123 gen_op_addl_A0_AL();
2124 if (s->aflag == 0)
2125 gen_op_andl_A0_ffff();
9c605cb1 2126 /* handle override */
31bb950b
FB
2127 {
2128 int override, must_add_seg;
31bb950b 2129 must_add_seg = s->addseg;
9c605cb1
FB
2130 override = R_DS;
2131 if (s->override >= 0) {
2132 override = s->override;
31bb950b 2133 must_add_seg = 1;
9c605cb1
FB
2134 } else {
2135 override = R_DS;
31bb950b
FB
2136 }
2137 if (must_add_seg) {
2138 gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[override].base));
2139 }
2140 }
2141 gen_op_ldub_T0_A0();
2142 gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
2143 break;
367e86e8
FB
2144 case 0xb0 ... 0xb7: /* mov R, Ib */
2145 val = insn_get(s, OT_BYTE);
ba1c6e37 2146 gen_op_movl_T0_im(val);
367e86e8
FB
2147 gen_op_mov_reg_T0[OT_BYTE][b & 7]();
2148 break;
2149 case 0xb8 ... 0xbf: /* mov R, Iv */
2150 ot = dflag ? OT_LONG : OT_WORD;
2151 val = insn_get(s, ot);
2152 reg = OR_EAX + (b & 7);
ba1c6e37 2153 gen_op_movl_T0_im(val);
367e86e8
FB
2154 gen_op_mov_reg_T0[ot][reg]();
2155 break;
2156
2157 case 0x91 ... 0x97: /* xchg R, EAX */
2158 ot = dflag ? OT_LONG : OT_WORD;
2159 reg = b & 7;
1a9353d2
FB
2160 rm = R_EAX;
2161 goto do_xchg_reg;
367e86e8
FB
2162 case 0x86:
2163 case 0x87: /* xchg Ev, Gv */
2164 if ((b & 1) == 0)
2165 ot = OT_BYTE;
2166 else
2167 ot = dflag ? OT_LONG : OT_WORD;
2168 modrm = ldub(s->pc++);
2169 reg = (modrm >> 3) & 7;
1a9353d2
FB
2170 mod = (modrm >> 6) & 3;
2171 if (mod == 3) {
2172 rm = modrm & 7;
2173 do_xchg_reg:
2174 gen_op_mov_TN_reg[ot][0][reg]();
2175 gen_op_mov_TN_reg[ot][1][rm]();
2176 gen_op_mov_reg_T0[ot][rm]();
2177 gen_op_mov_reg_T1[ot][reg]();
2178 } else {
2179 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2180 gen_op_mov_TN_reg[ot][0][reg]();
31bb950b
FB
2181 /* for xchg, lock is implicit */
2182 if (!(prefixes & PREFIX_LOCK))
2183 gen_op_lock();
1a9353d2
FB
2184 gen_op_ld_T1_A0[ot]();
2185 gen_op_st_T0_A0[ot]();
31bb950b
FB
2186 if (!(prefixes & PREFIX_LOCK))
2187 gen_op_unlock();
1a9353d2
FB
2188 gen_op_mov_reg_T1[ot][reg]();
2189 }
367e86e8 2190 break;
6dbad63e
FB
2191 case 0xc4: /* les Gv */
2192 op = R_ES;
2193 goto do_lxx;
2194 case 0xc5: /* lds Gv */
2195 op = R_DS;
2196 goto do_lxx;
2197 case 0x1b2: /* lss Gv */
2198 op = R_SS;
2199 goto do_lxx;
2200 case 0x1b4: /* lfs Gv */
2201 op = R_FS;
2202 goto do_lxx;
2203 case 0x1b5: /* lgs Gv */
2204 op = R_GS;
2205 do_lxx:
2206 ot = dflag ? OT_LONG : OT_WORD;
2207 modrm = ldub(s->pc++);
2208 reg = (modrm >> 3) & 7;
2209 mod = (modrm >> 6) & 3;
2210 if (mod == 3)
2211 goto illegal_op;
9c605cb1 2212 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
6dbad63e 2213 gen_op_ld_T1_A0[ot]();
dc99065b 2214 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
6dbad63e
FB
2215 /* load the segment first to handle exceptions properly */
2216 gen_op_lduw_T0_A0();
2217 gen_movl_seg_T0(s, op);
2218 /* then put the data */
2219 gen_op_mov_reg_T1[ot][reg]();
2220 break;
367e86e8
FB
2221
2222 /************************/
2223 /* shifts */
2224 case 0xc0:
2225 case 0xc1:
2226 /* shift Ev,Ib */
2227 shift = 2;
2228 grp2:
2229 {
2230 if ((b & 1) == 0)
2231 ot = OT_BYTE;
2232 else
2233 ot = dflag ? OT_LONG : OT_WORD;
2234
2235 modrm = ldub(s->pc++);
2236 mod = (modrm >> 6) & 3;
2237 rm = modrm & 7;
2238 op = (modrm >> 3) & 7;
2239
2240 if (mod != 3) {
2241 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2242 gen_op_ld_T0_A0[ot]();
2243 opreg = OR_TMP0;
2244 } else {
2245 opreg = rm + OR_EAX;
2246 }
2247
2248 /* simpler op */
2249 if (shift == 0) {
2250 gen_shift(s, op, ot, opreg, OR_ECX);
2251 } else {
2252 if (shift == 2) {
2253 shift = ldub(s->pc++);
2254 }
2255 gen_shifti(s, op, ot, opreg, shift);
2256 }
2257
2258 if (mod != 3) {
2259 gen_op_st_T0_A0[ot]();
2260 }
2261 }
2262 break;
2263 case 0xd0:
2264 case 0xd1:
2265 /* shift Ev,1 */
2266 shift = 1;
2267 goto grp2;
2268 case 0xd2:
2269 case 0xd3:
2270 /* shift Ev,cl */
2271 shift = 0;
2272 goto grp2;
2273
d57c4e01
FB
2274 case 0x1a4: /* shld imm */
2275 op = 0;
2276 shift = 1;
2277 goto do_shiftd;
2278 case 0x1a5: /* shld cl */
2279 op = 0;
2280 shift = 0;
2281 goto do_shiftd;
2282 case 0x1ac: /* shrd imm */
2283 op = 1;
2284 shift = 1;
2285 goto do_shiftd;
2286 case 0x1ad: /* shrd cl */
2287 op = 1;
2288 shift = 0;
2289 do_shiftd:
2290 ot = dflag ? OT_LONG : OT_WORD;
2291 modrm = ldub(s->pc++);
2292 mod = (modrm >> 6) & 3;
2293 rm = modrm & 7;
2294 reg = (modrm >> 3) & 7;
2295
2296 if (mod != 3) {
2297 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2298 gen_op_ld_T0_A0[ot]();
2299 } else {
2300 gen_op_mov_TN_reg[ot][0][rm]();
2301 }
2302 gen_op_mov_TN_reg[ot][1][reg]();
2303
2304 if (shift) {
2305 val = ldub(s->pc++);
2306 val &= 0x1f;
2307 if (val) {
2308 gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
2309 if (op == 0 && ot != OT_WORD)
2310 s->cc_op = CC_OP_SHLB + ot;
2311 else
2312 s->cc_op = CC_OP_SARB + ot;
2313 }
2314 } else {
2315 if (s->cc_op != CC_OP_DYNAMIC)
2316 gen_op_set_cc_op(s->cc_op);
2317 gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
2318 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
2319 }
2320 if (mod != 3) {
2321 gen_op_st_T0_A0[ot]();
2322 } else {
2323 gen_op_mov_reg_T0[ot][rm]();
2324 }
2325 break;
2326
367e86e8
FB
2327 /************************/
2328 /* floats */
367e86e8
FB
2329 case 0xd8 ... 0xdf:
2330 modrm = ldub(s->pc++);
2331 mod = (modrm >> 6) & 3;
2332 rm = modrm & 7;
2333 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
2334
2335 if (mod != 3) {
2336 /* memory op */
2337 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2338 switch(op) {
2339 case 0x00 ... 0x07: /* fxxxs */
2340 case 0x10 ... 0x17: /* fixxxl */
2341 case 0x20 ... 0x27: /* fxxxl */
2342 case 0x30 ... 0x37: /* fixxx */
2343 {
927f621e
FB
2344 int op1;
2345 op1 = op & 7;
367e86e8
FB
2346
2347 switch(op >> 4) {
2348 case 0:
927f621e 2349 gen_op_flds_FT0_A0();
367e86e8
FB
2350 break;
2351 case 1:
927f621e 2352 gen_op_fildl_FT0_A0();
367e86e8
FB
2353 break;
2354 case 2:
927f621e 2355 gen_op_fldl_FT0_A0();
367e86e8
FB
2356 break;
2357 case 3:
2358 default:
927f621e 2359 gen_op_fild_FT0_A0();
367e86e8
FB
2360 break;
2361 }
2362
927f621e
FB
2363 gen_op_fp_arith_ST0_FT0[op1]();
2364 if (op1 == 3) {
367e86e8 2365 /* fcomp needs pop */
927f621e 2366 gen_op_fpop();
367e86e8
FB
2367 }
2368 }
2369 break;
2370 case 0x08: /* flds */
2371 case 0x0a: /* fsts */
2372 case 0x0b: /* fstps */
2373 case 0x18: /* fildl */
2374 case 0x1a: /* fistl */
2375 case 0x1b: /* fistpl */
2376 case 0x28: /* fldl */
2377 case 0x2a: /* fstl */
2378 case 0x2b: /* fstpl */
2379 case 0x38: /* filds */
2380 case 0x3a: /* fists */
2381 case 0x3b: /* fistps */
2382
367e86e8
FB
2383 switch(op & 7) {
2384 case 0:
927f621e
FB
2385 gen_op_fpush();
2386 switch(op >> 4) {
2387 case 0:
2388 gen_op_flds_ST0_A0();
2389 break;
2390 case 1:
2391 gen_op_fildl_ST0_A0();
2392 break;
2393 case 2:
2394 gen_op_fldl_ST0_A0();
2395 break;
2396 case 3:
2397 default:
2398 gen_op_fild_ST0_A0();
2399 break;
367e86e8
FB
2400 }
2401 break;
2402 default:
927f621e
FB
2403 switch(op >> 4) {
2404 case 0:
2405 gen_op_fsts_ST0_A0();
2406 break;
2407 case 1:
2408 gen_op_fistl_ST0_A0();
2409 break;
2410 case 2:
2411 gen_op_fstl_ST0_A0();
2412 break;
2413 case 3:
2414 default:
2415 gen_op_fist_ST0_A0();
2416 break;
367e86e8
FB
2417 }
2418 if ((op & 7) == 3)
927f621e 2419 gen_op_fpop();
367e86e8
FB
2420 break;
2421 }
2422 break;
4b74fe1f
FB
2423 case 0x0d: /* fldcw mem */
2424 gen_op_fldcw_A0();
2425 break;
2426 case 0x0f: /* fnstcw mem */
2427 gen_op_fnstcw_A0();
2428 break;
77f8dd5a
FB
2429 case 0x1d: /* fldt mem */
2430 gen_op_fpush();
2431 gen_op_fldt_ST0_A0();
2432 break;
2433 case 0x1f: /* fstpt mem */
2434 gen_op_fstt_ST0_A0();
2435 gen_op_fpop();
2436 break;
367e86e8 2437 case 0x2f: /* fnstsw mem */
4b74fe1f 2438 gen_op_fnstsw_A0();
367e86e8 2439 break;
367e86e8 2440 case 0x3c: /* fbld */
77f8dd5a 2441 gen_op_fpush();
1017ebe9 2442 gen_op_fbld_ST0_A0();
77f8dd5a 2443 break;
367e86e8 2444 case 0x3e: /* fbstp */
77f8dd5a
FB
2445 gen_op_fbst_ST0_A0();
2446 gen_op_fpop();
2447 break;
367e86e8 2448 case 0x3d: /* fildll */
927f621e
FB
2449 gen_op_fpush();
2450 gen_op_fildll_ST0_A0();
367e86e8
FB
2451 break;
2452 case 0x3f: /* fistpll */
927f621e
FB
2453 gen_op_fistll_ST0_A0();
2454 gen_op_fpop();
367e86e8
FB
2455 break;
2456 default:
1a9353d2 2457 goto illegal_op;
367e86e8
FB
2458 }
2459 } else {
2460 /* register float ops */
927f621e 2461 opreg = rm;
367e86e8
FB
2462
2463 switch(op) {
2464 case 0x08: /* fld sti */
927f621e
FB
2465 gen_op_fpush();
2466 gen_op_fmov_ST0_STN((opreg + 1) & 7);
367e86e8
FB
2467 break;
2468 case 0x09: /* fxchg sti */
77f8dd5a 2469 gen_op_fxchg_ST0_STN(opreg);
367e86e8
FB
2470 break;
2471 case 0x0a: /* grp d9/2 */
2472 switch(rm) {
2473 case 0: /* fnop */
367e86e8
FB
2474 break;
2475 default:
1a9353d2 2476 goto illegal_op;
367e86e8
FB
2477 }
2478 break;
2479 case 0x0c: /* grp d9/4 */
2480 switch(rm) {
2481 case 0: /* fchs */
927f621e 2482 gen_op_fchs_ST0();
367e86e8
FB
2483 break;
2484 case 1: /* fabs */
927f621e 2485 gen_op_fabs_ST0();
367e86e8
FB
2486 break;
2487 case 4: /* ftst */
927f621e
FB
2488 gen_op_fldz_FT0();
2489 gen_op_fcom_ST0_FT0();
367e86e8
FB
2490 break;
2491 case 5: /* fxam */
927f621e 2492 gen_op_fxam_ST0();
367e86e8
FB
2493 break;
2494 default:
1a9353d2 2495 goto illegal_op;
367e86e8
FB
2496 }
2497 break;
2498 case 0x0d: /* grp d9/5 */
2499 {
927f621e
FB
2500 switch(rm) {
2501 case 0:
77f8dd5a 2502 gen_op_fpush();
927f621e
FB
2503 gen_op_fld1_ST0();
2504 break;
2505 case 1:
77f8dd5a
FB
2506 gen_op_fpush();
2507 gen_op_fldl2t_ST0();
927f621e
FB
2508 break;
2509 case 2:
77f8dd5a
FB
2510 gen_op_fpush();
2511 gen_op_fldl2e_ST0();
927f621e
FB
2512 break;
2513 case 3:
77f8dd5a 2514 gen_op_fpush();
927f621e
FB
2515 gen_op_fldpi_ST0();
2516 break;
2517 case 4:
77f8dd5a 2518 gen_op_fpush();
927f621e
FB
2519 gen_op_fldlg2_ST0();
2520 break;
2521 case 5:
77f8dd5a 2522 gen_op_fpush();
927f621e
FB
2523 gen_op_fldln2_ST0();
2524 break;
2525 case 6:
77f8dd5a 2526 gen_op_fpush();
927f621e
FB
2527 gen_op_fldz_ST0();
2528 break;
2529 default:
1a9353d2 2530 goto illegal_op;
367e86e8 2531 }
367e86e8
FB
2532 }
2533 break;
2534 case 0x0e: /* grp d9/6 */
2535 switch(rm) {
2536 case 0: /* f2xm1 */
927f621e 2537 gen_op_f2xm1();
367e86e8
FB
2538 break;
2539 case 1: /* fyl2x */
927f621e 2540 gen_op_fyl2x();
367e86e8
FB
2541 break;
2542 case 2: /* fptan */
927f621e 2543 gen_op_fptan();
367e86e8
FB
2544 break;
2545 case 3: /* fpatan */
927f621e 2546 gen_op_fpatan();
367e86e8
FB
2547 break;
2548 case 4: /* fxtract */
927f621e 2549 gen_op_fxtract();
367e86e8
FB
2550 break;
2551 case 5: /* fprem1 */
927f621e 2552 gen_op_fprem1();
367e86e8
FB
2553 break;
2554 case 6: /* fdecstp */
927f621e 2555 gen_op_fdecstp();
367e86e8
FB
2556 break;
2557 default:
927f621e
FB
2558 case 7: /* fincstp */
2559 gen_op_fincstp();
367e86e8
FB
2560 break;
2561 }
2562 break;
2563 case 0x0f: /* grp d9/7 */
2564 switch(rm) {
2565 case 0: /* fprem */
927f621e 2566 gen_op_fprem();
367e86e8
FB
2567 break;
2568 case 1: /* fyl2xp1 */
927f621e
FB
2569 gen_op_fyl2xp1();
2570 break;
2571 case 2: /* fsqrt */
2572 gen_op_fsqrt();
367e86e8
FB
2573 break;
2574 case 3: /* fsincos */
927f621e 2575 gen_op_fsincos();
367e86e8
FB
2576 break;
2577 case 5: /* fscale */
927f621e 2578 gen_op_fscale();
367e86e8 2579 break;
367e86e8 2580 case 4: /* frndint */
927f621e
FB
2581 gen_op_frndint();
2582 break;
367e86e8 2583 case 6: /* fsin */
927f621e
FB
2584 gen_op_fsin();
2585 break;
367e86e8
FB
2586 default:
2587 case 7: /* fcos */
927f621e 2588 gen_op_fcos();
367e86e8
FB
2589 break;
2590 }
2591 break;
2592 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
2593 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
2594 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
2595 {
927f621e 2596 int op1;
367e86e8 2597
927f621e 2598 op1 = op & 7;
367e86e8 2599 if (op >= 0x20) {
927f621e 2600 gen_op_fp_arith_STN_ST0[op1](opreg);
77f8dd5a
FB
2601 if (op >= 0x30)
2602 gen_op_fpop();
367e86e8 2603 } else {
927f621e
FB
2604 gen_op_fmov_FT0_STN(opreg);
2605 gen_op_fp_arith_ST0_FT0[op1]();
367e86e8 2606 }
367e86e8
FB
2607 }
2608 break;
2609 case 0x02: /* fcom */
927f621e
FB
2610 gen_op_fmov_FT0_STN(opreg);
2611 gen_op_fcom_ST0_FT0();
367e86e8
FB
2612 break;
2613 case 0x03: /* fcomp */
927f621e
FB
2614 gen_op_fmov_FT0_STN(opreg);
2615 gen_op_fcom_ST0_FT0();
2616 gen_op_fpop();
367e86e8
FB
2617 break;
2618 case 0x15: /* da/5 */
2619 switch(rm) {
2620 case 1: /* fucompp */
927f621e 2621 gen_op_fmov_FT0_STN(1);
77f8dd5a 2622 gen_op_fucom_ST0_FT0();
927f621e
FB
2623 gen_op_fpop();
2624 gen_op_fpop();
367e86e8
FB
2625 break;
2626 default:
1a9353d2
FB
2627 goto illegal_op;
2628 }
2629 break;
2630 case 0x1c:
2631 switch(rm) {
2632 case 2: /* fclex */
2633 gen_op_fclex();
2634 break;
2635 case 3: /* fninit */
2636 gen_op_fninit();
2637 break;
2638 default:
2639 goto illegal_op;
367e86e8
FB
2640 }
2641 break;
2642 case 0x2a: /* fst sti */
927f621e 2643 gen_op_fmov_STN_ST0(opreg);
367e86e8
FB
2644 break;
2645 case 0x2b: /* fstp sti */
927f621e
FB
2646 gen_op_fmov_STN_ST0(opreg);
2647 gen_op_fpop();
367e86e8 2648 break;
77f8dd5a
FB
2649 case 0x2c: /* fucom st(i) */
2650 gen_op_fmov_FT0_STN(opreg);
2651 gen_op_fucom_ST0_FT0();
2652 break;
2653 case 0x2d: /* fucomp st(i) */
2654 gen_op_fmov_FT0_STN(opreg);
2655 gen_op_fucom_ST0_FT0();
2656 gen_op_fpop();
2657 break;
367e86e8
FB
2658 case 0x33: /* de/3 */
2659 switch(rm) {
2660 case 1: /* fcompp */
927f621e
FB
2661 gen_op_fmov_FT0_STN(1);
2662 gen_op_fcom_ST0_FT0();
2663 gen_op_fpop();
2664 gen_op_fpop();
367e86e8
FB
2665 break;
2666 default:
1a9353d2 2667 goto illegal_op;
367e86e8
FB
2668 }
2669 break;
2670 case 0x3c: /* df/4 */
2671 switch(rm) {
2672 case 0:
77f8dd5a 2673 gen_op_fnstsw_EAX();
367e86e8
FB
2674 break;
2675 default:
1a9353d2 2676 goto illegal_op;
367e86e8
FB
2677 }
2678 break;
2679 default:
1a9353d2 2680 goto illegal_op;
367e86e8
FB
2681 }
2682 }
2683 break;
367e86e8
FB
2684 /************************/
2685 /* string ops */
9c605cb1 2686
367e86e8
FB
2687 case 0xa4: /* movsS */
2688 case 0xa5:
2689 if ((b & 1) == 0)
2690 ot = OT_BYTE;
2691 else
2692 ot = dflag ? OT_LONG : OT_WORD;
9c605cb1 2693
367e86e8 2694 if (prefixes & PREFIX_REPZ) {
9c605cb1 2695 gen_string_ds(s, ot, gen_op_movs + 9);
367e86e8 2696 } else {
9c605cb1 2697 gen_string_ds(s, ot, gen_op_movs);
367e86e8
FB
2698 }
2699 break;
2700
2701 case 0xaa: /* stosS */
2702 case 0xab:
2703 if ((b & 1) == 0)
2704 ot = OT_BYTE;
2705 else
2706 ot = dflag ? OT_LONG : OT_WORD;
9c605cb1 2707
367e86e8 2708 if (prefixes & PREFIX_REPZ) {
9c605cb1 2709 gen_string_es(s, ot, gen_op_stos + 9);
367e86e8 2710 } else {
9c605cb1 2711 gen_string_es(s, ot, gen_op_stos);
367e86e8
FB
2712 }
2713 break;
2714 case 0xac: /* lodsS */
2715 case 0xad:
2716 if ((b & 1) == 0)
2717 ot = OT_BYTE;
2718 else
2719 ot = dflag ? OT_LONG : OT_WORD;
2720 if (prefixes & PREFIX_REPZ) {
9c605cb1 2721 gen_string_ds(s, ot, gen_op_lods + 9);
367e86e8 2722 } else {
9c605cb1 2723 gen_string_ds(s, ot, gen_op_lods);
367e86e8
FB
2724 }
2725 break;
2726 case 0xae: /* scasS */
2727 case 0xaf:
2728 if ((b & 1) == 0)
2729 ot = OT_BYTE;
2730 else
9c605cb1 2731 ot = dflag ? OT_LONG : OT_WORD;
367e86e8 2732 if (prefixes & PREFIX_REPNZ) {
4b74fe1f
FB
2733 if (s->cc_op != CC_OP_DYNAMIC)
2734 gen_op_set_cc_op(s->cc_op);
9c605cb1 2735 gen_string_es(s, ot, gen_op_scas + 9 * 2);
4b74fe1f 2736 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2737 } else if (prefixes & PREFIX_REPZ) {
4b74fe1f
FB
2738 if (s->cc_op != CC_OP_DYNAMIC)
2739 gen_op_set_cc_op(s->cc_op);
9c605cb1 2740 gen_string_es(s, ot, gen_op_scas + 9);
4b74fe1f 2741 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2742 } else {
9c605cb1 2743 gen_string_es(s, ot, gen_op_scas);
4b74fe1f 2744 s->cc_op = CC_OP_SUBB + ot;
367e86e8
FB
2745 }
2746 break;
2747
2748 case 0xa6: /* cmpsS */
2749 case 0xa7:
2750 if ((b & 1) == 0)
2751 ot = OT_BYTE;
2752 else
2753 ot = dflag ? OT_LONG : OT_WORD;
2754 if (prefixes & PREFIX_REPNZ) {
4b74fe1f
FB
2755 if (s->cc_op != CC_OP_DYNAMIC)
2756 gen_op_set_cc_op(s->cc_op);
9c605cb1 2757 gen_string_ds(s, ot, gen_op_cmps + 9 * 2);
4b74fe1f 2758 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2759 } else if (prefixes & PREFIX_REPZ) {
4b74fe1f
FB
2760 if (s->cc_op != CC_OP_DYNAMIC)
2761 gen_op_set_cc_op(s->cc_op);
9c605cb1 2762 gen_string_ds(s, ot, gen_op_cmps + 9);
4b74fe1f 2763 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
367e86e8 2764 } else {
9c605cb1 2765 gen_string_ds(s, ot, gen_op_cmps);
4b74fe1f 2766 s->cc_op = CC_OP_SUBB + ot;
367e86e8
FB
2767 }
2768 break;
367e86e8
FB
2769 case 0x6c: /* insS */
2770 case 0x6d:
982b4315
FB
2771 if (s->cpl > s->iopl || s->vm86) {
2772 /* NOTE: even for (E)CX = 0 the exception is raised */
2773 gen_op_gpf(pc_start - s->cs_base);
367e86e8 2774 } else {
982b4315
FB
2775 if ((b & 1) == 0)
2776 ot = OT_BYTE;
2777 else
2778 ot = dflag ? OT_LONG : OT_WORD;
2779 if (prefixes & PREFIX_REPZ) {
2780 gen_string_es(s, ot, gen_op_ins + 9);
2781 } else {
2782 gen_string_es(s, ot, gen_op_ins);
2783 }
367e86e8
FB
2784 }
2785 break;
2786 case 0x6e: /* outsS */
2787 case 0x6f:
982b4315
FB
2788 if (s->cpl > s->iopl || s->vm86) {
2789 /* NOTE: even for (E)CX = 0 the exception is raised */
2790 gen_op_gpf(pc_start - s->cs_base);
367e86e8 2791 } else {
982b4315
FB
2792 if ((b & 1) == 0)
2793 ot = OT_BYTE;
2794 else
2795 ot = dflag ? OT_LONG : OT_WORD;
2796 if (prefixes & PREFIX_REPZ) {
2797 gen_string_ds(s, ot, gen_op_outs + 9);
2798 } else {
2799 gen_string_ds(s, ot, gen_op_outs);
2800 }
367e86e8
FB
2801 }
2802 break;
9c605cb1
FB
2803
2804 /************************/
2805 /* port I/O */
ba1c6e37
FB
2806 case 0xe4:
2807 case 0xe5:
982b4315
FB
2808 if (s->cpl > s->iopl || s->vm86) {
2809 gen_op_gpf(pc_start - s->cs_base);
2810 } else {
2811 if ((b & 1) == 0)
2812 ot = OT_BYTE;
2813 else
2814 ot = dflag ? OT_LONG : OT_WORD;
2815 val = ldub(s->pc++);
2816 gen_op_movl_T0_im(val);
2817 gen_op_in[ot]();
2818 gen_op_mov_reg_T1[ot][R_EAX]();
2819 }
ba1c6e37
FB
2820 break;
2821 case 0xe6:
2822 case 0xe7:
982b4315
FB
2823 if (s->cpl > s->iopl || s->vm86) {
2824 gen_op_gpf(pc_start - s->cs_base);
2825 } else {
2826 if ((b & 1) == 0)
2827 ot = OT_BYTE;
2828 else
2829 ot = dflag ? OT_LONG : OT_WORD;
2830 val = ldub(s->pc++);
2831 gen_op_movl_T0_im(val);
2832 gen_op_mov_TN_reg[ot][1][R_EAX]();
2833 gen_op_out[ot]();
2834 }
ba1c6e37
FB
2835 break;
2836 case 0xec:
2837 case 0xed:
982b4315
FB
2838 if (s->cpl > s->iopl || s->vm86) {
2839 gen_op_gpf(pc_start - s->cs_base);
2840 } else {
2841 if ((b & 1) == 0)
2842 ot = OT_BYTE;
2843 else
2844 ot = dflag ? OT_LONG : OT_WORD;
2845 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
2846 gen_op_in[ot]();
2847 gen_op_mov_reg_T1[ot][R_EAX]();
2848 }
ba1c6e37
FB
2849 break;
2850 case 0xee:
2851 case 0xef:
982b4315
FB
2852 if (s->cpl > s->iopl || s->vm86) {
2853 gen_op_gpf(pc_start - s->cs_base);
2854 } else {
2855 if ((b & 1) == 0)
2856 ot = OT_BYTE;
2857 else
2858 ot = dflag ? OT_LONG : OT_WORD;
2859 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
2860 gen_op_mov_TN_reg[ot][1][R_EAX]();
2861 gen_op_out[ot]();
2862 }
ba1c6e37 2863 break;
367e86e8
FB
2864
2865 /************************/
2866 /* control */
2867 case 0xc2: /* ret im */
367e86e8
FB
2868 val = ldsw(s->pc);
2869 s->pc += 2;
dab2ed99
FB
2870 gen_pop_T0(s);
2871 if (s->ss32)
2872 gen_op_addl_ESP_im(val + (2 << s->dflag));
2873 else
2874 gen_op_addw_ESP_im(val + (2 << s->dflag));
2875 if (s->dflag == 0)
2876 gen_op_andl_T0_ffff();
367e86e8 2877 gen_op_jmp_T0();
6dbad63e 2878 s->is_jmp = 1;
367e86e8
FB
2879 break;
2880 case 0xc3: /* ret */
dab2ed99
FB
2881 gen_pop_T0(s);
2882 gen_pop_update(s);
2883 if (s->dflag == 0)
2884 gen_op_andl_T0_ffff();
367e86e8 2885 gen_op_jmp_T0();
6dbad63e 2886 s->is_jmp = 1;
367e86e8 2887 break;
dab2ed99 2888 case 0xca: /* lret im */
f631ef9b 2889 /* XXX: not restartable */
dab2ed99
FB
2890 val = ldsw(s->pc);
2891 s->pc += 2;
2892 /* pop offset */
2893 gen_pop_T0(s);
2894 if (s->dflag == 0)
2895 gen_op_andl_T0_ffff();
2896 gen_op_jmp_T0();
2897 gen_pop_update(s);
2898 /* pop selector */
2899 gen_pop_T0(s);
2900 gen_movl_seg_T0(s, R_CS);
2901 gen_pop_update(s);
2902 /* add stack offset */
2903 if (s->ss32)
2904 gen_op_addl_ESP_im(val + (2 << s->dflag));
2905 else
2906 gen_op_addw_ESP_im(val + (2 << s->dflag));
2907 s->is_jmp = 1;
2908 break;
2909 case 0xcb: /* lret */
f631ef9b 2910 /* XXX: not restartable */
dab2ed99
FB
2911 /* pop offset */
2912 gen_pop_T0(s);
2913 if (s->dflag == 0)
2914 gen_op_andl_T0_ffff();
2915 gen_op_jmp_T0();
2916 gen_pop_update(s);
2917 /* pop selector */
2918 gen_pop_T0(s);
2919 gen_movl_seg_T0(s, R_CS);
2920 gen_pop_update(s);
6dbad63e 2921 s->is_jmp = 1;
367e86e8 2922 break;
f631ef9b
FB
2923 case 0xcf: /* iret */
2924 /* XXX: not restartable */
2925 /* pop offset */
2926 gen_pop_T0(s);
2927 if (s->dflag == 0)
2928 gen_op_andl_T0_ffff();
2929 gen_op_jmp_T0();
2930 gen_pop_update(s);
2931 /* pop selector */
2932 gen_pop_T0(s);
2933 gen_movl_seg_T0(s, R_CS);
2934 gen_pop_update(s);
2935 /* pop eflags */
2936 gen_pop_T0(s);
2937 if (s->dflag) {
2938 if (s->vm86)
2939 gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
2940 else
2941 gen_op_movl_eflags_T0();
2942 } else {
2943 if (s->vm86)
2944 gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
2945 else
2946 gen_op_movw_eflags_T0();
2947 }
2948 gen_pop_update(s);
2949 s->cc_op = CC_OP_EFLAGS;
2950 s->is_jmp = 1;
2951 break;
dab2ed99
FB
2952 case 0xe8: /* call im */
2953 {
2954 unsigned int next_eip;
2955 ot = dflag ? OT_LONG : OT_WORD;
2956 val = insn_get(s, ot);
2957 next_eip = s->pc - s->cs_base;
2958 val += next_eip;
2959 if (s->dflag == 0)
2960 val &= 0xffff;
2961 gen_op_movl_T0_im(next_eip);
2962 gen_push_T0(s);
2963 gen_op_jmp_im(val);
2964 s->is_jmp = 1;
2965 }
2966 break;
2967 case 0x9a: /* lcall im */
2968 {
2969 unsigned int selector, offset;
2970
2971 ot = dflag ? OT_LONG : OT_WORD;
2972 offset = insn_get(s, ot);
2973 selector = insn_get(s, OT_WORD);
2974
2975 /* push return segment + offset */
2976 gen_op_movl_T0_seg(R_CS);
2977 gen_push_T0(s);
2978 next_eip = s->pc - s->cs_base;
2979 gen_op_movl_T0_im(next_eip);
2980 gen_push_T0(s);
2981
2982 /* change cs and pc */
2983 gen_op_movl_T0_im(selector);
2984 gen_movl_seg_T0(s, R_CS);
2985 gen_op_jmp_im((unsigned long)offset);
2986 s->is_jmp = 1;
2987 }
2988 break;
367e86e8 2989 case 0xe9: /* jmp */
dab2ed99
FB
2990 ot = dflag ? OT_LONG : OT_WORD;
2991 val = insn_get(s, ot);
2992 val += s->pc - s->cs_base;
2993 if (s->dflag == 0)
2994 val = val & 0xffff;
367e86e8 2995 gen_op_jmp_im(val);
6dbad63e 2996 s->is_jmp = 1;
367e86e8 2997 break;
dab2ed99
FB
2998 case 0xea: /* ljmp im */
2999 {
3000 unsigned int selector, offset;
3001
3002 ot = dflag ? OT_LONG : OT_WORD;
3003 offset = insn_get(s, ot);
3004 selector = insn_get(s, OT_WORD);
3005
3006 /* change cs and pc */
3007 gen_op_movl_T0_im(selector);
3008 gen_movl_seg_T0(s, R_CS);
3009 gen_op_jmp_im((unsigned long)offset);
3010 s->is_jmp = 1;
3011 }
3012 break;
367e86e8
FB
3013 case 0xeb: /* jmp Jb */
3014 val = (int8_t)insn_get(s, OT_BYTE);
dab2ed99
FB
3015 val += s->pc - s->cs_base;
3016 if (s->dflag == 0)
3017 val = val & 0xffff;
367e86e8 3018 gen_op_jmp_im(val);
6dbad63e 3019 s->is_jmp = 1;
367e86e8
FB
3020 break;
3021 case 0x70 ... 0x7f: /* jcc Jb */
3022 val = (int8_t)insn_get(s, OT_BYTE);
367e86e8
FB
3023 goto do_jcc;
3024 case 0x180 ... 0x18f: /* jcc Jv */
3025 if (dflag) {
3026 val = insn_get(s, OT_LONG);
3027 } else {
3028 val = (int16_t)insn_get(s, OT_WORD);
3029 }
367e86e8 3030 do_jcc:
dab2ed99
FB
3031 next_eip = s->pc - s->cs_base;
3032 val += next_eip;
3033 if (s->dflag == 0)
3034 val &= 0xffff;
3035 gen_jcc(s, b, val, next_eip);
6dbad63e 3036 s->is_jmp = 1;
367e86e8
FB
3037 break;
3038
5dd9488c 3039 case 0x190 ... 0x19f: /* setcc Gv */
367e86e8
FB
3040 modrm = ldub(s->pc++);
3041 gen_setcc(s, b);
3042 gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
3043 break;
5dd9488c
FB
3044 case 0x140 ... 0x14f: /* cmov Gv, Ev */
3045 ot = dflag ? OT_LONG : OT_WORD;
3046 modrm = ldub(s->pc++);
3047 reg = (modrm >> 3) & 7;
3048 mod = (modrm >> 6) & 3;
3049 gen_setcc(s, b);
3050 if (mod != 3) {
3051 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3052 gen_op_ld_T1_A0[ot]();
3053 } else {
3054 rm = modrm & 7;
3055 gen_op_mov_TN_reg[ot][1][rm]();
3056 }
3057 gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
3058 break;
3059
367e86e8
FB
3060 /************************/
3061 /* flags */
3062 case 0x9c: /* pushf */
1017ebe9
FB
3063 if (s->cc_op != CC_OP_DYNAMIC)
3064 gen_op_set_cc_op(s->cc_op);
f631ef9b
FB
3065 if (s->vm86)
3066 gen_op_movl_T0_eflags_vm();
3067 else
3068 gen_op_movl_T0_eflags();
dab2ed99 3069 gen_push_T0(s);
367e86e8
FB
3070 break;
3071 case 0x9d: /* popf */
dab2ed99 3072 gen_pop_T0(s);
f631ef9b
FB
3073 if (s->dflag) {
3074 if (s->vm86)
3075 gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
3076 else
3077 gen_op_movl_eflags_T0();
3078 } else {
3079 if (s->vm86)
3080 gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
3081 else
3082 gen_op_movw_eflags_T0();
3083 }
dab2ed99 3084 gen_pop_update(s);
367e86e8
FB
3085 s->cc_op = CC_OP_EFLAGS;
3086 break;
3087 case 0x9e: /* sahf */
3088 gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();
3089 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3090 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3091 gen_op_movb_eflags_T0();
3092 s->cc_op = CC_OP_EFLAGS;
3093 break;
3094 case 0x9f: /* lahf */
3095 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3096 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3097 gen_op_movl_T0_eflags();
3098 gen_op_mov_reg_T0[OT_BYTE][R_AH]();
3099 break;
3100 case 0xf5: /* cmc */
3101 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3102 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3103 gen_op_cmc();
3104 s->cc_op = CC_OP_EFLAGS;
3105 break;
3106 case 0xf8: /* clc */
3107 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3108 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3109 gen_op_clc();
3110 s->cc_op = CC_OP_EFLAGS;
3111 break;
3112 case 0xf9: /* stc */
3113 if (s->cc_op != CC_OP_DYNAMIC)
1017ebe9 3114 gen_op_set_cc_op(s->cc_op);
367e86e8
FB
3115 gen_op_stc();
3116 s->cc_op = CC_OP_EFLAGS;
3117 break;
3118 case 0xfc: /* cld */
3119 gen_op_cld();
3120 break;
3121 case 0xfd: /* std */
3122 gen_op_std();
3123 break;
3124
4b74fe1f
FB
3125 /************************/
3126 /* bit operations */
3127 case 0x1ba: /* bt/bts/btr/btc Gv, im */
3128 ot = dflag ? OT_LONG : OT_WORD;
3129 modrm = ldub(s->pc++);
3130 op = (modrm >> 3) & 7;
3131 mod = (modrm >> 6) & 3;
3132 rm = modrm & 7;
3133 if (mod != 3) {
3134 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3135 gen_op_ld_T0_A0[ot]();
3136 } else {
3137 gen_op_mov_TN_reg[ot][0][rm]();
3138 }
3139 /* load shift */
3140 val = ldub(s->pc++);
3141 gen_op_movl_T1_im(val);
3142 if (op < 4)
1a9353d2 3143 goto illegal_op;
4b74fe1f
FB
3144 op -= 4;
3145 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
d57c4e01 3146 s->cc_op = CC_OP_SARB + ot;
4b74fe1f
FB
3147 if (op != 0) {
3148 if (mod != 3)
3149 gen_op_st_T0_A0[ot]();
3150 else
3151 gen_op_mov_reg_T0[ot][rm]();
3152 }
3153 break;
3154 case 0x1a3: /* bt Gv, Ev */
3155 op = 0;
3156 goto do_btx;
3157 case 0x1ab: /* bts */
3158 op = 1;
3159 goto do_btx;
3160 case 0x1b3: /* btr */
3161 op = 2;
3162 goto do_btx;
3163 case 0x1bb: /* btc */
3164 op = 3;
3165 do_btx:
3166 ot = dflag ? OT_LONG : OT_WORD;
3167 modrm = ldub(s->pc++);
3168 reg = (modrm >> 3) & 7;
3169 mod = (modrm >> 6) & 3;
3170 rm = modrm & 7;
3171 gen_op_mov_TN_reg[OT_LONG][1][reg]();
3172 if (mod != 3) {
3173 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3174 /* specific case: we need to add a displacement */
3175 if (ot == OT_WORD)
3176 gen_op_add_bitw_A0_T1();
3177 else
3178 gen_op_add_bitl_A0_T1();
3179 gen_op_ld_T0_A0[ot]();
3180 } else {
3181 gen_op_mov_TN_reg[ot][0][rm]();
3182 }
3183 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
d57c4e01 3184 s->cc_op = CC_OP_SARB + ot;
4b74fe1f
FB
3185 if (op != 0) {
3186 if (mod != 3)
3187 gen_op_st_T0_A0[ot]();
3188 else
3189 gen_op_mov_reg_T0[ot][rm]();
3190 }
3191 break;
77f8dd5a
FB
3192 case 0x1bc: /* bsf */
3193 case 0x1bd: /* bsr */
3194 ot = dflag ? OT_LONG : OT_WORD;
3195 modrm = ldub(s->pc++);
3196 reg = (modrm >> 3) & 7;
3197 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
3198 gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
3199 /* NOTE: we always write back the result. Intel doc says it is
3200 undefined if T0 == 0 */
3201 gen_op_mov_reg_T0[ot][reg]();
3202 s->cc_op = CC_OP_LOGICB + ot;
3203 break;
367e86e8 3204 /************************/
27362c82
FB
3205 /* bcd */
3206 case 0x27: /* daa */
3207 if (s->cc_op != CC_OP_DYNAMIC)
3208 gen_op_set_cc_op(s->cc_op);
3209 gen_op_daa();
3210 s->cc_op = CC_OP_EFLAGS;
3211 break;
3212 case 0x2f: /* das */
3213 if (s->cc_op != CC_OP_DYNAMIC)
3214 gen_op_set_cc_op(s->cc_op);
3215 gen_op_das();
3216 s->cc_op = CC_OP_EFLAGS;
3217 break;
3218 case 0x37: /* aaa */
3219 if (s->cc_op != CC_OP_DYNAMIC)
3220 gen_op_set_cc_op(s->cc_op);
3221 gen_op_aaa();
3222 s->cc_op = CC_OP_EFLAGS;
3223 break;
3224 case 0x3f: /* aas */
3225 if (s->cc_op != CC_OP_DYNAMIC)
3226 gen_op_set_cc_op(s->cc_op);
3227 gen_op_aas();
3228 s->cc_op = CC_OP_EFLAGS;
3229 break;
3230 case 0xd4: /* aam */
3231 val = ldub(s->pc++);
3232 gen_op_aam(val);
3233 s->cc_op = CC_OP_LOGICB;
3234 break;
3235 case 0xd5: /* aad */
3236 val = ldub(s->pc++);
3237 gen_op_aad(val);
3238 s->cc_op = CC_OP_LOGICB;
3239 break;
3240 /************************/
367e86e8
FB
3241 /* misc */
3242 case 0x90: /* nop */
3243 break;
0ecfa993
FB
3244 case 0xcc: /* int3 */
3245 gen_op_int3((long)pc_start);
6dbad63e 3246 s->is_jmp = 1;
0ecfa993
FB
3247 break;
3248 case 0xcd: /* int N */
3249 val = ldub(s->pc++);
982b4315 3250 gen_op_int_im(val, pc_start - s->cs_base);
6dbad63e 3251 s->is_jmp = 1;
0ecfa993
FB
3252 break;
3253 case 0xce: /* into */
3254 if (s->cc_op != CC_OP_DYNAMIC)
3255 gen_op_set_cc_op(s->cc_op);
9c605cb1
FB
3256 gen_op_into();
3257 break;
f631ef9b 3258 case 0xfa: /* cli */
982b4315
FB
3259 if (!s->vm86) {
3260 if (s->cpl <= s->iopl)
3261 gen_op_cli();
3262 else
3263 gen_op_gpf(pc_start - s->cs_base);
3264 } else {
3265 if (s->iopl == 3)
3266 gen_op_cli();
3267 else
3268 gen_op_cli_vm();
3269 }
f631ef9b
FB
3270 break;
3271 case 0xfb: /* sti */
982b4315
FB
3272 if (!s->vm86) {
3273 if (s->cpl <= s->iopl)
3274 gen_op_sti();
3275 else
3276 gen_op_gpf(pc_start - s->cs_base);
3277 } else {
3278 if (s->iopl == 3)
3279 gen_op_sti();
3280 else
3281 gen_op_sti_vm(pc_start - s->cs_base);
3282 }
f631ef9b 3283 break;
9c605cb1
FB
3284 case 0x62: /* bound */
3285 ot = dflag ? OT_LONG : OT_WORD;
3286 modrm = ldub(s->pc++);
3287 reg = (modrm >> 3) & 7;
3288 mod = (modrm >> 6) & 3;
3289 if (mod == 3)
3290 goto illegal_op;
3291 gen_op_mov_reg_T0[ot][reg]();
3292 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3293 if (ot == OT_WORD)
3294 gen_op_boundw();
3295 else
3296 gen_op_boundl();
0ecfa993 3297 break;
4b74fe1f 3298 case 0x1c8 ... 0x1cf: /* bswap reg */
27362c82
FB
3299 reg = b & 7;
3300 gen_op_mov_TN_reg[OT_LONG][0][reg]();
3301 gen_op_bswapl_T0();
3302 gen_op_mov_reg_T0[OT_LONG][reg]();
3303 break;
3304 case 0xd6: /* salc */
3305 if (s->cc_op != CC_OP_DYNAMIC)
3306 gen_op_set_cc_op(s->cc_op);
3307 gen_op_salc();
3308 break;
1a9353d2
FB
3309 case 0xe0: /* loopnz */
3310 case 0xe1: /* loopz */
3311 if (s->cc_op != CC_OP_DYNAMIC)
3312 gen_op_set_cc_op(s->cc_op);
3313 /* FALL THRU */
3314 case 0xe2: /* loop */
3315 case 0xe3: /* jecxz */
3316 val = (int8_t)insn_get(s, OT_BYTE);
dab2ed99
FB
3317 next_eip = s->pc - s->cs_base;
3318 val += next_eip;
3319 if (s->dflag == 0)
3320 val &= 0xffff;
3321 gen_op_loop[s->aflag][b & 3](val, next_eip);
1a9353d2
FB
3322 s->is_jmp = 1;
3323 break;
5dd9488c 3324 case 0x131: /* rdtsc */
27362c82
FB
3325 gen_op_rdtsc();
3326 break;
367e86e8 3327 case 0x1a2: /* cpuid */
9c605cb1 3328 gen_op_cpuid();
367e86e8 3329 break;
982b4315
FB
3330 case 0xf4: /* hlt */
3331 if (s->cpl == 0) {
3332 /* ignored */
3333 } else {
3334 gen_op_gpf(pc_start - s->cs_base);
3335 }
3336 break;
367e86e8 3337 default:
1a9353d2 3338 goto illegal_op;
367e86e8 3339 }
1b6b029e
FB
3340 /* lock generation */
3341 if (s->prefix & PREFIX_LOCK)
3342 gen_op_unlock();
367e86e8 3343 return (long)s->pc;
6dbad63e 3344 illegal_op:
1b6b029e 3345 /* XXX: ensure that no lock was generated */
6dbad63e 3346 return -1;
367e86e8
FB
3347}
3348
dc99065b
FB
3349#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
3350#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
3351
3352/* flags read by an operation */
3353static uint16_t opc_read_flags[NB_OPS] = {
3354 [INDEX_op_aas] = CC_A,
3355 [INDEX_op_aaa] = CC_A,
3356 [INDEX_op_das] = CC_A | CC_C,
3357 [INDEX_op_daa] = CC_A | CC_C,
3358
3359 [INDEX_op_adcb_T0_T1_cc] = CC_C,
3360 [INDEX_op_adcw_T0_T1_cc] = CC_C,
3361 [INDEX_op_adcl_T0_T1_cc] = CC_C,
3362 [INDEX_op_sbbb_T0_T1_cc] = CC_C,
3363 [INDEX_op_sbbw_T0_T1_cc] = CC_C,
3364 [INDEX_op_sbbl_T0_T1_cc] = CC_C,
3365
982b4315
FB
3366 /* subtle: due to the incl/decl implementation, C is used */
3367 [INDEX_op_incl_T0_cc] = CC_C,
3368 [INDEX_op_decl_T0_cc] = CC_C,
3369
dc99065b
FB
3370 [INDEX_op_into] = CC_O,
3371
3372 [INDEX_op_jo_cc] = CC_O,
3373 [INDEX_op_jb_cc] = CC_C,
3374 [INDEX_op_jz_cc] = CC_Z,
3375 [INDEX_op_jbe_cc] = CC_Z | CC_C,
3376 [INDEX_op_js_cc] = CC_S,
3377 [INDEX_op_jp_cc] = CC_P,
3378 [INDEX_op_jl_cc] = CC_O | CC_S,
3379 [INDEX_op_jle_cc] = CC_O | CC_S | CC_Z,
3380
3381 [INDEX_op_jb_subb] = CC_C,
3382 [INDEX_op_jb_subw] = CC_C,
3383 [INDEX_op_jb_subl] = CC_C,
3384
3385 [INDEX_op_jz_subb] = CC_Z,
3386 [INDEX_op_jz_subw] = CC_Z,
3387 [INDEX_op_jz_subl] = CC_Z,
3388
3389 [INDEX_op_jbe_subb] = CC_Z | CC_C,
3390 [INDEX_op_jbe_subw] = CC_Z | CC_C,
3391 [INDEX_op_jbe_subl] = CC_Z | CC_C,
3392
3393 [INDEX_op_js_subb] = CC_S,
3394 [INDEX_op_js_subw] = CC_S,
3395 [INDEX_op_js_subl] = CC_S,
3396
3397 [INDEX_op_jl_subb] = CC_O | CC_S,
3398 [INDEX_op_jl_subw] = CC_O | CC_S,
3399 [INDEX_op_jl_subl] = CC_O | CC_S,
3400
3401 [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z,
3402 [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z,
3403 [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z,
3404
3405 [INDEX_op_loopnzw] = CC_Z,
3406 [INDEX_op_loopnzl] = CC_Z,
3407 [INDEX_op_loopzw] = CC_Z,
3408 [INDEX_op_loopzl] = CC_Z,
3409
3410 [INDEX_op_seto_T0_cc] = CC_O,
3411 [INDEX_op_setb_T0_cc] = CC_C,
3412 [INDEX_op_setz_T0_cc] = CC_Z,
3413 [INDEX_op_setbe_T0_cc] = CC_Z | CC_C,
3414 [INDEX_op_sets_T0_cc] = CC_S,
3415 [INDEX_op_setp_T0_cc] = CC_P,
3416 [INDEX_op_setl_T0_cc] = CC_O | CC_S,
3417 [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z,
3418
3419 [INDEX_op_setb_T0_subb] = CC_C,
3420 [INDEX_op_setb_T0_subw] = CC_C,
3421 [INDEX_op_setb_T0_subl] = CC_C,
3422
3423 [INDEX_op_setz_T0_subb] = CC_Z,
3424 [INDEX_op_setz_T0_subw] = CC_Z,
3425 [INDEX_op_setz_T0_subl] = CC_Z,
3426
3427 [INDEX_op_setbe_T0_subb] = CC_Z | CC_C,
3428 [INDEX_op_setbe_T0_subw] = CC_Z | CC_C,
3429 [INDEX_op_setbe_T0_subl] = CC_Z | CC_C,
3430
3431 [INDEX_op_sets_T0_subb] = CC_S,
3432 [INDEX_op_sets_T0_subw] = CC_S,
3433 [INDEX_op_sets_T0_subl] = CC_S,
3434
3435 [INDEX_op_setl_T0_subb] = CC_O | CC_S,
3436 [INDEX_op_setl_T0_subw] = CC_O | CC_S,
3437 [INDEX_op_setl_T0_subl] = CC_O | CC_S,
3438
3439 [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z,
3440 [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z,
3441 [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
3442
3443 [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
f631ef9b 3444 [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
dc99065b
FB
3445 [INDEX_op_cmc] = CC_C,
3446 [INDEX_op_salc] = CC_C,
3447
3448 [INDEX_op_rclb_T0_T1_cc] = CC_C,
3449 [INDEX_op_rclw_T0_T1_cc] = CC_C,
3450 [INDEX_op_rcll_T0_T1_cc] = CC_C,
3451 [INDEX_op_rcrb_T0_T1_cc] = CC_C,
3452 [INDEX_op_rcrw_T0_T1_cc] = CC_C,
3453 [INDEX_op_rcrl_T0_T1_cc] = CC_C,
3454};
3455
3456/* flags written by an operation */
3457static uint16_t opc_write_flags[NB_OPS] = {
3458 [INDEX_op_addl_T0_T1_cc] = CC_OSZAPC,
3459 [INDEX_op_orl_T0_T1_cc] = CC_OSZAPC,
3460 [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
3461 [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
3462 [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
3463 [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
3464 [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
3465 [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
3466 [INDEX_op_andl_T0_T1_cc] = CC_OSZAPC,
3467 [INDEX_op_subl_T0_T1_cc] = CC_OSZAPC,
3468 [INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC,
3469 [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
3470 [INDEX_op_negl_T0_cc] = CC_OSZAPC,
982b4315
FB
3471 /* subtle: due to the incl/decl implementation, C is used */
3472 [INDEX_op_incl_T0_cc] = CC_OSZAPC,
3473 [INDEX_op_decl_T0_cc] = CC_OSZAPC,
dc99065b
FB
3474 [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
3475
3476 [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
3477 [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
3478 [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
3479 [INDEX_op_imulw_AX_T0] = CC_OSZAPC,
3480 [INDEX_op_mull_EAX_T0] = CC_OSZAPC,
3481 [INDEX_op_imull_EAX_T0] = CC_OSZAPC,
3482 [INDEX_op_imulw_T0_T1] = CC_OSZAPC,
3483 [INDEX_op_imull_T0_T1] = CC_OSZAPC,
3484
3485 /* bcd */
3486 [INDEX_op_aam] = CC_OSZAPC,
3487 [INDEX_op_aad] = CC_OSZAPC,
3488 [INDEX_op_aas] = CC_OSZAPC,
3489 [INDEX_op_aaa] = CC_OSZAPC,
3490 [INDEX_op_das] = CC_OSZAPC,
3491 [INDEX_op_daa] = CC_OSZAPC,
3492
3493 [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
f631ef9b
FB
3494 [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
3495 [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC,
dc99065b 3496 [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
f631ef9b 3497 [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC,
dc99065b
FB
3498 [INDEX_op_clc] = CC_C,
3499 [INDEX_op_stc] = CC_C,
3500 [INDEX_op_cmc] = CC_C,
3501
3502 [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C,
3503 [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C,
3504 [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C,
3505 [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C,
3506 [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C,
3507 [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C,
3508
3509 [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C,
3510 [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C,
3511 [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C,
3512 [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C,
3513 [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C,
3514 [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C,
3515
3516 [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC,
3517 [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC,
3518 [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC,
3519
3520 [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC,
3521 [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC,
3522 [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC,
3523
3524 [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC,
3525 [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC,
3526 [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC,
3527
3528 [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC,
3529 [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC,
3530 [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC,
3531 [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC,
3532
3533 [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC,
3534 [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC,
3535 [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
3536 [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
3537
3538 [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
3539 [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
3540 [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
3541 [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC,
3542 [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC,
3543 [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC,
3544 [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC,
3545 [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC,
3546
3547 [INDEX_op_bsfw_T0_cc] = CC_OSZAPC,
3548 [INDEX_op_bsfl_T0_cc] = CC_OSZAPC,
3549 [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
3550 [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
3551
9c605cb1
FB
3552#undef STRINGOP
3553#define STRINGOP(x) \
3554 [INDEX_op_ ## x ## b_fast] = CC_OSZAPC, \
3555 [INDEX_op_ ## x ## w_fast] = CC_OSZAPC, \
3556 [INDEX_op_ ## x ## l_fast] = CC_OSZAPC, \
3557 [INDEX_op_ ## x ## b_a32] = CC_OSZAPC, \
3558 [INDEX_op_ ## x ## w_a32] = CC_OSZAPC, \
3559 [INDEX_op_ ## x ## l_a32] = CC_OSZAPC, \
3560 [INDEX_op_ ## x ## b_a16] = CC_OSZAPC, \
3561 [INDEX_op_ ## x ## w_a16] = CC_OSZAPC, \
3562 [INDEX_op_ ## x ## l_a16] = CC_OSZAPC,
3563
3564 STRINGOP(scas)
3565 STRINGOP(repz_scas)
3566 STRINGOP(repnz_scas)
3567 STRINGOP(cmps)
3568 STRINGOP(repz_cmps)
3569 STRINGOP(repnz_cmps)
3570
3571 [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
dc99065b
FB
3572 [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
3573 [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
9c605cb1
FB
3574
3575 [INDEX_op_cmpxchg8b] = CC_Z,
dc99065b
FB
3576};
3577
3578/* simpler form of an operation if no flags need to be generated */
3579static uint16_t opc_simpler[NB_OPS] = {
3580 [INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1,
3581 [INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1,
3582 [INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1,
3583 [INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1,
3584 [INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1,
3585 [INDEX_op_negl_T0_cc] = INDEX_op_negl_T0,
3586 [INDEX_op_incl_T0_cc] = INDEX_op_incl_T0,
3587 [INDEX_op_decl_T0_cc] = INDEX_op_decl_T0,
3588
3589 [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
3590 [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
3591 [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
3592
3593 [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1,
3594 [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
3595 [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
3596
3597 [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
3598 [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
3599 [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
3600
3601 [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1,
3602 [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1,
3603 [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1,
3604
3605 [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
3606 [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
3607 [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
3608};
3609
3610static void optimize_flags_init(void)
3611{
3612 int i;
3613 /* put default values in arrays */
3614 for(i = 0; i < NB_OPS; i++) {
3615 if (opc_simpler[i] == 0)
3616 opc_simpler[i] = i;
3617 }
3618}
3619
3620/* CPU flags computation optimization: we move backward thru the
3621 generated code to see which flags are needed. The operation is
3622 modified if suitable */
3623static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
3624{
3625 uint16_t *opc_ptr;
3626 int live_flags, write_flags, op;
3627
3628 opc_ptr = opc_buf + opc_buf_len;
3629 /* live_flags contains the flags needed by the next instructions
3630 in the code. At the end of the bloc, we consider that all the
3631 flags are live. */
3632 live_flags = CC_OSZAPC;
3633 while (opc_ptr > opc_buf) {
3634 op = *--opc_ptr;
3635 /* if none of the flags written by the instruction is used,
3636 then we can try to find a simpler instruction */
3637 write_flags = opc_write_flags[op];
3638 if ((live_flags & write_flags) == 0) {
3639 *opc_ptr = opc_simpler[op];
3640 }
3641 /* compute the live flags before the instruction */
3642 live_flags &= ~write_flags;
3643 live_flags |= opc_read_flags[op];
3644 }
3645}
3646
3647
3648#ifdef DEBUG_DISAS
3649static const char *op_str[] = {
9c605cb1
FB
3650#define DEF(s, n) #s,
3651#include "opc-i386.h"
3652#undef DEF
3653};
3654
3655static uint8_t op_nb_args[] = {
3656#define DEF(s, n) n,
dc99065b
FB
3657#include "opc-i386.h"
3658#undef DEF
3659};
3660
9c605cb1 3661static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
dc99065b
FB
3662{
3663 const uint16_t *opc_ptr;
9c605cb1
FB
3664 const uint32_t *opparam_ptr;
3665 int c, n, i;
3666
dc99065b 3667 opc_ptr = opc_buf;
9c605cb1 3668 opparam_ptr = opparam_buf;
dc99065b
FB
3669 for(;;) {
3670 c = *opc_ptr++;
9c605cb1
FB
3671 n = op_nb_args[c];
3672 fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]);
3673 for(i = 0; i < n; i++) {
3674 fprintf(logfile, " 0x%x", opparam_ptr[i]);
3675 }
3676 fprintf(logfile, "\n");
dc99065b
FB
3677 if (c == INDEX_op_end)
3678 break;
9c605cb1 3679 opparam_ptr += n;
dc99065b
FB
3680 }
3681}
3682
3683#endif
3684
3685/* XXX: make this buffer thread safe */
3686/* XXX: make safe guess about sizes */
3687#define MAX_OP_PER_INSTR 32
3688#define OPC_BUF_SIZE 512
3689#define OPC_MAX_SIZE (OPC_BUF_SIZE - MAX_OP_PER_INSTR)
3690
3691#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
3692
3693static uint16_t gen_opc_buf[OPC_BUF_SIZE];
3694static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
3695
9de5e440
FB
3696/* return non zero if the very first instruction is invalid so that
3697 the virtual CPU can trigger an exception. */
1017ebe9 3698int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
dab2ed99
FB
3699 int *gen_code_size_ptr,
3700 uint8_t *pc_start, uint8_t *cs_base, int flags)
ba1c6e37
FB
3701{
3702 DisasContext dc1, *dc = &dc1;
dc99065b
FB
3703 uint8_t *pc_ptr;
3704 uint16_t *gen_opc_end;
04369ff2 3705 int gen_code_size;
ba1c6e37 3706 long ret;
dc99065b
FB
3707
3708 /* generate intermediate code */
3709
6dbad63e 3710 dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
dab2ed99 3711 dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
6dbad63e
FB
3712 dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
3713 dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
9c605cb1 3714 dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
982b4315
FB
3715 dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3;
3716 dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3;
ba1c6e37 3717 dc->cc_op = CC_OP_DYNAMIC;
dab2ed99 3718 dc->cs_base = cs_base;
dc99065b
FB
3719
3720 gen_opc_ptr = gen_opc_buf;
3721 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3722 gen_opparam_ptr = gen_opparam_buf;
0ecfa993 3723
6dbad63e 3724 dc->is_jmp = 0;
1017ebe9
FB
3725 pc_ptr = pc_start;
3726 do {
6dbad63e 3727 ret = disas_insn(dc, pc_ptr);
1a9353d2 3728 if (ret == -1) {
9de5e440
FB
3729 /* we trigger an illegal instruction operation only if it
3730 is the first instruction. Otherwise, we simply stop
3731 generating the code just before it */
3732 if (pc_ptr == pc_start)
3733 return -1;
3734 else
3735 break;
1a9353d2 3736 }
1017ebe9 3737 pc_ptr = (void *)ret;
dc99065b 3738 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end);
0ecfa993
FB
3739 /* we must store the eflags state if it is not already done */
3740 if (dc->cc_op != CC_OP_DYNAMIC)
3741 gen_op_set_cc_op(dc->cc_op);
6dbad63e 3742 if (dc->is_jmp != 1) {
0ecfa993 3743 /* we add an additionnal jmp to update the simulated PC */
dab2ed99 3744 gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
0ecfa993 3745 }
dc99065b 3746 *gen_opc_ptr = INDEX_op_end;
0ecfa993
FB
3747
3748#ifdef DEBUG_DISAS
586314f2 3749 if (loglevel) {
dc99065b 3750 fprintf(logfile, "----------------\n");
b9adb4a6
FB
3751 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
3752 disas(logfile, pc_start, pc_ptr - pc_start,
3753 dc->code32 ? DISAS_I386_I386 : DISAS_I386_I8086);
1017ebe9 3754 fprintf(logfile, "\n");
982b4315 3755
dc99065b 3756 fprintf(logfile, "OP:\n");
9c605cb1 3757 dump_ops(gen_opc_buf, gen_opparam_buf);
dc99065b
FB
3758 fprintf(logfile, "\n");
3759 }
3760#endif
3761
3762 /* optimize flag computations */
3763 optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
3764
3765#ifdef DEBUG_DISAS
3766 if (loglevel) {
3767 fprintf(logfile, "AFTER FLAGS OPT:\n");
9c605cb1 3768 dump_ops(gen_opc_buf, gen_opparam_buf);
dc99065b
FB
3769 fprintf(logfile, "\n");
3770 }
3771#endif
3772
3773 /* generate machine code */
04369ff2
FB
3774 gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
3775 flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
3776 *gen_code_size_ptr = gen_code_size;
dc99065b
FB
3777
3778#ifdef DEBUG_DISAS
3779 if (loglevel) {
0ecfa993 3780 fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
b9adb4a6 3781 disas(logfile, gen_code_buf, *gen_code_size_ptr, DISAS_TARGET);
0ecfa993 3782 fprintf(logfile, "\n");
1b6b029e 3783 fflush(logfile);
0ecfa993
FB
3784 }
3785#endif
ba1c6e37
FB
3786 return 0;
3787}
3788
3789CPUX86State *cpu_x86_init(void)
3790{
3791 CPUX86State *env;
3792 int i;
dc99065b 3793 static int inited;
ba1c6e37 3794
7d13299d
FB
3795 cpu_x86_tblocks_init();
3796
ba1c6e37
FB
3797 env = malloc(sizeof(CPUX86State));
3798 if (!env)
3799 return NULL;
3800 memset(env, 0, sizeof(CPUX86State));
3801 /* basic FPU init */
3802 for(i = 0;i < 8; i++)
3803 env->fptags[i] = 1;
3804 env->fpuc = 0x37f;
9c605cb1
FB
3805 /* flags setup : we activate the IRQs by default as in user mode */
3806 env->eflags = 0x2 | IF_MASK;
dc99065b
FB
3807
3808 /* init various static tables */
3809 if (!inited) {
3810 inited = 1;
3811 optimize_flags_init();
3812 }
ba1c6e37
FB
3813 return env;
3814}
3815
3816void cpu_x86_close(CPUX86State *env)
3817{
3818 free(env);
3819}