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