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