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