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