]> git.proxmox.com Git - mirror_qemu.git/blame - target-i386/translate.c
labels support in dyngen
[mirror_qemu.git] / target-i386 / translate.c
CommitLineData
2c0262af
FB
1/*
2 * i386 translation
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
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.
10 *
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.
15 *
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
19 */
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25#include <signal.h>
26#include <assert.h>
2c0262af
FB
27
28#include "cpu.h"
29#include "exec-all.h"
30#include "disas.h"
31
32/* XXX: move that elsewhere */
33static uint16_t *gen_opc_ptr;
34static uint32_t *gen_opparam_ptr;
35
36#define PREFIX_REPZ 0x01
37#define PREFIX_REPNZ 0x02
38#define PREFIX_LOCK 0x04
39#define PREFIX_DATA 0x08
40#define PREFIX_ADR 0x10
41
42typedef struct DisasContext {
43 /* current insn context */
44 int override; /* -1 if no override */
45 int prefix;
46 int aflag, dflag;
47 uint8_t *pc; /* pc = eip + cs_base */
48 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
49 static state change (stop translation) */
50 /* current block context */
51 uint8_t *cs_base; /* base of CS segment */
52 int pe; /* protected mode */
53 int code32; /* 32 bit code segment */
54 int ss32; /* 32 bit stack segment */
55 int cc_op; /* current CC operation */
56 int addseg; /* non zero if either DS/ES/SS have a non zero base */
57 int f_st; /* currently unused */
58 int vm86; /* vm86 mode */
59 int cpl;
60 int iopl;
61 int tf; /* TF cpu flag */
34865134 62 int singlestep_enabled; /* "hardware" single step enabled */
2c0262af
FB
63 int jmp_opt; /* use direct block chaining for direct jumps */
64 int mem_index; /* select memory access functions */
7eee2a50 65 int flags; /* all execution flags */
2c0262af
FB
66 struct TranslationBlock *tb;
67 int popl_esp_hack; /* for correct popl with esp base handling */
68} DisasContext;
69
70static void gen_eob(DisasContext *s);
71static void gen_jmp(DisasContext *s, unsigned int eip);
72
73/* i386 arith/logic operations */
74enum {
75 OP_ADDL,
76 OP_ORL,
77 OP_ADCL,
78 OP_SBBL,
79 OP_ANDL,
80 OP_SUBL,
81 OP_XORL,
82 OP_CMPL,
83};
84
85/* i386 shift ops */
86enum {
87 OP_ROL,
88 OP_ROR,
89 OP_RCL,
90 OP_RCR,
91 OP_SHL,
92 OP_SHR,
93 OP_SHL1, /* undocumented */
94 OP_SAR = 7,
95};
96
97enum {
98#define DEF(s, n, copy_size) INDEX_op_ ## s,
99#include "opc.h"
100#undef DEF
101 NB_OPS,
102};
103
104#include "gen-op.h"
105
106/* operand size */
107enum {
108 OT_BYTE = 0,
109 OT_WORD,
110 OT_LONG,
111 OT_QUAD,
112};
113
114enum {
115 /* I386 int registers */
116 OR_EAX, /* MUST be even numbered */
117 OR_ECX,
118 OR_EDX,
119 OR_EBX,
120 OR_ESP,
121 OR_EBP,
122 OR_ESI,
123 OR_EDI,
124 OR_TMP0, /* temporary operand register */
125 OR_TMP1,
126 OR_A0, /* temporary register used when doing address evaluation */
127 OR_ZERO, /* fixed zero register */
128 NB_OREGS,
129};
130
2c0262af
FB
131static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
132 [OT_BYTE] = {
133 gen_op_movb_EAX_T0,
134 gen_op_movb_ECX_T0,
135 gen_op_movb_EDX_T0,
136 gen_op_movb_EBX_T0,
137 gen_op_movh_EAX_T0,
138 gen_op_movh_ECX_T0,
139 gen_op_movh_EDX_T0,
140 gen_op_movh_EBX_T0,
141 },
142 [OT_WORD] = {
143 gen_op_movw_EAX_T0,
144 gen_op_movw_ECX_T0,
145 gen_op_movw_EDX_T0,
146 gen_op_movw_EBX_T0,
147 gen_op_movw_ESP_T0,
148 gen_op_movw_EBP_T0,
149 gen_op_movw_ESI_T0,
150 gen_op_movw_EDI_T0,
151 },
152 [OT_LONG] = {
153 gen_op_movl_EAX_T0,
154 gen_op_movl_ECX_T0,
155 gen_op_movl_EDX_T0,
156 gen_op_movl_EBX_T0,
157 gen_op_movl_ESP_T0,
158 gen_op_movl_EBP_T0,
159 gen_op_movl_ESI_T0,
160 gen_op_movl_EDI_T0,
161 },
162};
163
164static GenOpFunc *gen_op_mov_reg_T1[3][8] = {
165 [OT_BYTE] = {
166 gen_op_movb_EAX_T1,
167 gen_op_movb_ECX_T1,
168 gen_op_movb_EDX_T1,
169 gen_op_movb_EBX_T1,
170 gen_op_movh_EAX_T1,
171 gen_op_movh_ECX_T1,
172 gen_op_movh_EDX_T1,
173 gen_op_movh_EBX_T1,
174 },
175 [OT_WORD] = {
176 gen_op_movw_EAX_T1,
177 gen_op_movw_ECX_T1,
178 gen_op_movw_EDX_T1,
179 gen_op_movw_EBX_T1,
180 gen_op_movw_ESP_T1,
181 gen_op_movw_EBP_T1,
182 gen_op_movw_ESI_T1,
183 gen_op_movw_EDI_T1,
184 },
185 [OT_LONG] = {
186 gen_op_movl_EAX_T1,
187 gen_op_movl_ECX_T1,
188 gen_op_movl_EDX_T1,
189 gen_op_movl_EBX_T1,
190 gen_op_movl_ESP_T1,
191 gen_op_movl_EBP_T1,
192 gen_op_movl_ESI_T1,
193 gen_op_movl_EDI_T1,
194 },
195};
196
197static GenOpFunc *gen_op_mov_reg_A0[2][8] = {
198 [0] = {
199 gen_op_movw_EAX_A0,
200 gen_op_movw_ECX_A0,
201 gen_op_movw_EDX_A0,
202 gen_op_movw_EBX_A0,
203 gen_op_movw_ESP_A0,
204 gen_op_movw_EBP_A0,
205 gen_op_movw_ESI_A0,
206 gen_op_movw_EDI_A0,
207 },
208 [1] = {
209 gen_op_movl_EAX_A0,
210 gen_op_movl_ECX_A0,
211 gen_op_movl_EDX_A0,
212 gen_op_movl_EBX_A0,
213 gen_op_movl_ESP_A0,
214 gen_op_movl_EBP_A0,
215 gen_op_movl_ESI_A0,
216 gen_op_movl_EDI_A0,
217 },
218};
219
220static GenOpFunc *gen_op_mov_TN_reg[3][2][8] =
221{
222 [OT_BYTE] = {
223 {
224 gen_op_movl_T0_EAX,
225 gen_op_movl_T0_ECX,
226 gen_op_movl_T0_EDX,
227 gen_op_movl_T0_EBX,
228 gen_op_movh_T0_EAX,
229 gen_op_movh_T0_ECX,
230 gen_op_movh_T0_EDX,
231 gen_op_movh_T0_EBX,
232 },
233 {
234 gen_op_movl_T1_EAX,
235 gen_op_movl_T1_ECX,
236 gen_op_movl_T1_EDX,
237 gen_op_movl_T1_EBX,
238 gen_op_movh_T1_EAX,
239 gen_op_movh_T1_ECX,
240 gen_op_movh_T1_EDX,
241 gen_op_movh_T1_EBX,
242 },
243 },
244 [OT_WORD] = {
245 {
246 gen_op_movl_T0_EAX,
247 gen_op_movl_T0_ECX,
248 gen_op_movl_T0_EDX,
249 gen_op_movl_T0_EBX,
250 gen_op_movl_T0_ESP,
251 gen_op_movl_T0_EBP,
252 gen_op_movl_T0_ESI,
253 gen_op_movl_T0_EDI,
254 },
255 {
256 gen_op_movl_T1_EAX,
257 gen_op_movl_T1_ECX,
258 gen_op_movl_T1_EDX,
259 gen_op_movl_T1_EBX,
260 gen_op_movl_T1_ESP,
261 gen_op_movl_T1_EBP,
262 gen_op_movl_T1_ESI,
263 gen_op_movl_T1_EDI,
264 },
265 },
266 [OT_LONG] = {
267 {
268 gen_op_movl_T0_EAX,
269 gen_op_movl_T0_ECX,
270 gen_op_movl_T0_EDX,
271 gen_op_movl_T0_EBX,
272 gen_op_movl_T0_ESP,
273 gen_op_movl_T0_EBP,
274 gen_op_movl_T0_ESI,
275 gen_op_movl_T0_EDI,
276 },
277 {
278 gen_op_movl_T1_EAX,
279 gen_op_movl_T1_ECX,
280 gen_op_movl_T1_EDX,
281 gen_op_movl_T1_EBX,
282 gen_op_movl_T1_ESP,
283 gen_op_movl_T1_EBP,
284 gen_op_movl_T1_ESI,
285 gen_op_movl_T1_EDI,
286 },
287 },
288};
289
290static GenOpFunc *gen_op_movl_A0_reg[8] = {
291 gen_op_movl_A0_EAX,
292 gen_op_movl_A0_ECX,
293 gen_op_movl_A0_EDX,
294 gen_op_movl_A0_EBX,
295 gen_op_movl_A0_ESP,
296 gen_op_movl_A0_EBP,
297 gen_op_movl_A0_ESI,
298 gen_op_movl_A0_EDI,
299};
300
301static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = {
302 [0] = {
303 gen_op_addl_A0_EAX,
304 gen_op_addl_A0_ECX,
305 gen_op_addl_A0_EDX,
306 gen_op_addl_A0_EBX,
307 gen_op_addl_A0_ESP,
308 gen_op_addl_A0_EBP,
309 gen_op_addl_A0_ESI,
310 gen_op_addl_A0_EDI,
311 },
312 [1] = {
313 gen_op_addl_A0_EAX_s1,
314 gen_op_addl_A0_ECX_s1,
315 gen_op_addl_A0_EDX_s1,
316 gen_op_addl_A0_EBX_s1,
317 gen_op_addl_A0_ESP_s1,
318 gen_op_addl_A0_EBP_s1,
319 gen_op_addl_A0_ESI_s1,
320 gen_op_addl_A0_EDI_s1,
321 },
322 [2] = {
323 gen_op_addl_A0_EAX_s2,
324 gen_op_addl_A0_ECX_s2,
325 gen_op_addl_A0_EDX_s2,
326 gen_op_addl_A0_EBX_s2,
327 gen_op_addl_A0_ESP_s2,
328 gen_op_addl_A0_EBP_s2,
329 gen_op_addl_A0_ESI_s2,
330 gen_op_addl_A0_EDI_s2,
331 },
332 [3] = {
333 gen_op_addl_A0_EAX_s3,
334 gen_op_addl_A0_ECX_s3,
335 gen_op_addl_A0_EDX_s3,
336 gen_op_addl_A0_EBX_s3,
337 gen_op_addl_A0_ESP_s3,
338 gen_op_addl_A0_EBP_s3,
339 gen_op_addl_A0_ESI_s3,
340 gen_op_addl_A0_EDI_s3,
341 },
342};
343
344static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = {
345 [0] = {
346 gen_op_cmovw_EAX_T1_T0,
347 gen_op_cmovw_ECX_T1_T0,
348 gen_op_cmovw_EDX_T1_T0,
349 gen_op_cmovw_EBX_T1_T0,
350 gen_op_cmovw_ESP_T1_T0,
351 gen_op_cmovw_EBP_T1_T0,
352 gen_op_cmovw_ESI_T1_T0,
353 gen_op_cmovw_EDI_T1_T0,
354 },
355 [1] = {
356 gen_op_cmovl_EAX_T1_T0,
357 gen_op_cmovl_ECX_T1_T0,
358 gen_op_cmovl_EDX_T1_T0,
359 gen_op_cmovl_EBX_T1_T0,
360 gen_op_cmovl_ESP_T1_T0,
361 gen_op_cmovl_EBP_T1_T0,
362 gen_op_cmovl_ESI_T1_T0,
363 gen_op_cmovl_EDI_T1_T0,
364 },
365};
366
367static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
368 NULL,
369 gen_op_orl_T0_T1,
370 NULL,
371 NULL,
372 gen_op_andl_T0_T1,
373 NULL,
374 gen_op_xorl_T0_T1,
375 NULL,
376};
377
4f31916f
FB
378#define DEF_ARITHC(SUFFIX)\
379 {\
380 gen_op_adcb ## SUFFIX ## _T0_T1_cc,\
381 gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\
382 },\
383 {\
384 gen_op_adcw ## SUFFIX ## _T0_T1_cc,\
385 gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\
386 },\
387 {\
388 gen_op_adcl ## SUFFIX ## _T0_T1_cc,\
389 gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\
2c0262af 390 },
4f31916f
FB
391
392static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
4bb2fcc7 393 DEF_ARITHC( )
2c0262af
FB
394};
395
4f31916f
FB
396static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[9][2] = {
397 DEF_ARITHC(_raw)
398#ifndef CONFIG_USER_ONLY
399 DEF_ARITHC(_kernel)
400 DEF_ARITHC(_user)
401#endif
2c0262af
FB
402};
403
404static const int cc_op_arithb[8] = {
405 CC_OP_ADDB,
406 CC_OP_LOGICB,
407 CC_OP_ADDB,
408 CC_OP_SUBB,
409 CC_OP_LOGICB,
410 CC_OP_SUBB,
411 CC_OP_LOGICB,
412 CC_OP_SUBB,
413};
414
4f31916f
FB
415#define DEF_CMPXCHG(SUFFIX)\
416 gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\
417 gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\
418 gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,
419
420
2c0262af 421static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
4bb2fcc7 422 DEF_CMPXCHG( )
2c0262af
FB
423};
424
4f31916f
FB
425static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[9] = {
426 DEF_CMPXCHG(_raw)
427#ifndef CONFIG_USER_ONLY
428 DEF_CMPXCHG(_kernel)
429 DEF_CMPXCHG(_user)
430#endif
2c0262af
FB
431};
432
4f31916f
FB
433#define DEF_SHIFT(SUFFIX)\
434 {\
435 gen_op_rolb ## SUFFIX ## _T0_T1_cc,\
436 gen_op_rorb ## SUFFIX ## _T0_T1_cc,\
437 gen_op_rclb ## SUFFIX ## _T0_T1_cc,\
438 gen_op_rcrb ## SUFFIX ## _T0_T1_cc,\
439 gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
440 gen_op_shrb ## SUFFIX ## _T0_T1_cc,\
441 gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
442 gen_op_sarb ## SUFFIX ## _T0_T1_cc,\
443 },\
444 {\
445 gen_op_rolw ## SUFFIX ## _T0_T1_cc,\
446 gen_op_rorw ## SUFFIX ## _T0_T1_cc,\
447 gen_op_rclw ## SUFFIX ## _T0_T1_cc,\
448 gen_op_rcrw ## SUFFIX ## _T0_T1_cc,\
449 gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
450 gen_op_shrw ## SUFFIX ## _T0_T1_cc,\
451 gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
452 gen_op_sarw ## SUFFIX ## _T0_T1_cc,\
453 },\
454 {\
455 gen_op_roll ## SUFFIX ## _T0_T1_cc,\
456 gen_op_rorl ## SUFFIX ## _T0_T1_cc,\
457 gen_op_rcll ## SUFFIX ## _T0_T1_cc,\
458 gen_op_rcrl ## SUFFIX ## _T0_T1_cc,\
459 gen_op_shll ## SUFFIX ## _T0_T1_cc,\
460 gen_op_shrl ## SUFFIX ## _T0_T1_cc,\
461 gen_op_shll ## SUFFIX ## _T0_T1_cc,\
462 gen_op_sarl ## SUFFIX ## _T0_T1_cc,\
2c0262af 463 },
4f31916f
FB
464
465static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
4bb2fcc7 466 DEF_SHIFT( )
2c0262af
FB
467};
468
4f31916f
FB
469static GenOpFunc *gen_op_shift_mem_T0_T1_cc[9][8] = {
470 DEF_SHIFT(_raw)
471#ifndef CONFIG_USER_ONLY
472 DEF_SHIFT(_kernel)
473 DEF_SHIFT(_user)
474#endif
2c0262af
FB
475};
476
4f31916f
FB
477#define DEF_SHIFTD(SUFFIX, op)\
478 {\
479 NULL,\
480 NULL,\
481 },\
482 {\
483 gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
484 gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
485 },\
486 {\
487 gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
488 gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
2c0262af 489 },
4f31916f
FB
490
491
492static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[3][2] = {
493 DEF_SHIFTD(, im)
2c0262af
FB
494};
495
4f31916f
FB
496static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[3][2] = {
497 DEF_SHIFTD(, ECX)
2c0262af
FB
498};
499
4f31916f
FB
500static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[9][2] = {
501 DEF_SHIFTD(_raw, im)
502#ifndef CONFIG_USER_ONLY
503 DEF_SHIFTD(_kernel, im)
504 DEF_SHIFTD(_user, im)
505#endif
2c0262af
FB
506};
507
4f31916f
FB
508static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[9][2] = {
509 DEF_SHIFTD(_raw, ECX)
510#ifndef CONFIG_USER_ONLY
511 DEF_SHIFTD(_kernel, ECX)
512 DEF_SHIFTD(_user, ECX)
513#endif
2c0262af
FB
514};
515
516static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
517 [0] = {
518 gen_op_btw_T0_T1_cc,
519 gen_op_btsw_T0_T1_cc,
520 gen_op_btrw_T0_T1_cc,
521 gen_op_btcw_T0_T1_cc,
522 },
523 [1] = {
524 gen_op_btl_T0_T1_cc,
525 gen_op_btsl_T0_T1_cc,
526 gen_op_btrl_T0_T1_cc,
527 gen_op_btcl_T0_T1_cc,
528 },
529};
530
531static GenOpFunc *gen_op_bsx_T0_cc[2][2] = {
532 [0] = {
533 gen_op_bsfw_T0_cc,
534 gen_op_bsrw_T0_cc,
535 },
536 [1] = {
537 gen_op_bsfl_T0_cc,
538 gen_op_bsrl_T0_cc,
539 },
540};
541
542static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = {
61382a50
FB
543 gen_op_ldsb_raw_T0_A0,
544 gen_op_ldsw_raw_T0_A0,
2c0262af 545 NULL,
61382a50 546#ifndef CONFIG_USER_ONLY
2c0262af
FB
547 gen_op_ldsb_kernel_T0_A0,
548 gen_op_ldsw_kernel_T0_A0,
549 NULL,
550
551 gen_op_ldsb_user_T0_A0,
552 gen_op_ldsw_user_T0_A0,
553 NULL,
61382a50 554#endif
2c0262af
FB
555};
556
557static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = {
61382a50
FB
558 gen_op_ldub_raw_T0_A0,
559 gen_op_lduw_raw_T0_A0,
2c0262af
FB
560 NULL,
561
61382a50 562#ifndef CONFIG_USER_ONLY
2c0262af
FB
563 gen_op_ldub_kernel_T0_A0,
564 gen_op_lduw_kernel_T0_A0,
565 NULL,
566
567 gen_op_ldub_user_T0_A0,
568 gen_op_lduw_user_T0_A0,
569 NULL,
61382a50 570#endif
2c0262af
FB
571};
572
573/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */
574static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = {
61382a50
FB
575 gen_op_ldub_raw_T0_A0,
576 gen_op_lduw_raw_T0_A0,
577 gen_op_ldl_raw_T0_A0,
2c0262af 578
61382a50 579#ifndef CONFIG_USER_ONLY
2c0262af
FB
580 gen_op_ldub_kernel_T0_A0,
581 gen_op_lduw_kernel_T0_A0,
582 gen_op_ldl_kernel_T0_A0,
583
584 gen_op_ldub_user_T0_A0,
585 gen_op_lduw_user_T0_A0,
586 gen_op_ldl_user_T0_A0,
61382a50 587#endif
2c0262af
FB
588};
589
590static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = {
61382a50
FB
591 gen_op_ldub_raw_T1_A0,
592 gen_op_lduw_raw_T1_A0,
593 gen_op_ldl_raw_T1_A0,
2c0262af 594
61382a50 595#ifndef CONFIG_USER_ONLY
2c0262af
FB
596 gen_op_ldub_kernel_T1_A0,
597 gen_op_lduw_kernel_T1_A0,
598 gen_op_ldl_kernel_T1_A0,
599
600 gen_op_ldub_user_T1_A0,
601 gen_op_lduw_user_T1_A0,
602 gen_op_ldl_user_T1_A0,
61382a50 603#endif
2c0262af
FB
604};
605
606static GenOpFunc *gen_op_st_T0_A0[3 * 3] = {
61382a50
FB
607 gen_op_stb_raw_T0_A0,
608 gen_op_stw_raw_T0_A0,
609 gen_op_stl_raw_T0_A0,
2c0262af 610
61382a50 611#ifndef CONFIG_USER_ONLY
2c0262af
FB
612 gen_op_stb_kernel_T0_A0,
613 gen_op_stw_kernel_T0_A0,
614 gen_op_stl_kernel_T0_A0,
615
616 gen_op_stb_user_T0_A0,
617 gen_op_stw_user_T0_A0,
618 gen_op_stl_user_T0_A0,
61382a50 619#endif
2c0262af
FB
620};
621
4f31916f
FB
622static GenOpFunc *gen_op_st_T1_A0[3 * 3] = {
623 NULL,
624 gen_op_stw_raw_T1_A0,
625 gen_op_stl_raw_T1_A0,
626
627#ifndef CONFIG_USER_ONLY
628 NULL,
629 gen_op_stw_kernel_T1_A0,
630 gen_op_stl_kernel_T1_A0,
631
632 NULL,
633 gen_op_stw_user_T1_A0,
634 gen_op_stl_user_T1_A0,
635#endif
636};
637
2c0262af
FB
638static inline void gen_string_movl_A0_ESI(DisasContext *s)
639{
640 int override;
641
642 override = s->override;
643 if (s->aflag) {
644 /* 32 bit address */
645 if (s->addseg && override < 0)
646 override = R_DS;
647 if (override >= 0) {
648 gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
649 gen_op_addl_A0_reg_sN[0][R_ESI]();
650 } else {
651 gen_op_movl_A0_reg[R_ESI]();
652 }
653 } else {
654 /* 16 address, always override */
655 if (override < 0)
656 override = R_DS;
657 gen_op_movl_A0_reg[R_ESI]();
658 gen_op_andl_A0_ffff();
659 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
660 }
661}
662
663static inline void gen_string_movl_A0_EDI(DisasContext *s)
664{
665 if (s->aflag) {
666 if (s->addseg) {
667 gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base));
668 gen_op_addl_A0_reg_sN[0][R_EDI]();
669 } else {
670 gen_op_movl_A0_reg[R_EDI]();
671 }
672 } else {
673 gen_op_movl_A0_reg[R_EDI]();
674 gen_op_andl_A0_ffff();
675 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base));
676 }
677}
678
679static GenOpFunc *gen_op_movl_T0_Dshift[3] = {
680 gen_op_movl_T0_Dshiftb,
681 gen_op_movl_T0_Dshiftw,
682 gen_op_movl_T0_Dshiftl,
683};
684
685static GenOpFunc2 *gen_op_jz_ecx[2] = {
686 gen_op_jz_ecxw,
687 gen_op_jz_ecxl,
688};
689
690static GenOpFunc1 *gen_op_jz_ecx_im[2] = {
691 gen_op_jz_ecxw_im,
692 gen_op_jz_ecxl_im,
693};
694
695static GenOpFunc *gen_op_dec_ECX[2] = {
696 gen_op_decw_ECX,
697 gen_op_decl_ECX,
698};
699
7399c5a9
FB
700#ifdef USE_DIRECT_JUMP
701typedef GenOpFunc GenOpFuncTB2;
702#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot]()
703#else
704typedef GenOpFunc1 GenOpFuncTB2;
705#define gen_op_string_jnz_sub(nz, ot, tb) gen_op_string_jnz_sub2[nz][ot](tb)
706#endif
707
708static GenOpFuncTB2 *gen_op_string_jnz_sub2[2][3] = {
2c0262af
FB
709 {
710 gen_op_string_jnz_subb,
711 gen_op_string_jnz_subw,
712 gen_op_string_jnz_subl,
713 },
714 {
715 gen_op_string_jz_subb,
716 gen_op_string_jz_subw,
717 gen_op_string_jz_subl,
718 },
719};
720
721static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = {
722 {
723 gen_op_string_jnz_subb_im,
724 gen_op_string_jnz_subw_im,
725 gen_op_string_jnz_subl_im,
726 },
727 {
728 gen_op_string_jz_subb_im,
729 gen_op_string_jz_subw_im,
730 gen_op_string_jz_subl_im,
731 },
732};
733
734static GenOpFunc *gen_op_in_DX_T0[3] = {
735 gen_op_inb_DX_T0,
736 gen_op_inw_DX_T0,
737 gen_op_inl_DX_T0,
738};
739
740static GenOpFunc *gen_op_out_DX_T0[3] = {
741 gen_op_outb_DX_T0,
742 gen_op_outw_DX_T0,
743 gen_op_outl_DX_T0,
744};
745
f115e911
FB
746static GenOpFunc *gen_op_in[3] = {
747 gen_op_inb_T0_T1,
748 gen_op_inw_T0_T1,
749 gen_op_inl_T0_T1,
750};
751
752static GenOpFunc *gen_op_out[3] = {
753 gen_op_outb_T0_T1,
754 gen_op_outw_T0_T1,
755 gen_op_outl_T0_T1,
756};
757
758static GenOpFunc *gen_check_io_T0[3] = {
759 gen_op_check_iob_T0,
760 gen_op_check_iow_T0,
761 gen_op_check_iol_T0,
762};
763
764static GenOpFunc *gen_check_io_DX[3] = {
765 gen_op_check_iob_DX,
766 gen_op_check_iow_DX,
767 gen_op_check_iol_DX,
768};
769
770static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip)
771{
772 if (s->pe && (s->cpl > s->iopl || s->vm86)) {
773 if (s->cc_op != CC_OP_DYNAMIC)
774 gen_op_set_cc_op(s->cc_op);
775 gen_op_jmp_im(cur_eip);
776 if (use_dx)
777 gen_check_io_DX[ot]();
778 else
779 gen_check_io_T0[ot]();
780 }
781}
782
2c0262af
FB
783static inline void gen_movs(DisasContext *s, int ot)
784{
785 gen_string_movl_A0_ESI(s);
786 gen_op_ld_T0_A0[ot + s->mem_index]();
787 gen_string_movl_A0_EDI(s);
788 gen_op_st_T0_A0[ot + s->mem_index]();
789 gen_op_movl_T0_Dshift[ot]();
790 if (s->aflag) {
791 gen_op_addl_ESI_T0();
792 gen_op_addl_EDI_T0();
793 } else {
794 gen_op_addw_ESI_T0();
795 gen_op_addw_EDI_T0();
796 }
797}
798
799static inline void gen_update_cc_op(DisasContext *s)
800{
801 if (s->cc_op != CC_OP_DYNAMIC) {
802 gen_op_set_cc_op(s->cc_op);
803 s->cc_op = CC_OP_DYNAMIC;
804 }
805}
806
807static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip)
808{
809 if (s->jmp_opt) {
810 gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip);
811 } else {
812 /* XXX: does not work with gdbstub "ice" single step - not a
813 serious problem */
814 gen_op_jz_ecx_im[s->aflag](next_eip);
815 }
816}
817
818static inline void gen_stos(DisasContext *s, int ot)
819{
820 gen_op_mov_TN_reg[OT_LONG][0][R_EAX]();
821 gen_string_movl_A0_EDI(s);
822 gen_op_st_T0_A0[ot + s->mem_index]();
823 gen_op_movl_T0_Dshift[ot]();
824 if (s->aflag) {
825 gen_op_addl_EDI_T0();
826 } else {
827 gen_op_addw_EDI_T0();
828 }
829}
830
831static inline void gen_lods(DisasContext *s, int ot)
832{
833 gen_string_movl_A0_ESI(s);
834 gen_op_ld_T0_A0[ot + s->mem_index]();
835 gen_op_mov_reg_T0[ot][R_EAX]();
836 gen_op_movl_T0_Dshift[ot]();
837 if (s->aflag) {
838 gen_op_addl_ESI_T0();
839 } else {
840 gen_op_addw_ESI_T0();
841 }
842}
843
844static inline void gen_scas(DisasContext *s, int ot)
845{
846 gen_op_mov_TN_reg[OT_LONG][0][R_EAX]();
847 gen_string_movl_A0_EDI(s);
848 gen_op_ld_T1_A0[ot + s->mem_index]();
849 gen_op_cmpl_T0_T1_cc();
850 gen_op_movl_T0_Dshift[ot]();
851 if (s->aflag) {
852 gen_op_addl_EDI_T0();
853 } else {
854 gen_op_addw_EDI_T0();
855 }
856}
857
858static inline void gen_cmps(DisasContext *s, int ot)
859{
860 gen_string_movl_A0_ESI(s);
861 gen_op_ld_T0_A0[ot + s->mem_index]();
862 gen_string_movl_A0_EDI(s);
863 gen_op_ld_T1_A0[ot + s->mem_index]();
864 gen_op_cmpl_T0_T1_cc();
865 gen_op_movl_T0_Dshift[ot]();
866 if (s->aflag) {
867 gen_op_addl_ESI_T0();
868 gen_op_addl_EDI_T0();
869 } else {
870 gen_op_addw_ESI_T0();
871 gen_op_addw_EDI_T0();
872 }
873}
874
875static inline void gen_ins(DisasContext *s, int ot)
876{
2c0262af 877 gen_string_movl_A0_EDI(s);
9772c73b
FB
878 gen_op_movl_T0_0();
879 gen_op_st_T0_A0[ot + s->mem_index]();
880 gen_op_in_DX_T0[ot]();
2c0262af
FB
881 gen_op_st_T0_A0[ot + s->mem_index]();
882 gen_op_movl_T0_Dshift[ot]();
883 if (s->aflag) {
884 gen_op_addl_EDI_T0();
885 } else {
886 gen_op_addw_EDI_T0();
887 }
888}
889
890static inline void gen_outs(DisasContext *s, int ot)
891{
892 gen_string_movl_A0_ESI(s);
893 gen_op_ld_T0_A0[ot + s->mem_index]();
894 gen_op_out_DX_T0[ot]();
895 gen_op_movl_T0_Dshift[ot]();
896 if (s->aflag) {
897 gen_op_addl_ESI_T0();
898 } else {
899 gen_op_addw_ESI_T0();
900 }
901}
902
903/* same method as Valgrind : we generate jumps to current or next
904 instruction */
905#define GEN_REPZ(op) \
906static inline void gen_repz_ ## op(DisasContext *s, int ot, \
907 unsigned int cur_eip, unsigned int next_eip) \
908{ \
909 gen_update_cc_op(s); \
910 gen_jz_ecx_string(s, next_eip); \
911 gen_ ## op(s, ot); \
912 gen_op_dec_ECX[s->aflag](); \
913 /* a loop would cause two single step exceptions if ECX = 1 \
914 before rep string_insn */ \
915 if (!s->jmp_opt) \
916 gen_op_jz_ecx_im[s->aflag](next_eip); \
917 gen_jmp(s, cur_eip); \
918}
919
920#define GEN_REPZ2(op) \
921static inline void gen_repz_ ## op(DisasContext *s, int ot, \
922 unsigned int cur_eip, \
923 unsigned int next_eip, \
924 int nz) \
925{ \
926 gen_update_cc_op(s); \
927 gen_jz_ecx_string(s, next_eip); \
928 gen_ ## op(s, ot); \
929 gen_op_dec_ECX[s->aflag](); \
930 gen_op_set_cc_op(CC_OP_SUBB + ot); \
931 if (!s->jmp_opt) \
932 gen_op_string_jnz_sub_im[nz][ot](next_eip); \
933 else \
7399c5a9 934 gen_op_string_jnz_sub(nz, ot, (long)s->tb); \
2c0262af
FB
935 if (!s->jmp_opt) \
936 gen_op_jz_ecx_im[s->aflag](next_eip); \
937 gen_jmp(s, cur_eip); \
938}
939
940GEN_REPZ(movs)
941GEN_REPZ(stos)
942GEN_REPZ(lods)
943GEN_REPZ(ins)
944GEN_REPZ(outs)
945GEN_REPZ2(scas)
946GEN_REPZ2(cmps)
947
2c0262af
FB
948enum {
949 JCC_O,
950 JCC_B,
951 JCC_Z,
952 JCC_BE,
953 JCC_S,
954 JCC_P,
955 JCC_L,
956 JCC_LE,
957};
958
959static GenOpFunc3 *gen_jcc_sub[3][8] = {
960 [OT_BYTE] = {
961 NULL,
962 gen_op_jb_subb,
963 gen_op_jz_subb,
964 gen_op_jbe_subb,
965 gen_op_js_subb,
966 NULL,
967 gen_op_jl_subb,
968 gen_op_jle_subb,
969 },
970 [OT_WORD] = {
971 NULL,
972 gen_op_jb_subw,
973 gen_op_jz_subw,
974 gen_op_jbe_subw,
975 gen_op_js_subw,
976 NULL,
977 gen_op_jl_subw,
978 gen_op_jle_subw,
979 },
980 [OT_LONG] = {
981 NULL,
982 gen_op_jb_subl,
983 gen_op_jz_subl,
984 gen_op_jbe_subl,
985 gen_op_js_subl,
986 NULL,
987 gen_op_jl_subl,
988 gen_op_jle_subl,
989 },
990};
991static GenOpFunc2 *gen_op_loop[2][4] = {
992 [0] = {
993 gen_op_loopnzw,
994 gen_op_loopzw,
995 gen_op_loopw,
996 gen_op_jecxzw,
997 },
998 [1] = {
999 gen_op_loopnzl,
1000 gen_op_loopzl,
1001 gen_op_loopl,
1002 gen_op_jecxzl,
1003 },
1004};
1005
1006static GenOpFunc *gen_setcc_slow[8] = {
1007 gen_op_seto_T0_cc,
1008 gen_op_setb_T0_cc,
1009 gen_op_setz_T0_cc,
1010 gen_op_setbe_T0_cc,
1011 gen_op_sets_T0_cc,
1012 gen_op_setp_T0_cc,
1013 gen_op_setl_T0_cc,
1014 gen_op_setle_T0_cc,
1015};
1016
1017static GenOpFunc *gen_setcc_sub[3][8] = {
1018 [OT_BYTE] = {
1019 NULL,
1020 gen_op_setb_T0_subb,
1021 gen_op_setz_T0_subb,
1022 gen_op_setbe_T0_subb,
1023 gen_op_sets_T0_subb,
1024 NULL,
1025 gen_op_setl_T0_subb,
1026 gen_op_setle_T0_subb,
1027 },
1028 [OT_WORD] = {
1029 NULL,
1030 gen_op_setb_T0_subw,
1031 gen_op_setz_T0_subw,
1032 gen_op_setbe_T0_subw,
1033 gen_op_sets_T0_subw,
1034 NULL,
1035 gen_op_setl_T0_subw,
1036 gen_op_setle_T0_subw,
1037 },
1038 [OT_LONG] = {
1039 NULL,
1040 gen_op_setb_T0_subl,
1041 gen_op_setz_T0_subl,
1042 gen_op_setbe_T0_subl,
1043 gen_op_sets_T0_subl,
1044 NULL,
1045 gen_op_setl_T0_subl,
1046 gen_op_setle_T0_subl,
1047 },
1048};
1049
1050static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = {
1051 gen_op_fadd_ST0_FT0,
1052 gen_op_fmul_ST0_FT0,
1053 gen_op_fcom_ST0_FT0,
1054 gen_op_fcom_ST0_FT0,
1055 gen_op_fsub_ST0_FT0,
1056 gen_op_fsubr_ST0_FT0,
1057 gen_op_fdiv_ST0_FT0,
1058 gen_op_fdivr_ST0_FT0,
1059};
1060
1061/* NOTE the exception in "r" op ordering */
1062static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
1063 gen_op_fadd_STN_ST0,
1064 gen_op_fmul_STN_ST0,
1065 NULL,
1066 NULL,
1067 gen_op_fsubr_STN_ST0,
1068 gen_op_fsub_STN_ST0,
1069 gen_op_fdivr_STN_ST0,
1070 gen_op_fdiv_STN_ST0,
1071};
1072
1073/* if d == OR_TMP0, it means memory operand (address in A0) */
1074static void gen_op(DisasContext *s1, int op, int ot, int d)
1075{
1076 GenOpFunc *gen_update_cc;
1077
1078 if (d != OR_TMP0) {
1079 gen_op_mov_TN_reg[ot][0][d]();
1080 } else {
1081 gen_op_ld_T0_A0[ot + s1->mem_index]();
1082 }
1083 switch(op) {
1084 case OP_ADCL:
1085 case OP_SBBL:
1086 if (s1->cc_op != CC_OP_DYNAMIC)
1087 gen_op_set_cc_op(s1->cc_op);
1088 if (d != OR_TMP0) {
1089 gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
1090 gen_op_mov_reg_T0[ot][d]();
1091 } else {
4f31916f 1092 gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL]();
2c0262af
FB
1093 }
1094 s1->cc_op = CC_OP_DYNAMIC;
1095 goto the_end;
1096 case OP_ADDL:
1097 gen_op_addl_T0_T1();
1098 s1->cc_op = CC_OP_ADDB + ot;
1099 gen_update_cc = gen_op_update2_cc;
1100 break;
1101 case OP_SUBL:
1102 gen_op_subl_T0_T1();
1103 s1->cc_op = CC_OP_SUBB + ot;
1104 gen_update_cc = gen_op_update2_cc;
1105 break;
1106 default:
1107 case OP_ANDL:
1108 case OP_ORL:
1109 case OP_XORL:
1110 gen_op_arith_T0_T1_cc[op]();
1111 s1->cc_op = CC_OP_LOGICB + ot;
1112 gen_update_cc = gen_op_update1_cc;
1113 break;
1114 case OP_CMPL:
1115 gen_op_cmpl_T0_T1_cc();
1116 s1->cc_op = CC_OP_SUBB + ot;
1117 gen_update_cc = NULL;
1118 break;
1119 }
1120 if (op != OP_CMPL) {
1121 if (d != OR_TMP0)
1122 gen_op_mov_reg_T0[ot][d]();
1123 else
1124 gen_op_st_T0_A0[ot + s1->mem_index]();
1125 }
1126 /* the flags update must happen after the memory write (precise
1127 exception support) */
1128 if (gen_update_cc)
1129 gen_update_cc();
1130 the_end: ;
1131}
1132
1133/* if d == OR_TMP0, it means memory operand (address in A0) */
1134static void gen_inc(DisasContext *s1, int ot, int d, int c)
1135{
1136 if (d != OR_TMP0)
1137 gen_op_mov_TN_reg[ot][0][d]();
1138 else
1139 gen_op_ld_T0_A0[ot + s1->mem_index]();
1140 if (s1->cc_op != CC_OP_DYNAMIC)
1141 gen_op_set_cc_op(s1->cc_op);
1142 if (c > 0) {
1143 gen_op_incl_T0();
1144 s1->cc_op = CC_OP_INCB + ot;
1145 } else {
1146 gen_op_decl_T0();
1147 s1->cc_op = CC_OP_DECB + ot;
1148 }
1149 if (d != OR_TMP0)
1150 gen_op_mov_reg_T0[ot][d]();
1151 else
1152 gen_op_st_T0_A0[ot + s1->mem_index]();
1153 gen_op_update_inc_cc();
1154}
1155
1156static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
1157{
1158 if (d != OR_TMP0)
1159 gen_op_mov_TN_reg[ot][0][d]();
1160 else
1161 gen_op_ld_T0_A0[ot + s1->mem_index]();
1162 if (s != OR_TMP1)
1163 gen_op_mov_TN_reg[ot][1][s]();
1164 /* for zero counts, flags are not updated, so must do it dynamically */
1165 if (s1->cc_op != CC_OP_DYNAMIC)
1166 gen_op_set_cc_op(s1->cc_op);
1167
1168 if (d != OR_TMP0)
1169 gen_op_shift_T0_T1_cc[ot][op]();
1170 else
4f31916f 1171 gen_op_shift_mem_T0_T1_cc[ot + s1->mem_index][op]();
2c0262af
FB
1172 if (d != OR_TMP0)
1173 gen_op_mov_reg_T0[ot][d]();
1174 s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
1175}
1176
1177static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
1178{
1179 /* currently not optimized */
1180 gen_op_movl_T1_im(c);
1181 gen_shift(s1, op, ot, d, OR_TMP1);
1182}
1183
1184static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
1185{
1186 int havesib;
1187 int base, disp;
1188 int index;
1189 int scale;
1190 int opreg;
1191 int mod, rm, code, override, must_add_seg;
1192
1193 override = s->override;
1194 must_add_seg = s->addseg;
1195 if (override >= 0)
1196 must_add_seg = 1;
1197 mod = (modrm >> 6) & 3;
1198 rm = modrm & 7;
1199
1200 if (s->aflag) {
1201
1202 havesib = 0;
1203 base = rm;
1204 index = 0;
1205 scale = 0;
1206
1207 if (base == 4) {
1208 havesib = 1;
61382a50 1209 code = ldub_code(s->pc++);
2c0262af
FB
1210 scale = (code >> 6) & 3;
1211 index = (code >> 3) & 7;
1212 base = code & 7;
1213 }
1214
1215 switch (mod) {
1216 case 0:
1217 if (base == 5) {
1218 base = -1;
61382a50 1219 disp = ldl_code(s->pc);
2c0262af
FB
1220 s->pc += 4;
1221 } else {
1222 disp = 0;
1223 }
1224 break;
1225 case 1:
61382a50 1226 disp = (int8_t)ldub_code(s->pc++);
2c0262af
FB
1227 break;
1228 default:
1229 case 2:
61382a50 1230 disp = ldl_code(s->pc);
2c0262af
FB
1231 s->pc += 4;
1232 break;
1233 }
1234
1235 if (base >= 0) {
1236 /* for correct popl handling with esp */
1237 if (base == 4 && s->popl_esp_hack)
1238 disp += s->popl_esp_hack;
1239 gen_op_movl_A0_reg[base]();
1240 if (disp != 0)
1241 gen_op_addl_A0_im(disp);
1242 } else {
1243 gen_op_movl_A0_im(disp);
1244 }
1245 /* XXX: index == 4 is always invalid */
1246 if (havesib && (index != 4 || scale != 0)) {
1247 gen_op_addl_A0_reg_sN[scale][index]();
1248 }
1249 if (must_add_seg) {
1250 if (override < 0) {
1251 if (base == R_EBP || base == R_ESP)
1252 override = R_SS;
1253 else
1254 override = R_DS;
1255 }
1256 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
1257 }
1258 } else {
1259 switch (mod) {
1260 case 0:
1261 if (rm == 6) {
61382a50 1262 disp = lduw_code(s->pc);
2c0262af
FB
1263 s->pc += 2;
1264 gen_op_movl_A0_im(disp);
1265 rm = 0; /* avoid SS override */
1266 goto no_rm;
1267 } else {
1268 disp = 0;
1269 }
1270 break;
1271 case 1:
61382a50 1272 disp = (int8_t)ldub_code(s->pc++);
2c0262af
FB
1273 break;
1274 default:
1275 case 2:
61382a50 1276 disp = lduw_code(s->pc);
2c0262af
FB
1277 s->pc += 2;
1278 break;
1279 }
1280 switch(rm) {
1281 case 0:
1282 gen_op_movl_A0_reg[R_EBX]();
1283 gen_op_addl_A0_reg_sN[0][R_ESI]();
1284 break;
1285 case 1:
1286 gen_op_movl_A0_reg[R_EBX]();
1287 gen_op_addl_A0_reg_sN[0][R_EDI]();
1288 break;
1289 case 2:
1290 gen_op_movl_A0_reg[R_EBP]();
1291 gen_op_addl_A0_reg_sN[0][R_ESI]();
1292 break;
1293 case 3:
1294 gen_op_movl_A0_reg[R_EBP]();
1295 gen_op_addl_A0_reg_sN[0][R_EDI]();
1296 break;
1297 case 4:
1298 gen_op_movl_A0_reg[R_ESI]();
1299 break;
1300 case 5:
1301 gen_op_movl_A0_reg[R_EDI]();
1302 break;
1303 case 6:
1304 gen_op_movl_A0_reg[R_EBP]();
1305 break;
1306 default:
1307 case 7:
1308 gen_op_movl_A0_reg[R_EBX]();
1309 break;
1310 }
1311 if (disp != 0)
1312 gen_op_addl_A0_im(disp);
1313 gen_op_andl_A0_ffff();
1314 no_rm:
1315 if (must_add_seg) {
1316 if (override < 0) {
1317 if (rm == 2 || rm == 3 || rm == 6)
1318 override = R_SS;
1319 else
1320 override = R_DS;
1321 }
1322 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
1323 }
1324 }
1325
1326 opreg = OR_A0;
1327 disp = 0;
1328 *reg_ptr = opreg;
1329 *offset_ptr = disp;
1330}
1331
1332/* generate modrm memory load or store of 'reg'. TMP0 is used if reg !=
1333 OR_TMP0 */
1334static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
1335{
1336 int mod, rm, opreg, disp;
1337
1338 mod = (modrm >> 6) & 3;
1339 rm = modrm & 7;
1340 if (mod == 3) {
1341 if (is_store) {
1342 if (reg != OR_TMP0)
1343 gen_op_mov_TN_reg[ot][0][reg]();
1344 gen_op_mov_reg_T0[ot][rm]();
1345 } else {
1346 gen_op_mov_TN_reg[ot][0][rm]();
1347 if (reg != OR_TMP0)
1348 gen_op_mov_reg_T0[ot][reg]();
1349 }
1350 } else {
1351 gen_lea_modrm(s, modrm, &opreg, &disp);
1352 if (is_store) {
1353 if (reg != OR_TMP0)
1354 gen_op_mov_TN_reg[ot][0][reg]();
1355 gen_op_st_T0_A0[ot + s->mem_index]();
1356 } else {
1357 gen_op_ld_T0_A0[ot + s->mem_index]();
1358 if (reg != OR_TMP0)
1359 gen_op_mov_reg_T0[ot][reg]();
1360 }
1361 }
1362}
1363
1364static inline uint32_t insn_get(DisasContext *s, int ot)
1365{
1366 uint32_t ret;
1367
1368 switch(ot) {
1369 case OT_BYTE:
61382a50 1370 ret = ldub_code(s->pc);
2c0262af
FB
1371 s->pc++;
1372 break;
1373 case OT_WORD:
61382a50 1374 ret = lduw_code(s->pc);
2c0262af
FB
1375 s->pc += 2;
1376 break;
1377 default:
1378 case OT_LONG:
61382a50 1379 ret = ldl_code(s->pc);
2c0262af
FB
1380 s->pc += 4;
1381 break;
1382 }
1383 return ret;
1384}
1385
1386static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
1387{
1388 TranslationBlock *tb;
1389 int inv, jcc_op;
1390 GenOpFunc3 *func;
1391
1392 inv = b & 1;
1393 jcc_op = (b >> 1) & 7;
1394
1395 if (s->jmp_opt) {
1396 switch(s->cc_op) {
1397 /* we optimize the cmp/jcc case */
1398 case CC_OP_SUBB:
1399 case CC_OP_SUBW:
1400 case CC_OP_SUBL:
1401 func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
1402 break;
1403
1404 /* some jumps are easy to compute */
1405 case CC_OP_ADDB:
1406 case CC_OP_ADDW:
1407 case CC_OP_ADDL:
1408 case CC_OP_ADCB:
1409 case CC_OP_ADCW:
1410 case CC_OP_ADCL:
1411 case CC_OP_SBBB:
1412 case CC_OP_SBBW:
1413 case CC_OP_SBBL:
1414 case CC_OP_LOGICB:
1415 case CC_OP_LOGICW:
1416 case CC_OP_LOGICL:
1417 case CC_OP_INCB:
1418 case CC_OP_INCW:
1419 case CC_OP_INCL:
1420 case CC_OP_DECB:
1421 case CC_OP_DECW:
1422 case CC_OP_DECL:
1423 case CC_OP_SHLB:
1424 case CC_OP_SHLW:
1425 case CC_OP_SHLL:
1426 case CC_OP_SARB:
1427 case CC_OP_SARW:
1428 case CC_OP_SARL:
1429 switch(jcc_op) {
1430 case JCC_Z:
1431 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1432 break;
1433 case JCC_S:
1434 func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1435 break;
1436 default:
1437 func = NULL;
1438 break;
1439 }
1440 break;
1441 default:
1442 func = NULL;
1443 break;
1444 }
1445
1446 if (s->cc_op != CC_OP_DYNAMIC)
1447 gen_op_set_cc_op(s->cc_op);
1448
1449 if (!func) {
1450 gen_setcc_slow[jcc_op]();
1451 func = gen_op_jcc;
1452 }
1453
1454 tb = s->tb;
1455 if (!inv) {
1456 func((long)tb, val, next_eip);
1457 } else {
1458 func((long)tb, next_eip, val);
1459 }
1460 s->is_jmp = 3;
1461 } else {
1462 if (s->cc_op != CC_OP_DYNAMIC) {
1463 gen_op_set_cc_op(s->cc_op);
1464 s->cc_op = CC_OP_DYNAMIC;
1465 }
1466 gen_setcc_slow[jcc_op]();
1467 if (!inv) {
1468 gen_op_jcc_im(val, next_eip);
1469 } else {
1470 gen_op_jcc_im(next_eip, val);
1471 }
1472 gen_eob(s);
1473 }
1474}
1475
1476static void gen_setcc(DisasContext *s, int b)
1477{
1478 int inv, jcc_op;
1479 GenOpFunc *func;
1480
1481 inv = b & 1;
1482 jcc_op = (b >> 1) & 7;
1483 switch(s->cc_op) {
1484 /* we optimize the cmp/jcc case */
1485 case CC_OP_SUBB:
1486 case CC_OP_SUBW:
1487 case CC_OP_SUBL:
1488 func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
1489 if (!func)
1490 goto slow_jcc;
1491 break;
1492
1493 /* some jumps are easy to compute */
1494 case CC_OP_ADDB:
1495 case CC_OP_ADDW:
1496 case CC_OP_ADDL:
1497 case CC_OP_LOGICB:
1498 case CC_OP_LOGICW:
1499 case CC_OP_LOGICL:
1500 case CC_OP_INCB:
1501 case CC_OP_INCW:
1502 case CC_OP_INCL:
1503 case CC_OP_DECB:
1504 case CC_OP_DECW:
1505 case CC_OP_DECL:
1506 case CC_OP_SHLB:
1507 case CC_OP_SHLW:
1508 case CC_OP_SHLL:
1509 switch(jcc_op) {
1510 case JCC_Z:
1511 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1512 break;
1513 case JCC_S:
1514 func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
1515 break;
1516 default:
1517 goto slow_jcc;
1518 }
1519 break;
1520 default:
1521 slow_jcc:
1522 if (s->cc_op != CC_OP_DYNAMIC)
1523 gen_op_set_cc_op(s->cc_op);
1524 func = gen_setcc_slow[jcc_op];
1525 break;
1526 }
1527 func();
1528 if (inv) {
1529 gen_op_xor_T0_1();
1530 }
1531}
1532
1533/* move T0 to seg_reg and compute if the CPU state may change. Never
1534 call this function with seg_reg == R_CS */
1535static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
1536{
3415a4dd
FB
1537 if (s->pe && !s->vm86) {
1538 /* XXX: optimize by finding processor state dynamically */
1539 if (s->cc_op != CC_OP_DYNAMIC)
1540 gen_op_set_cc_op(s->cc_op);
1541 gen_op_jmp_im(cur_eip);
1542 gen_op_movl_seg_T0(seg_reg);
dc196a57
FB
1543 /* abort translation because the addseg value may change or
1544 because ss32 may change. For R_SS, translation must always
1545 stop as a special handling must be done to disable hardware
1546 interrupts for the next instruction */
1547 if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
1548 s->is_jmp = 3;
3415a4dd 1549 } else {
2c0262af 1550 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
dc196a57
FB
1551 if (seg_reg == R_SS)
1552 s->is_jmp = 3;
3415a4dd 1553 }
2c0262af
FB
1554}
1555
4f31916f
FB
1556static inline void gen_stack_update(DisasContext *s, int addend)
1557{
1558 if (s->ss32) {
1559 if (addend == 2)
1560 gen_op_addl_ESP_2();
1561 else if (addend == 4)
1562 gen_op_addl_ESP_4();
1563 else
1564 gen_op_addl_ESP_im(addend);
1565 } else {
1566 if (addend == 2)
1567 gen_op_addw_ESP_2();
1568 else if (addend == 4)
1569 gen_op_addw_ESP_4();
1570 else
1571 gen_op_addw_ESP_im(addend);
1572 }
1573}
1574
2c0262af
FB
1575/* generate a push. It depends on ss32, addseg and dflag */
1576static void gen_push_T0(DisasContext *s)
1577{
4f31916f
FB
1578 gen_op_movl_A0_reg[R_ESP]();
1579 if (!s->dflag)
1580 gen_op_subl_A0_2();
1581 else
1582 gen_op_subl_A0_4();
2c0262af 1583 if (s->ss32) {
4f31916f
FB
1584 if (s->addseg) {
1585 gen_op_movl_T1_A0();
1586 gen_op_addl_A0_SS();
2c0262af
FB
1587 }
1588 } else {
4f31916f
FB
1589 gen_op_andl_A0_ffff();
1590 gen_op_movl_T1_A0();
1591 gen_op_addl_A0_SS();
2c0262af 1592 }
4f31916f
FB
1593 gen_op_st_T0_A0[s->dflag + 1 + s->mem_index]();
1594 if (s->ss32 && !s->addseg)
1595 gen_op_movl_ESP_A0();
1596 else
1597 gen_op_mov_reg_T1[s->ss32 + 1][R_ESP]();
2c0262af
FB
1598}
1599
4f31916f
FB
1600/* generate a push. It depends on ss32, addseg and dflag */
1601/* slower version for T1, only used for call Ev */
1602static void gen_push_T1(DisasContext *s)
2c0262af 1603{
4f31916f
FB
1604 gen_op_movl_A0_reg[R_ESP]();
1605 if (!s->dflag)
1606 gen_op_subl_A0_2();
1607 else
1608 gen_op_subl_A0_4();
2c0262af 1609 if (s->ss32) {
4f31916f
FB
1610 if (s->addseg) {
1611 gen_op_addl_A0_SS();
2c0262af
FB
1612 }
1613 } else {
4f31916f
FB
1614 gen_op_andl_A0_ffff();
1615 gen_op_addl_A0_SS();
2c0262af 1616 }
4f31916f
FB
1617 gen_op_st_T1_A0[s->dflag + 1 + s->mem_index]();
1618
1619 if (s->ss32 && !s->addseg)
1620 gen_op_movl_ESP_A0();
1621 else
1622 gen_stack_update(s, (-2) << s->dflag);
2c0262af
FB
1623}
1624
4f31916f
FB
1625/* two step pop is necessary for precise exceptions */
1626static void gen_pop_T0(DisasContext *s)
2c0262af 1627{
4f31916f 1628 gen_op_movl_A0_reg[R_ESP]();
2c0262af 1629 if (s->ss32) {
4f31916f
FB
1630 if (s->addseg)
1631 gen_op_addl_A0_SS();
2c0262af 1632 } else {
4f31916f
FB
1633 gen_op_andl_A0_ffff();
1634 gen_op_addl_A0_SS();
2c0262af 1635 }
4f31916f 1636 gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index]();
2c0262af
FB
1637}
1638
1639static void gen_pop_update(DisasContext *s)
1640{
1641 gen_stack_update(s, 2 << s->dflag);
1642}
1643
1644static void gen_stack_A0(DisasContext *s)
1645{
1646 gen_op_movl_A0_ESP();
1647 if (!s->ss32)
1648 gen_op_andl_A0_ffff();
1649 gen_op_movl_T1_A0();
1650 if (s->addseg)
1651 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
1652}
1653
1654/* NOTE: wrap around in 16 bit not fully handled */
1655static void gen_pusha(DisasContext *s)
1656{
1657 int i;
1658 gen_op_movl_A0_ESP();
1659 gen_op_addl_A0_im(-16 << s->dflag);
1660 if (!s->ss32)
1661 gen_op_andl_A0_ffff();
1662 gen_op_movl_T1_A0();
1663 if (s->addseg)
1664 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
1665 for(i = 0;i < 8; i++) {
1666 gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
1667 gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index]();
1668 gen_op_addl_A0_im(2 << s->dflag);
1669 }
1670 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1671}
1672
1673/* NOTE: wrap around in 16 bit not fully handled */
1674static void gen_popa(DisasContext *s)
1675{
1676 int i;
1677 gen_op_movl_A0_ESP();
1678 if (!s->ss32)
1679 gen_op_andl_A0_ffff();
1680 gen_op_movl_T1_A0();
1681 gen_op_addl_T1_im(16 << s->dflag);
1682 if (s->addseg)
1683 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
1684 for(i = 0;i < 8; i++) {
1685 /* ESP is not reloaded */
1686 if (i != 3) {
1687 gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index]();
1688 gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i]();
1689 }
1690 gen_op_addl_A0_im(2 << s->dflag);
1691 }
1692 gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP]();
1693}
1694
2c0262af
FB
1695static void gen_enter(DisasContext *s, int esp_addend, int level)
1696{
61a8c4ec 1697 int ot, opsize;
2c0262af
FB
1698
1699 ot = s->dflag + OT_WORD;
1700 level &= 0x1f;
2c0262af
FB
1701 opsize = 2 << s->dflag;
1702
1703 gen_op_movl_A0_ESP();
1704 gen_op_addl_A0_im(-opsize);
1705 if (!s->ss32)
1706 gen_op_andl_A0_ffff();
1707 gen_op_movl_T1_A0();
1708 if (s->addseg)
1709 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
1710 /* push bp */
1711 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
1712 gen_op_st_T0_A0[ot + s->mem_index]();
1713 if (level) {
61a8c4ec 1714 gen_op_enter_level(level, s->dflag);
2c0262af
FB
1715 }
1716 gen_op_mov_reg_T1[ot][R_EBP]();
61a8c4ec 1717 gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
2c0262af
FB
1718 gen_op_mov_reg_T1[ot][R_ESP]();
1719}
1720
1721static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
1722{
1723 if (s->cc_op != CC_OP_DYNAMIC)
1724 gen_op_set_cc_op(s->cc_op);
1725 gen_op_jmp_im(cur_eip);
1726 gen_op_raise_exception(trapno);
1727 s->is_jmp = 3;
1728}
1729
1730/* an interrupt is different from an exception because of the
1731 priviledge checks */
1732static void gen_interrupt(DisasContext *s, int intno,
1733 unsigned int cur_eip, unsigned int next_eip)
1734{
1735 if (s->cc_op != CC_OP_DYNAMIC)
1736 gen_op_set_cc_op(s->cc_op);
1737 gen_op_jmp_im(cur_eip);
1738 gen_op_raise_interrupt(intno, next_eip);
1739 s->is_jmp = 3;
1740}
1741
1742static void gen_debug(DisasContext *s, unsigned int cur_eip)
1743{
1744 if (s->cc_op != CC_OP_DYNAMIC)
1745 gen_op_set_cc_op(s->cc_op);
1746 gen_op_jmp_im(cur_eip);
1747 gen_op_debug();
1748 s->is_jmp = 3;
1749}
1750
1751/* generate a generic end of block. Trace exception is also generated
1752 if needed */
1753static void gen_eob(DisasContext *s)
1754{
1755 if (s->cc_op != CC_OP_DYNAMIC)
1756 gen_op_set_cc_op(s->cc_op);
a2cc3b24
FB
1757 if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
1758 gen_op_reset_inhibit_irq();
1759 }
34865134
FB
1760 if (s->singlestep_enabled) {
1761 gen_op_debug();
1762 } else if (s->tf) {
2c0262af
FB
1763 gen_op_raise_exception(EXCP01_SSTP);
1764 } else {
1765 gen_op_movl_T0_0();
1766 gen_op_exit_tb();
1767 }
1768 s->is_jmp = 3;
1769}
1770
1771/* generate a jump to eip. No segment change must happen before as a
1772 direct call to the next block may occur */
1773static void gen_jmp(DisasContext *s, unsigned int eip)
1774{
1775 TranslationBlock *tb = s->tb;
1776
1777 if (s->jmp_opt) {
1778 if (s->cc_op != CC_OP_DYNAMIC)
1779 gen_op_set_cc_op(s->cc_op);
1780 gen_op_jmp((long)tb, eip);
1781 s->is_jmp = 3;
1782 } else {
1783 gen_op_jmp_im(eip);
1784 gen_eob(s);
1785 }
1786}
1787
1788/* convert one instruction. s->is_jmp is set if the translation must
1789 be stopped. Return the next pc value */
1790static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
1791{
1792 int b, prefixes, aflag, dflag;
1793 int shift, ot;
1794 int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
1795 unsigned int next_eip;
1796
1797 s->pc = pc_start;
1798 prefixes = 0;
1799 aflag = s->code32;
1800 dflag = s->code32;
1801 s->override = -1;
1802 next_byte:
61382a50 1803 b = ldub_code(s->pc);
2c0262af
FB
1804 s->pc++;
1805 /* check prefixes */
1806 switch (b) {
1807 case 0xf3:
1808 prefixes |= PREFIX_REPZ;
1809 goto next_byte;
1810 case 0xf2:
1811 prefixes |= PREFIX_REPNZ;
1812 goto next_byte;
1813 case 0xf0:
1814 prefixes |= PREFIX_LOCK;
1815 goto next_byte;
1816 case 0x2e:
1817 s->override = R_CS;
1818 goto next_byte;
1819 case 0x36:
1820 s->override = R_SS;
1821 goto next_byte;
1822 case 0x3e:
1823 s->override = R_DS;
1824 goto next_byte;
1825 case 0x26:
1826 s->override = R_ES;
1827 goto next_byte;
1828 case 0x64:
1829 s->override = R_FS;
1830 goto next_byte;
1831 case 0x65:
1832 s->override = R_GS;
1833 goto next_byte;
1834 case 0x66:
1835 prefixes |= PREFIX_DATA;
1836 goto next_byte;
1837 case 0x67:
1838 prefixes |= PREFIX_ADR;
1839 goto next_byte;
1840 }
1841
1842 if (prefixes & PREFIX_DATA)
1843 dflag ^= 1;
1844 if (prefixes & PREFIX_ADR)
1845 aflag ^= 1;
1846
1847 s->prefix = prefixes;
1848 s->aflag = aflag;
1849 s->dflag = dflag;
1850
1851 /* lock generation */
1852 if (prefixes & PREFIX_LOCK)
1853 gen_op_lock();
1854
1855 /* now check op code */
1856 reswitch:
1857 switch(b) {
1858 case 0x0f:
1859 /**************************/
1860 /* extended op code */
61382a50 1861 b = ldub_code(s->pc++) | 0x100;
2c0262af
FB
1862 goto reswitch;
1863
1864 /**************************/
1865 /* arith & logic */
1866 case 0x00 ... 0x05:
1867 case 0x08 ... 0x0d:
1868 case 0x10 ... 0x15:
1869 case 0x18 ... 0x1d:
1870 case 0x20 ... 0x25:
1871 case 0x28 ... 0x2d:
1872 case 0x30 ... 0x35:
1873 case 0x38 ... 0x3d:
1874 {
1875 int op, f, val;
1876 op = (b >> 3) & 7;
1877 f = (b >> 1) & 3;
1878
1879 if ((b & 1) == 0)
1880 ot = OT_BYTE;
1881 else
1882 ot = dflag ? OT_LONG : OT_WORD;
1883
1884 switch(f) {
1885 case 0: /* OP Ev, Gv */
61382a50 1886 modrm = ldub_code(s->pc++);
2c0262af
FB
1887 reg = ((modrm >> 3) & 7);
1888 mod = (modrm >> 6) & 3;
1889 rm = modrm & 7;
1890 if (mod != 3) {
1891 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1892 opreg = OR_TMP0;
1893 } else if (op == OP_XORL && rm == reg) {
1894 xor_zero:
1895 /* xor reg, reg optimisation */
1896 gen_op_movl_T0_0();
1897 s->cc_op = CC_OP_LOGICB + ot;
1898 gen_op_mov_reg_T0[ot][reg]();
1899 gen_op_update1_cc();
1900 break;
1901 } else {
1902 opreg = rm;
1903 }
1904 gen_op_mov_TN_reg[ot][1][reg]();
1905 gen_op(s, op, ot, opreg);
1906 break;
1907 case 1: /* OP Gv, Ev */
61382a50 1908 modrm = ldub_code(s->pc++);
2c0262af
FB
1909 mod = (modrm >> 6) & 3;
1910 reg = ((modrm >> 3) & 7);
1911 rm = modrm & 7;
1912 if (mod != 3) {
1913 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1914 gen_op_ld_T1_A0[ot + s->mem_index]();
1915 } else if (op == OP_XORL && rm == reg) {
1916 goto xor_zero;
1917 } else {
1918 gen_op_mov_TN_reg[ot][1][rm]();
1919 }
1920 gen_op(s, op, ot, reg);
1921 break;
1922 case 2: /* OP A, Iv */
1923 val = insn_get(s, ot);
1924 gen_op_movl_T1_im(val);
1925 gen_op(s, op, ot, OR_EAX);
1926 break;
1927 }
1928 }
1929 break;
1930
1931 case 0x80: /* GRP1 */
1932 case 0x81:
d64477af 1933 case 0x82:
2c0262af
FB
1934 case 0x83:
1935 {
1936 int val;
1937
1938 if ((b & 1) == 0)
1939 ot = OT_BYTE;
1940 else
1941 ot = dflag ? OT_LONG : OT_WORD;
1942
61382a50 1943 modrm = ldub_code(s->pc++);
2c0262af
FB
1944 mod = (modrm >> 6) & 3;
1945 rm = modrm & 7;
1946 op = (modrm >> 3) & 7;
1947
1948 if (mod != 3) {
1949 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1950 opreg = OR_TMP0;
1951 } else {
1952 opreg = rm + OR_EAX;
1953 }
1954
1955 switch(b) {
1956 default:
1957 case 0x80:
1958 case 0x81:
d64477af 1959 case 0x82:
2c0262af
FB
1960 val = insn_get(s, ot);
1961 break;
1962 case 0x83:
1963 val = (int8_t)insn_get(s, OT_BYTE);
1964 break;
1965 }
1966 gen_op_movl_T1_im(val);
1967 gen_op(s, op, ot, opreg);
1968 }
1969 break;
1970
1971 /**************************/
1972 /* inc, dec, and other misc arith */
1973 case 0x40 ... 0x47: /* inc Gv */
1974 ot = dflag ? OT_LONG : OT_WORD;
1975 gen_inc(s, ot, OR_EAX + (b & 7), 1);
1976 break;
1977 case 0x48 ... 0x4f: /* dec Gv */
1978 ot = dflag ? OT_LONG : OT_WORD;
1979 gen_inc(s, ot, OR_EAX + (b & 7), -1);
1980 break;
1981 case 0xf6: /* GRP3 */
1982 case 0xf7:
1983 if ((b & 1) == 0)
1984 ot = OT_BYTE;
1985 else
1986 ot = dflag ? OT_LONG : OT_WORD;
1987
61382a50 1988 modrm = ldub_code(s->pc++);
2c0262af
FB
1989 mod = (modrm >> 6) & 3;
1990 rm = modrm & 7;
1991 op = (modrm >> 3) & 7;
1992 if (mod != 3) {
1993 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
1994 gen_op_ld_T0_A0[ot + s->mem_index]();
1995 } else {
1996 gen_op_mov_TN_reg[ot][0][rm]();
1997 }
1998
1999 switch(op) {
2000 case 0: /* test */
2001 val = insn_get(s, ot);
2002 gen_op_movl_T1_im(val);
2003 gen_op_testl_T0_T1_cc();
2004 s->cc_op = CC_OP_LOGICB + ot;
2005 break;
2006 case 2: /* not */
2007 gen_op_notl_T0();
2008 if (mod != 3) {
2009 gen_op_st_T0_A0[ot + s->mem_index]();
2010 } else {
2011 gen_op_mov_reg_T0[ot][rm]();
2012 }
2013 break;
2014 case 3: /* neg */
2015 gen_op_negl_T0();
2016 if (mod != 3) {
2017 gen_op_st_T0_A0[ot + s->mem_index]();
2018 } else {
2019 gen_op_mov_reg_T0[ot][rm]();
2020 }
2021 gen_op_update_neg_cc();
2022 s->cc_op = CC_OP_SUBB + ot;
2023 break;
2024 case 4: /* mul */
2025 switch(ot) {
2026 case OT_BYTE:
2027 gen_op_mulb_AL_T0();
d36cd60e 2028 s->cc_op = CC_OP_MULB;
2c0262af
FB
2029 break;
2030 case OT_WORD:
2031 gen_op_mulw_AX_T0();
d36cd60e 2032 s->cc_op = CC_OP_MULW;
2c0262af
FB
2033 break;
2034 default:
2035 case OT_LONG:
2036 gen_op_mull_EAX_T0();
d36cd60e 2037 s->cc_op = CC_OP_MULL;
2c0262af
FB
2038 break;
2039 }
2c0262af
FB
2040 break;
2041 case 5: /* imul */
2042 switch(ot) {
2043 case OT_BYTE:
2044 gen_op_imulb_AL_T0();
d36cd60e 2045 s->cc_op = CC_OP_MULB;
2c0262af
FB
2046 break;
2047 case OT_WORD:
2048 gen_op_imulw_AX_T0();
d36cd60e 2049 s->cc_op = CC_OP_MULW;
2c0262af
FB
2050 break;
2051 default:
2052 case OT_LONG:
2053 gen_op_imull_EAX_T0();
d36cd60e 2054 s->cc_op = CC_OP_MULL;
2c0262af
FB
2055 break;
2056 }
2c0262af
FB
2057 break;
2058 case 6: /* div */
2059 switch(ot) {
2060 case OT_BYTE:
2061 gen_op_divb_AL_T0(pc_start - s->cs_base);
2062 break;
2063 case OT_WORD:
2064 gen_op_divw_AX_T0(pc_start - s->cs_base);
2065 break;
2066 default:
2067 case OT_LONG:
2068 gen_op_divl_EAX_T0(pc_start - s->cs_base);
2069 break;
2070 }
2071 break;
2072 case 7: /* idiv */
2073 switch(ot) {
2074 case OT_BYTE:
2075 gen_op_idivb_AL_T0(pc_start - s->cs_base);
2076 break;
2077 case OT_WORD:
2078 gen_op_idivw_AX_T0(pc_start - s->cs_base);
2079 break;
2080 default:
2081 case OT_LONG:
2082 gen_op_idivl_EAX_T0(pc_start - s->cs_base);
2083 break;
2084 }
2085 break;
2086 default:
2087 goto illegal_op;
2088 }
2089 break;
2090
2091 case 0xfe: /* GRP4 */
2092 case 0xff: /* GRP5 */
2093 if ((b & 1) == 0)
2094 ot = OT_BYTE;
2095 else
2096 ot = dflag ? OT_LONG : OT_WORD;
2097
61382a50 2098 modrm = ldub_code(s->pc++);
2c0262af
FB
2099 mod = (modrm >> 6) & 3;
2100 rm = modrm & 7;
2101 op = (modrm >> 3) & 7;
2102 if (op >= 2 && b == 0xfe) {
2103 goto illegal_op;
2104 }
2105 if (mod != 3) {
2106 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2107 if (op >= 2 && op != 3 && op != 5)
2108 gen_op_ld_T0_A0[ot + s->mem_index]();
2109 } else {
2110 gen_op_mov_TN_reg[ot][0][rm]();
2111 }
2112
2113 switch(op) {
2114 case 0: /* inc Ev */
2115 if (mod != 3)
2116 opreg = OR_TMP0;
2117 else
2118 opreg = rm;
2119 gen_inc(s, ot, opreg, 1);
2120 break;
2121 case 1: /* dec Ev */
2122 if (mod != 3)
2123 opreg = OR_TMP0;
2124 else
2125 opreg = rm;
2126 gen_inc(s, ot, opreg, -1);
2127 break;
2128 case 2: /* call Ev */
4f31916f 2129 /* XXX: optimize if memory (no 'and' is necessary) */
2c0262af
FB
2130 if (s->dflag == 0)
2131 gen_op_andl_T0_ffff();
2c0262af 2132 next_eip = s->pc - s->cs_base;
4f31916f
FB
2133 gen_op_movl_T1_im(next_eip);
2134 gen_push_T1(s);
2135 gen_op_jmp_T0();
2c0262af
FB
2136 gen_eob(s);
2137 break;
61382a50 2138 case 3: /* lcall Ev */
2c0262af
FB
2139 gen_op_ld_T1_A0[ot + s->mem_index]();
2140 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
61382a50 2141 gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
2c0262af
FB
2142 do_lcall:
2143 if (s->pe && !s->vm86) {
2144 if (s->cc_op != CC_OP_DYNAMIC)
2145 gen_op_set_cc_op(s->cc_op);
2146 gen_op_jmp_im(pc_start - s->cs_base);
2147 gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base);
2148 } else {
2149 gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base);
2150 }
2151 gen_eob(s);
2152 break;
2153 case 4: /* jmp Ev */
2154 if (s->dflag == 0)
2155 gen_op_andl_T0_ffff();
2156 gen_op_jmp_T0();
2157 gen_eob(s);
2158 break;
2159 case 5: /* ljmp Ev */
2160 gen_op_ld_T1_A0[ot + s->mem_index]();
2161 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
61382a50 2162 gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
2c0262af
FB
2163 do_ljmp:
2164 if (s->pe && !s->vm86) {
2165 if (s->cc_op != CC_OP_DYNAMIC)
2166 gen_op_set_cc_op(s->cc_op);
2167 gen_op_jmp_im(pc_start - s->cs_base);
08cea4ee 2168 gen_op_ljmp_protected_T0_T1(s->pc - s->cs_base);
2c0262af
FB
2169 } else {
2170 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
2171 gen_op_movl_T0_T1();
2172 gen_op_jmp_T0();
2173 }
2174 gen_eob(s);
2175 break;
2176 case 6: /* push Ev */
2177 gen_push_T0(s);
2178 break;
2179 default:
2180 goto illegal_op;
2181 }
2182 break;
2183
2184 case 0x84: /* test Ev, Gv */
2185 case 0x85:
2186 if ((b & 1) == 0)
2187 ot = OT_BYTE;
2188 else
2189 ot = dflag ? OT_LONG : OT_WORD;
2190
61382a50 2191 modrm = ldub_code(s->pc++);
2c0262af
FB
2192 mod = (modrm >> 6) & 3;
2193 rm = modrm & 7;
2194 reg = (modrm >> 3) & 7;
2195
2196 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2197 gen_op_mov_TN_reg[ot][1][reg + OR_EAX]();
2198 gen_op_testl_T0_T1_cc();
2199 s->cc_op = CC_OP_LOGICB + ot;
2200 break;
2201
2202 case 0xa8: /* test eAX, Iv */
2203 case 0xa9:
2204 if ((b & 1) == 0)
2205 ot = OT_BYTE;
2206 else
2207 ot = dflag ? OT_LONG : OT_WORD;
2208 val = insn_get(s, ot);
2209
2210 gen_op_mov_TN_reg[ot][0][OR_EAX]();
2211 gen_op_movl_T1_im(val);
2212 gen_op_testl_T0_T1_cc();
2213 s->cc_op = CC_OP_LOGICB + ot;
2214 break;
2215
2216 case 0x98: /* CWDE/CBW */
2217 if (dflag)
2218 gen_op_movswl_EAX_AX();
2219 else
2220 gen_op_movsbw_AX_AL();
2221 break;
2222 case 0x99: /* CDQ/CWD */
2223 if (dflag)
2224 gen_op_movslq_EDX_EAX();
2225 else
2226 gen_op_movswl_DX_AX();
2227 break;
2228 case 0x1af: /* imul Gv, Ev */
2229 case 0x69: /* imul Gv, Ev, I */
2230 case 0x6b:
2231 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2232 modrm = ldub_code(s->pc++);
2c0262af
FB
2233 reg = ((modrm >> 3) & 7) + OR_EAX;
2234 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2235 if (b == 0x69) {
2236 val = insn_get(s, ot);
2237 gen_op_movl_T1_im(val);
2238 } else if (b == 0x6b) {
d64477af 2239 val = (int8_t)insn_get(s, OT_BYTE);
2c0262af
FB
2240 gen_op_movl_T1_im(val);
2241 } else {
2242 gen_op_mov_TN_reg[ot][1][reg]();
2243 }
2244
2245 if (ot == OT_LONG) {
2246 gen_op_imull_T0_T1();
2247 } else {
2248 gen_op_imulw_T0_T1();
2249 }
2250 gen_op_mov_reg_T0[ot][reg]();
d36cd60e 2251 s->cc_op = CC_OP_MULB + ot;
2c0262af
FB
2252 break;
2253 case 0x1c0:
2254 case 0x1c1: /* xadd Ev, Gv */
2255 if ((b & 1) == 0)
2256 ot = OT_BYTE;
2257 else
2258 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2259 modrm = ldub_code(s->pc++);
2c0262af
FB
2260 reg = (modrm >> 3) & 7;
2261 mod = (modrm >> 6) & 3;
2262 if (mod == 3) {
2263 rm = modrm & 7;
2264 gen_op_mov_TN_reg[ot][0][reg]();
2265 gen_op_mov_TN_reg[ot][1][rm]();
2266 gen_op_addl_T0_T1();
2c0262af 2267 gen_op_mov_reg_T1[ot][reg]();
5a1388b6 2268 gen_op_mov_reg_T0[ot][rm]();
2c0262af
FB
2269 } else {
2270 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2271 gen_op_mov_TN_reg[ot][0][reg]();
2272 gen_op_ld_T1_A0[ot + s->mem_index]();
2273 gen_op_addl_T0_T1();
2274 gen_op_st_T0_A0[ot + s->mem_index]();
2275 gen_op_mov_reg_T1[ot][reg]();
2276 }
2277 gen_op_update2_cc();
2278 s->cc_op = CC_OP_ADDB + ot;
2279 break;
2280 case 0x1b0:
2281 case 0x1b1: /* cmpxchg Ev, Gv */
2282 if ((b & 1) == 0)
2283 ot = OT_BYTE;
2284 else
2285 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2286 modrm = ldub_code(s->pc++);
2c0262af
FB
2287 reg = (modrm >> 3) & 7;
2288 mod = (modrm >> 6) & 3;
2289 gen_op_mov_TN_reg[ot][1][reg]();
2290 if (mod == 3) {
2291 rm = modrm & 7;
2292 gen_op_mov_TN_reg[ot][0][rm]();
2293 gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
2294 gen_op_mov_reg_T0[ot][rm]();
2295 } else {
2296 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2297 gen_op_ld_T0_A0[ot + s->mem_index]();
4f31916f 2298 gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index]();
2c0262af
FB
2299 }
2300 s->cc_op = CC_OP_SUBB + ot;
2301 break;
2302 case 0x1c7: /* cmpxchg8b */
61382a50 2303 modrm = ldub_code(s->pc++);
2c0262af
FB
2304 mod = (modrm >> 6) & 3;
2305 if (mod == 3)
2306 goto illegal_op;
2307 if (s->cc_op != CC_OP_DYNAMIC)
2308 gen_op_set_cc_op(s->cc_op);
2309 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2310 gen_op_cmpxchg8b();
2311 s->cc_op = CC_OP_EFLAGS;
2312 break;
2313
2314 /**************************/
2315 /* push/pop */
2316 case 0x50 ... 0x57: /* push */
2317 gen_op_mov_TN_reg[OT_LONG][0][b & 7]();
2318 gen_push_T0(s);
2319 break;
2320 case 0x58 ... 0x5f: /* pop */
2321 ot = dflag ? OT_LONG : OT_WORD;
2322 gen_pop_T0(s);
77729c24 2323 /* NOTE: order is important for pop %sp */
2c0262af 2324 gen_pop_update(s);
77729c24 2325 gen_op_mov_reg_T0[ot][b & 7]();
2c0262af
FB
2326 break;
2327 case 0x60: /* pusha */
2328 gen_pusha(s);
2329 break;
2330 case 0x61: /* popa */
2331 gen_popa(s);
2332 break;
2333 case 0x68: /* push Iv */
2334 case 0x6a:
2335 ot = dflag ? OT_LONG : OT_WORD;
2336 if (b == 0x68)
2337 val = insn_get(s, ot);
2338 else
2339 val = (int8_t)insn_get(s, OT_BYTE);
2340 gen_op_movl_T0_im(val);
2341 gen_push_T0(s);
2342 break;
2343 case 0x8f: /* pop Ev */
2344 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2345 modrm = ldub_code(s->pc++);
77729c24 2346 mod = (modrm >> 6) & 3;
2c0262af 2347 gen_pop_T0(s);
77729c24
FB
2348 if (mod == 3) {
2349 /* NOTE: order is important for pop %sp */
2350 gen_pop_update(s);
2351 rm = modrm & 7;
2352 gen_op_mov_reg_T0[ot][rm]();
2353 } else {
2354 /* NOTE: order is important too for MMU exceptions */
2355 s->popl_esp_hack = 2 << dflag;
2356 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
2357 s->popl_esp_hack = 0;
2358 gen_pop_update(s);
2359 }
2c0262af
FB
2360 break;
2361 case 0xc8: /* enter */
2362 {
2363 int level;
61382a50 2364 val = lduw_code(s->pc);
2c0262af 2365 s->pc += 2;
61382a50 2366 level = ldub_code(s->pc++);
2c0262af
FB
2367 gen_enter(s, val, level);
2368 }
2369 break;
2370 case 0xc9: /* leave */
2371 /* XXX: exception not precise (ESP is updated before potential exception) */
2372 if (s->ss32) {
2373 gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
2374 gen_op_mov_reg_T0[OT_LONG][R_ESP]();
2375 } else {
2376 gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();
2377 gen_op_mov_reg_T0[OT_WORD][R_ESP]();
2378 }
2379 gen_pop_T0(s);
2380 ot = dflag ? OT_LONG : OT_WORD;
2381 gen_op_mov_reg_T0[ot][R_EBP]();
2382 gen_pop_update(s);
2383 break;
2384 case 0x06: /* push es */
2385 case 0x0e: /* push cs */
2386 case 0x16: /* push ss */
2387 case 0x1e: /* push ds */
2388 gen_op_movl_T0_seg(b >> 3);
2389 gen_push_T0(s);
2390 break;
2391 case 0x1a0: /* push fs */
2392 case 0x1a8: /* push gs */
2393 gen_op_movl_T0_seg((b >> 3) & 7);
2394 gen_push_T0(s);
2395 break;
2396 case 0x07: /* pop es */
2397 case 0x17: /* pop ss */
2398 case 0x1f: /* pop ds */
2399 reg = b >> 3;
2400 gen_pop_T0(s);
2401 gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
2402 gen_pop_update(s);
2403 if (reg == R_SS) {
a2cc3b24
FB
2404 /* if reg == SS, inhibit interrupts/trace. */
2405 /* If several instructions disable interrupts, only the
2406 _first_ does it */
2407 if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
2408 gen_op_set_inhibit_irq();
2c0262af
FB
2409 s->tf = 0;
2410 }
2411 if (s->is_jmp) {
2412 gen_op_jmp_im(s->pc - s->cs_base);
2413 gen_eob(s);
2414 }
2415 break;
2416 case 0x1a1: /* pop fs */
2417 case 0x1a9: /* pop gs */
2418 gen_pop_T0(s);
2419 gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
2420 gen_pop_update(s);
2421 if (s->is_jmp) {
2422 gen_op_jmp_im(s->pc - s->cs_base);
2423 gen_eob(s);
2424 }
2425 break;
2426
2427 /**************************/
2428 /* mov */
2429 case 0x88:
2430 case 0x89: /* mov Gv, Ev */
2431 if ((b & 1) == 0)
2432 ot = OT_BYTE;
2433 else
2434 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2435 modrm = ldub_code(s->pc++);
2c0262af
FB
2436 reg = (modrm >> 3) & 7;
2437
2438 /* generate a generic store */
2439 gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1);
2440 break;
2441 case 0xc6:
2442 case 0xc7: /* mov Ev, Iv */
2443 if ((b & 1) == 0)
2444 ot = OT_BYTE;
2445 else
2446 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2447 modrm = ldub_code(s->pc++);
2c0262af
FB
2448 mod = (modrm >> 6) & 3;
2449 if (mod != 3)
2450 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2451 val = insn_get(s, ot);
2452 gen_op_movl_T0_im(val);
2453 if (mod != 3)
2454 gen_op_st_T0_A0[ot + s->mem_index]();
2455 else
2456 gen_op_mov_reg_T0[ot][modrm & 7]();
2457 break;
2458 case 0x8a:
2459 case 0x8b: /* mov Ev, Gv */
2460 if ((b & 1) == 0)
2461 ot = OT_BYTE;
2462 else
2463 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2464 modrm = ldub_code(s->pc++);
2c0262af
FB
2465 reg = (modrm >> 3) & 7;
2466
2467 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
2468 gen_op_mov_reg_T0[ot][reg]();
2469 break;
2470 case 0x8e: /* mov seg, Gv */
61382a50 2471 modrm = ldub_code(s->pc++);
2c0262af
FB
2472 reg = (modrm >> 3) & 7;
2473 if (reg >= 6 || reg == R_CS)
2474 goto illegal_op;
2475 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
2476 gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
2477 if (reg == R_SS) {
2478 /* if reg == SS, inhibit interrupts/trace */
a2cc3b24
FB
2479 /* If several instructions disable interrupts, only the
2480 _first_ does it */
2481 if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
2482 gen_op_set_inhibit_irq();
2c0262af
FB
2483 s->tf = 0;
2484 }
2485 if (s->is_jmp) {
2486 gen_op_jmp_im(s->pc - s->cs_base);
2487 gen_eob(s);
2488 }
2489 break;
2490 case 0x8c: /* mov Gv, seg */
61382a50 2491 modrm = ldub_code(s->pc++);
2c0262af
FB
2492 reg = (modrm >> 3) & 7;
2493 mod = (modrm >> 6) & 3;
2494 if (reg >= 6)
2495 goto illegal_op;
2496 gen_op_movl_T0_seg(reg);
2497 ot = OT_WORD;
2498 if (mod == 3 && dflag)
2499 ot = OT_LONG;
2500 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
2501 break;
2502
2503 case 0x1b6: /* movzbS Gv, Eb */
2504 case 0x1b7: /* movzwS Gv, Eb */
2505 case 0x1be: /* movsbS Gv, Eb */
2506 case 0x1bf: /* movswS Gv, Eb */
2507 {
2508 int d_ot;
2509 /* d_ot is the size of destination */
2510 d_ot = dflag + OT_WORD;
2511 /* ot is the size of source */
2512 ot = (b & 1) + OT_BYTE;
61382a50 2513 modrm = ldub_code(s->pc++);
2c0262af
FB
2514 reg = ((modrm >> 3) & 7) + OR_EAX;
2515 mod = (modrm >> 6) & 3;
2516 rm = modrm & 7;
2517
2518 if (mod == 3) {
2519 gen_op_mov_TN_reg[ot][0][rm]();
2520 switch(ot | (b & 8)) {
2521 case OT_BYTE:
2522 gen_op_movzbl_T0_T0();
2523 break;
2524 case OT_BYTE | 8:
2525 gen_op_movsbl_T0_T0();
2526 break;
2527 case OT_WORD:
2528 gen_op_movzwl_T0_T0();
2529 break;
2530 default:
2531 case OT_WORD | 8:
2532 gen_op_movswl_T0_T0();
2533 break;
2534 }
2535 gen_op_mov_reg_T0[d_ot][reg]();
2536 } else {
2537 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2538 if (b & 8) {
2539 gen_op_lds_T0_A0[ot + s->mem_index]();
2540 } else {
2541 gen_op_ldu_T0_A0[ot + s->mem_index]();
2542 }
2543 gen_op_mov_reg_T0[d_ot][reg]();
2544 }
2545 }
2546 break;
2547
2548 case 0x8d: /* lea */
2549 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2550 modrm = ldub_code(s->pc++);
3a1d9b8b
FB
2551 mod = (modrm >> 6) & 3;
2552 if (mod == 3)
2553 goto illegal_op;
2c0262af
FB
2554 reg = (modrm >> 3) & 7;
2555 /* we must ensure that no segment is added */
2556 s->override = -1;
2557 val = s->addseg;
2558 s->addseg = 0;
2559 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2560 s->addseg = val;
2561 gen_op_mov_reg_A0[ot - OT_WORD][reg]();
2562 break;
2563
2564 case 0xa0: /* mov EAX, Ov */
2565 case 0xa1:
2566 case 0xa2: /* mov Ov, EAX */
2567 case 0xa3:
2568 if ((b & 1) == 0)
2569 ot = OT_BYTE;
2570 else
2571 ot = dflag ? OT_LONG : OT_WORD;
2572 if (s->aflag)
2573 offset_addr = insn_get(s, OT_LONG);
2574 else
2575 offset_addr = insn_get(s, OT_WORD);
2576 gen_op_movl_A0_im(offset_addr);
2577 /* handle override */
2578 {
2579 int override, must_add_seg;
2580 must_add_seg = s->addseg;
2581 if (s->override >= 0) {
2582 override = s->override;
2583 must_add_seg = 1;
2584 } else {
2585 override = R_DS;
2586 }
2587 if (must_add_seg) {
2588 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
2589 }
2590 }
2591 if ((b & 2) == 0) {
2592 gen_op_ld_T0_A0[ot + s->mem_index]();
2593 gen_op_mov_reg_T0[ot][R_EAX]();
2594 } else {
2595 gen_op_mov_TN_reg[ot][0][R_EAX]();
2596 gen_op_st_T0_A0[ot + s->mem_index]();
2597 }
2598 break;
2599 case 0xd7: /* xlat */
2600 gen_op_movl_A0_reg[R_EBX]();
2601 gen_op_addl_A0_AL();
2602 if (s->aflag == 0)
2603 gen_op_andl_A0_ffff();
2604 /* handle override */
2605 {
2606 int override, must_add_seg;
2607 must_add_seg = s->addseg;
2608 override = R_DS;
2609 if (s->override >= 0) {
2610 override = s->override;
2611 must_add_seg = 1;
2612 } else {
2613 override = R_DS;
2614 }
2615 if (must_add_seg) {
2616 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
2617 }
2618 }
2619 gen_op_ldu_T0_A0[OT_BYTE + s->mem_index]();
2620 gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
2621 break;
2622 case 0xb0 ... 0xb7: /* mov R, Ib */
2623 val = insn_get(s, OT_BYTE);
2624 gen_op_movl_T0_im(val);
2625 gen_op_mov_reg_T0[OT_BYTE][b & 7]();
2626 break;
2627 case 0xb8 ... 0xbf: /* mov R, Iv */
2628 ot = dflag ? OT_LONG : OT_WORD;
2629 val = insn_get(s, ot);
2630 reg = OR_EAX + (b & 7);
2631 gen_op_movl_T0_im(val);
2632 gen_op_mov_reg_T0[ot][reg]();
2633 break;
2634
2635 case 0x91 ... 0x97: /* xchg R, EAX */
2636 ot = dflag ? OT_LONG : OT_WORD;
2637 reg = b & 7;
2638 rm = R_EAX;
2639 goto do_xchg_reg;
2640 case 0x86:
2641 case 0x87: /* xchg Ev, Gv */
2642 if ((b & 1) == 0)
2643 ot = OT_BYTE;
2644 else
2645 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2646 modrm = ldub_code(s->pc++);
2c0262af
FB
2647 reg = (modrm >> 3) & 7;
2648 mod = (modrm >> 6) & 3;
2649 if (mod == 3) {
2650 rm = modrm & 7;
2651 do_xchg_reg:
2652 gen_op_mov_TN_reg[ot][0][reg]();
2653 gen_op_mov_TN_reg[ot][1][rm]();
2654 gen_op_mov_reg_T0[ot][rm]();
2655 gen_op_mov_reg_T1[ot][reg]();
2656 } else {
2657 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2658 gen_op_mov_TN_reg[ot][0][reg]();
2659 /* for xchg, lock is implicit */
2660 if (!(prefixes & PREFIX_LOCK))
2661 gen_op_lock();
2662 gen_op_ld_T1_A0[ot + s->mem_index]();
2663 gen_op_st_T0_A0[ot + s->mem_index]();
2664 if (!(prefixes & PREFIX_LOCK))
2665 gen_op_unlock();
2666 gen_op_mov_reg_T1[ot][reg]();
2667 }
2668 break;
2669 case 0xc4: /* les Gv */
2670 op = R_ES;
2671 goto do_lxx;
2672 case 0xc5: /* lds Gv */
2673 op = R_DS;
2674 goto do_lxx;
2675 case 0x1b2: /* lss Gv */
2676 op = R_SS;
2677 goto do_lxx;
2678 case 0x1b4: /* lfs Gv */
2679 op = R_FS;
2680 goto do_lxx;
2681 case 0x1b5: /* lgs Gv */
2682 op = R_GS;
2683 do_lxx:
2684 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2685 modrm = ldub_code(s->pc++);
2c0262af
FB
2686 reg = (modrm >> 3) & 7;
2687 mod = (modrm >> 6) & 3;
2688 if (mod == 3)
2689 goto illegal_op;
2690 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2691 gen_op_ld_T1_A0[ot + s->mem_index]();
2692 gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
2693 /* load the segment first to handle exceptions properly */
61382a50 2694 gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
2c0262af
FB
2695 gen_movl_seg_T0(s, op, pc_start - s->cs_base);
2696 /* then put the data */
2697 gen_op_mov_reg_T1[ot][reg]();
2698 if (s->is_jmp) {
2699 gen_op_jmp_im(s->pc - s->cs_base);
2700 gen_eob(s);
2701 }
2702 break;
2703
2704 /************************/
2705 /* shifts */
2706 case 0xc0:
2707 case 0xc1:
2708 /* shift Ev,Ib */
2709 shift = 2;
2710 grp2:
2711 {
2712 if ((b & 1) == 0)
2713 ot = OT_BYTE;
2714 else
2715 ot = dflag ? OT_LONG : OT_WORD;
2716
61382a50 2717 modrm = ldub_code(s->pc++);
2c0262af
FB
2718 mod = (modrm >> 6) & 3;
2719 rm = modrm & 7;
2720 op = (modrm >> 3) & 7;
2721
2722 if (mod != 3) {
2723 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2724 opreg = OR_TMP0;
2725 } else {
2726 opreg = rm + OR_EAX;
2727 }
2728
2729 /* simpler op */
2730 if (shift == 0) {
2731 gen_shift(s, op, ot, opreg, OR_ECX);
2732 } else {
2733 if (shift == 2) {
61382a50 2734 shift = ldub_code(s->pc++);
2c0262af
FB
2735 }
2736 gen_shifti(s, op, ot, opreg, shift);
2737 }
2738 }
2739 break;
2740 case 0xd0:
2741 case 0xd1:
2742 /* shift Ev,1 */
2743 shift = 1;
2744 goto grp2;
2745 case 0xd2:
2746 case 0xd3:
2747 /* shift Ev,cl */
2748 shift = 0;
2749 goto grp2;
2750
2751 case 0x1a4: /* shld imm */
2752 op = 0;
2753 shift = 1;
2754 goto do_shiftd;
2755 case 0x1a5: /* shld cl */
2756 op = 0;
2757 shift = 0;
2758 goto do_shiftd;
2759 case 0x1ac: /* shrd imm */
2760 op = 1;
2761 shift = 1;
2762 goto do_shiftd;
2763 case 0x1ad: /* shrd cl */
2764 op = 1;
2765 shift = 0;
2766 do_shiftd:
2767 ot = dflag ? OT_LONG : OT_WORD;
61382a50 2768 modrm = ldub_code(s->pc++);
2c0262af
FB
2769 mod = (modrm >> 6) & 3;
2770 rm = modrm & 7;
2771 reg = (modrm >> 3) & 7;
2772
2773 if (mod != 3) {
2774 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2775 gen_op_ld_T0_A0[ot + s->mem_index]();
2776 } else {
2777 gen_op_mov_TN_reg[ot][0][rm]();
2778 }
2779 gen_op_mov_TN_reg[ot][1][reg]();
2780
2781 if (shift) {
61382a50 2782 val = ldub_code(s->pc++);
2c0262af
FB
2783 val &= 0x1f;
2784 if (val) {
2785 if (mod == 3)
4f31916f 2786 gen_op_shiftd_T0_T1_im_cc[ot][op](val);
2c0262af 2787 else
4f31916f 2788 gen_op_shiftd_mem_T0_T1_im_cc[ot + s->mem_index][op](val);
2c0262af
FB
2789 if (op == 0 && ot != OT_WORD)
2790 s->cc_op = CC_OP_SHLB + ot;
2791 else
2792 s->cc_op = CC_OP_SARB + ot;
2793 }
2794 } else {
2795 if (s->cc_op != CC_OP_DYNAMIC)
2796 gen_op_set_cc_op(s->cc_op);
2797 if (mod == 3)
4f31916f 2798 gen_op_shiftd_T0_T1_ECX_cc[ot][op]();
2c0262af 2799 else
4f31916f 2800 gen_op_shiftd_mem_T0_T1_ECX_cc[ot + s->mem_index][op]();
2c0262af
FB
2801 s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
2802 }
2803 if (mod == 3) {
2804 gen_op_mov_reg_T0[ot][rm]();
2805 }
2806 break;
2807
2808 /************************/
2809 /* floats */
2810 case 0xd8 ... 0xdf:
7eee2a50
FB
2811 if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
2812 /* if CR0.EM or CR0.TS are set, generate an FPU exception */
2813 /* XXX: what to do if illegal op ? */
2814 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
2815 break;
2816 }
61382a50 2817 modrm = ldub_code(s->pc++);
2c0262af
FB
2818 mod = (modrm >> 6) & 3;
2819 rm = modrm & 7;
2820 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
2c0262af
FB
2821 if (mod != 3) {
2822 /* memory op */
2823 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
2824 switch(op) {
2825 case 0x00 ... 0x07: /* fxxxs */
2826 case 0x10 ... 0x17: /* fixxxl */
2827 case 0x20 ... 0x27: /* fxxxl */
2828 case 0x30 ... 0x37: /* fixxx */
2829 {
2830 int op1;
2831 op1 = op & 7;
2832
2833 switch(op >> 4) {
2834 case 0:
2835 gen_op_flds_FT0_A0();
2836 break;
2837 case 1:
2838 gen_op_fildl_FT0_A0();
2839 break;
2840 case 2:
2841 gen_op_fldl_FT0_A0();
2842 break;
2843 case 3:
2844 default:
2845 gen_op_fild_FT0_A0();
2846 break;
2847 }
2848
2849 gen_op_fp_arith_ST0_FT0[op1]();
2850 if (op1 == 3) {
2851 /* fcomp needs pop */
2852 gen_op_fpop();
2853 }
2854 }
2855 break;
2856 case 0x08: /* flds */
2857 case 0x0a: /* fsts */
2858 case 0x0b: /* fstps */
2859 case 0x18: /* fildl */
2860 case 0x1a: /* fistl */
2861 case 0x1b: /* fistpl */
2862 case 0x28: /* fldl */
2863 case 0x2a: /* fstl */
2864 case 0x2b: /* fstpl */
2865 case 0x38: /* filds */
2866 case 0x3a: /* fists */
2867 case 0x3b: /* fistps */
2868
2869 switch(op & 7) {
2870 case 0:
2871 switch(op >> 4) {
2872 case 0:
2873 gen_op_flds_ST0_A0();
2874 break;
2875 case 1:
2876 gen_op_fildl_ST0_A0();
2877 break;
2878 case 2:
2879 gen_op_fldl_ST0_A0();
2880 break;
2881 case 3:
2882 default:
2883 gen_op_fild_ST0_A0();
2884 break;
2885 }
2886 break;
2887 default:
2888 switch(op >> 4) {
2889 case 0:
2890 gen_op_fsts_ST0_A0();
2891 break;
2892 case 1:
2893 gen_op_fistl_ST0_A0();
2894 break;
2895 case 2:
2896 gen_op_fstl_ST0_A0();
2897 break;
2898 case 3:
2899 default:
2900 gen_op_fist_ST0_A0();
2901 break;
2902 }
2903 if ((op & 7) == 3)
2904 gen_op_fpop();
2905 break;
2906 }
2907 break;
2908 case 0x0c: /* fldenv mem */
2909 gen_op_fldenv_A0(s->dflag);
2910 break;
2911 case 0x0d: /* fldcw mem */
2912 gen_op_fldcw_A0();
2913 break;
2914 case 0x0e: /* fnstenv mem */
2915 gen_op_fnstenv_A0(s->dflag);
2916 break;
2917 case 0x0f: /* fnstcw mem */
2918 gen_op_fnstcw_A0();
2919 break;
2920 case 0x1d: /* fldt mem */
2921 gen_op_fldt_ST0_A0();
2922 break;
2923 case 0x1f: /* fstpt mem */
2924 gen_op_fstt_ST0_A0();
2925 gen_op_fpop();
2926 break;
2927 case 0x2c: /* frstor mem */
2928 gen_op_frstor_A0(s->dflag);
2929 break;
2930 case 0x2e: /* fnsave mem */
2931 gen_op_fnsave_A0(s->dflag);
2932 break;
2933 case 0x2f: /* fnstsw mem */
2934 gen_op_fnstsw_A0();
2935 break;
2936 case 0x3c: /* fbld */
2937 gen_op_fbld_ST0_A0();
2938 break;
2939 case 0x3e: /* fbstp */
2940 gen_op_fbst_ST0_A0();
2941 gen_op_fpop();
2942 break;
2943 case 0x3d: /* fildll */
2944 gen_op_fildll_ST0_A0();
2945 break;
2946 case 0x3f: /* fistpll */
2947 gen_op_fistll_ST0_A0();
2948 gen_op_fpop();
2949 break;
2950 default:
2951 goto illegal_op;
2952 }
2953 } else {
2954 /* register float ops */
2955 opreg = rm;
2956
2957 switch(op) {
2958 case 0x08: /* fld sti */
2959 gen_op_fpush();
2960 gen_op_fmov_ST0_STN((opreg + 1) & 7);
2961 break;
2962 case 0x09: /* fxchg sti */
c169c906
FB
2963 case 0x29: /* fxchg4 sti, undocumented op */
2964 case 0x39: /* fxchg7 sti, undocumented op */
2c0262af
FB
2965 gen_op_fxchg_ST0_STN(opreg);
2966 break;
2967 case 0x0a: /* grp d9/2 */
2968 switch(rm) {
2969 case 0: /* fnop */
023fe10d
FB
2970 /* check exceptions (FreeBSD FPU probe) */
2971 if (s->cc_op != CC_OP_DYNAMIC)
2972 gen_op_set_cc_op(s->cc_op);
2973 gen_op_jmp_im(pc_start - s->cs_base);
2974 gen_op_fwait();
2c0262af
FB
2975 break;
2976 default:
2977 goto illegal_op;
2978 }
2979 break;
2980 case 0x0c: /* grp d9/4 */
2981 switch(rm) {
2982 case 0: /* fchs */
2983 gen_op_fchs_ST0();
2984 break;
2985 case 1: /* fabs */
2986 gen_op_fabs_ST0();
2987 break;
2988 case 4: /* ftst */
2989 gen_op_fldz_FT0();
2990 gen_op_fcom_ST0_FT0();
2991 break;
2992 case 5: /* fxam */
2993 gen_op_fxam_ST0();
2994 break;
2995 default:
2996 goto illegal_op;
2997 }
2998 break;
2999 case 0x0d: /* grp d9/5 */
3000 {
3001 switch(rm) {
3002 case 0:
3003 gen_op_fpush();
3004 gen_op_fld1_ST0();
3005 break;
3006 case 1:
3007 gen_op_fpush();
3008 gen_op_fldl2t_ST0();
3009 break;
3010 case 2:
3011 gen_op_fpush();
3012 gen_op_fldl2e_ST0();
3013 break;
3014 case 3:
3015 gen_op_fpush();
3016 gen_op_fldpi_ST0();
3017 break;
3018 case 4:
3019 gen_op_fpush();
3020 gen_op_fldlg2_ST0();
3021 break;
3022 case 5:
3023 gen_op_fpush();
3024 gen_op_fldln2_ST0();
3025 break;
3026 case 6:
3027 gen_op_fpush();
3028 gen_op_fldz_ST0();
3029 break;
3030 default:
3031 goto illegal_op;
3032 }
3033 }
3034 break;
3035 case 0x0e: /* grp d9/6 */
3036 switch(rm) {
3037 case 0: /* f2xm1 */
3038 gen_op_f2xm1();
3039 break;
3040 case 1: /* fyl2x */
3041 gen_op_fyl2x();
3042 break;
3043 case 2: /* fptan */
3044 gen_op_fptan();
3045 break;
3046 case 3: /* fpatan */
3047 gen_op_fpatan();
3048 break;
3049 case 4: /* fxtract */
3050 gen_op_fxtract();
3051 break;
3052 case 5: /* fprem1 */
3053 gen_op_fprem1();
3054 break;
3055 case 6: /* fdecstp */
3056 gen_op_fdecstp();
3057 break;
3058 default:
3059 case 7: /* fincstp */
3060 gen_op_fincstp();
3061 break;
3062 }
3063 break;
3064 case 0x0f: /* grp d9/7 */
3065 switch(rm) {
3066 case 0: /* fprem */
3067 gen_op_fprem();
3068 break;
3069 case 1: /* fyl2xp1 */
3070 gen_op_fyl2xp1();
3071 break;
3072 case 2: /* fsqrt */
3073 gen_op_fsqrt();
3074 break;
3075 case 3: /* fsincos */
3076 gen_op_fsincos();
3077 break;
3078 case 5: /* fscale */
3079 gen_op_fscale();
3080 break;
3081 case 4: /* frndint */
3082 gen_op_frndint();
3083 break;
3084 case 6: /* fsin */
3085 gen_op_fsin();
3086 break;
3087 default:
3088 case 7: /* fcos */
3089 gen_op_fcos();
3090 break;
3091 }
3092 break;
3093 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
3094 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
3095 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
3096 {
3097 int op1;
3098
3099 op1 = op & 7;
3100 if (op >= 0x20) {
3101 gen_op_fp_arith_STN_ST0[op1](opreg);
3102 if (op >= 0x30)
3103 gen_op_fpop();
3104 } else {
3105 gen_op_fmov_FT0_STN(opreg);
3106 gen_op_fp_arith_ST0_FT0[op1]();
3107 }
3108 }
3109 break;
3110 case 0x02: /* fcom */
c169c906 3111 case 0x22: /* fcom2, undocumented op */
2c0262af
FB
3112 gen_op_fmov_FT0_STN(opreg);
3113 gen_op_fcom_ST0_FT0();
3114 break;
3115 case 0x03: /* fcomp */
c169c906
FB
3116 case 0x23: /* fcomp3, undocumented op */
3117 case 0x32: /* fcomp5, undocumented op */
2c0262af
FB
3118 gen_op_fmov_FT0_STN(opreg);
3119 gen_op_fcom_ST0_FT0();
3120 gen_op_fpop();
3121 break;
3122 case 0x15: /* da/5 */
3123 switch(rm) {
3124 case 1: /* fucompp */
3125 gen_op_fmov_FT0_STN(1);
3126 gen_op_fucom_ST0_FT0();
3127 gen_op_fpop();
3128 gen_op_fpop();
3129 break;
3130 default:
3131 goto illegal_op;
3132 }
3133 break;
3134 case 0x1c:
3135 switch(rm) {
3136 case 0: /* feni (287 only, just do nop here) */
3137 break;
3138 case 1: /* fdisi (287 only, just do nop here) */
3139 break;
3140 case 2: /* fclex */
3141 gen_op_fclex();
3142 break;
3143 case 3: /* fninit */
3144 gen_op_fninit();
3145 break;
3146 case 4: /* fsetpm (287 only, just do nop here) */
3147 break;
3148 default:
3149 goto illegal_op;
3150 }
3151 break;
3152 case 0x1d: /* fucomi */
3153 if (s->cc_op != CC_OP_DYNAMIC)
3154 gen_op_set_cc_op(s->cc_op);
3155 gen_op_fmov_FT0_STN(opreg);
3156 gen_op_fucomi_ST0_FT0();
3157 s->cc_op = CC_OP_EFLAGS;
3158 break;
3159 case 0x1e: /* fcomi */
3160 if (s->cc_op != CC_OP_DYNAMIC)
3161 gen_op_set_cc_op(s->cc_op);
3162 gen_op_fmov_FT0_STN(opreg);
3163 gen_op_fcomi_ST0_FT0();
3164 s->cc_op = CC_OP_EFLAGS;
3165 break;
658c8bda
FB
3166 case 0x28: /* ffree sti */
3167 gen_op_ffree_STN(opreg);
3168 break;
2c0262af
FB
3169 case 0x2a: /* fst sti */
3170 gen_op_fmov_STN_ST0(opreg);
3171 break;
3172 case 0x2b: /* fstp sti */
c169c906
FB
3173 case 0x0b: /* fstp1 sti, undocumented op */
3174 case 0x3a: /* fstp8 sti, undocumented op */
3175 case 0x3b: /* fstp9 sti, undocumented op */
2c0262af
FB
3176 gen_op_fmov_STN_ST0(opreg);
3177 gen_op_fpop();
3178 break;
3179 case 0x2c: /* fucom st(i) */
3180 gen_op_fmov_FT0_STN(opreg);
3181 gen_op_fucom_ST0_FT0();
3182 break;
3183 case 0x2d: /* fucomp st(i) */
3184 gen_op_fmov_FT0_STN(opreg);
3185 gen_op_fucom_ST0_FT0();
3186 gen_op_fpop();
3187 break;
3188 case 0x33: /* de/3 */
3189 switch(rm) {
3190 case 1: /* fcompp */
3191 gen_op_fmov_FT0_STN(1);
3192 gen_op_fcom_ST0_FT0();
3193 gen_op_fpop();
3194 gen_op_fpop();
3195 break;
3196 default:
3197 goto illegal_op;
3198 }
3199 break;
c169c906
FB
3200 case 0x38: /* ffreep sti, undocumented op */
3201 gen_op_ffree_STN(opreg);
3202 gen_op_fpop();
3203 break;
2c0262af
FB
3204 case 0x3c: /* df/4 */
3205 switch(rm) {
3206 case 0:
3207 gen_op_fnstsw_EAX();
3208 break;
3209 default:
3210 goto illegal_op;
3211 }
3212 break;
3213 case 0x3d: /* fucomip */
3214 if (s->cc_op != CC_OP_DYNAMIC)
3215 gen_op_set_cc_op(s->cc_op);
3216 gen_op_fmov_FT0_STN(opreg);
3217 gen_op_fucomi_ST0_FT0();
3218 gen_op_fpop();
3219 s->cc_op = CC_OP_EFLAGS;
3220 break;
3221 case 0x3e: /* fcomip */
3222 if (s->cc_op != CC_OP_DYNAMIC)
3223 gen_op_set_cc_op(s->cc_op);
3224 gen_op_fmov_FT0_STN(opreg);
3225 gen_op_fcomi_ST0_FT0();
3226 gen_op_fpop();
3227 s->cc_op = CC_OP_EFLAGS;
3228 break;
a2cc3b24
FB
3229 case 0x10 ... 0x13: /* fcmovxx */
3230 case 0x18 ... 0x1b:
3231 {
3232 int op1;
3233 const static uint8_t fcmov_cc[8] = {
3234 (JCC_B << 1),
3235 (JCC_Z << 1),
3236 (JCC_BE << 1),
3237 (JCC_P << 1),
3238 };
3239 op1 = fcmov_cc[op & 3] | ((op >> 3) & 1);
3240 gen_setcc(s, op1);
3241 gen_op_fcmov_ST0_STN_T0(opreg);
3242 }
3243 break;
2c0262af
FB
3244 default:
3245 goto illegal_op;
3246 }
3247 }
7eee2a50
FB
3248#ifdef USE_CODE_COPY
3249 s->tb->cflags |= CF_TB_FP_USED;
3250#endif
2c0262af
FB
3251 break;
3252 /************************/
3253 /* string ops */
3254
3255 case 0xa4: /* movsS */
3256 case 0xa5:
3257 if ((b & 1) == 0)
3258 ot = OT_BYTE;
3259 else
3260 ot = dflag ? OT_LONG : OT_WORD;
3261
3262 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
3263 gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
3264 } else {
3265 gen_movs(s, ot);
3266 }
3267 break;
3268
3269 case 0xaa: /* stosS */
3270 case 0xab:
3271 if ((b & 1) == 0)
3272 ot = OT_BYTE;
3273 else
3274 ot = dflag ? OT_LONG : OT_WORD;
3275
3276 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
3277 gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
3278 } else {
3279 gen_stos(s, ot);
3280 }
3281 break;
3282 case 0xac: /* lodsS */
3283 case 0xad:
3284 if ((b & 1) == 0)
3285 ot = OT_BYTE;
3286 else
3287 ot = dflag ? OT_LONG : OT_WORD;
3288 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
3289 gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
3290 } else {
3291 gen_lods(s, ot);
3292 }
3293 break;
3294 case 0xae: /* scasS */
3295 case 0xaf:
3296 if ((b & 1) == 0)
3297 ot = OT_BYTE;
3298 else
3299 ot = dflag ? OT_LONG : OT_WORD;
3300 if (prefixes & PREFIX_REPNZ) {
3301 gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
3302 } else if (prefixes & PREFIX_REPZ) {
3303 gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
3304 } else {
3305 gen_scas(s, ot);
3306 s->cc_op = CC_OP_SUBB + ot;
3307 }
3308 break;
3309
3310 case 0xa6: /* cmpsS */
3311 case 0xa7:
3312 if ((b & 1) == 0)
3313 ot = OT_BYTE;
3314 else
3315 ot = dflag ? OT_LONG : OT_WORD;
3316 if (prefixes & PREFIX_REPNZ) {
3317 gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
3318 } else if (prefixes & PREFIX_REPZ) {
3319 gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
3320 } else {
3321 gen_cmps(s, ot);
3322 s->cc_op = CC_OP_SUBB + ot;
3323 }
3324 break;
3325 case 0x6c: /* insS */
3326 case 0x6d:
f115e911
FB
3327 if ((b & 1) == 0)
3328 ot = OT_BYTE;
3329 else
3330 ot = dflag ? OT_LONG : OT_WORD;
3331 gen_check_io(s, ot, 1, pc_start - s->cs_base);
3332 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
3333 gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
2c0262af 3334 } else {
f115e911 3335 gen_ins(s, ot);
2c0262af
FB
3336 }
3337 break;
3338 case 0x6e: /* outsS */
3339 case 0x6f:
f115e911
FB
3340 if ((b & 1) == 0)
3341 ot = OT_BYTE;
3342 else
3343 ot = dflag ? OT_LONG : OT_WORD;
3344 gen_check_io(s, ot, 1, pc_start - s->cs_base);
3345 if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
3346 gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
2c0262af 3347 } else {
f115e911 3348 gen_outs(s, ot);
2c0262af
FB
3349 }
3350 break;
3351
3352 /************************/
3353 /* port I/O */
3354 case 0xe4:
3355 case 0xe5:
f115e911
FB
3356 if ((b & 1) == 0)
3357 ot = OT_BYTE;
3358 else
3359 ot = dflag ? OT_LONG : OT_WORD;
3360 val = ldub_code(s->pc++);
3361 gen_op_movl_T0_im(val);
3362 gen_check_io(s, ot, 0, pc_start - s->cs_base);
3363 gen_op_in[ot]();
3364 gen_op_mov_reg_T1[ot][R_EAX]();
2c0262af
FB
3365 break;
3366 case 0xe6:
3367 case 0xe7:
f115e911
FB
3368 if ((b & 1) == 0)
3369 ot = OT_BYTE;
3370 else
3371 ot = dflag ? OT_LONG : OT_WORD;
3372 val = ldub_code(s->pc++);
3373 gen_op_movl_T0_im(val);
3374 gen_check_io(s, ot, 0, pc_start - s->cs_base);
3375 gen_op_mov_TN_reg[ot][1][R_EAX]();
3376 gen_op_out[ot]();
2c0262af
FB
3377 break;
3378 case 0xec:
3379 case 0xed:
f115e911
FB
3380 if ((b & 1) == 0)
3381 ot = OT_BYTE;
3382 else
3383 ot = dflag ? OT_LONG : OT_WORD;
3384 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
4f31916f 3385 gen_op_andl_T0_ffff();
f115e911
FB
3386 gen_check_io(s, ot, 0, pc_start - s->cs_base);
3387 gen_op_in[ot]();
3388 gen_op_mov_reg_T1[ot][R_EAX]();
2c0262af
FB
3389 break;
3390 case 0xee:
3391 case 0xef:
f115e911
FB
3392 if ((b & 1) == 0)
3393 ot = OT_BYTE;
3394 else
3395 ot = dflag ? OT_LONG : OT_WORD;
3396 gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
4f31916f 3397 gen_op_andl_T0_ffff();
f115e911
FB
3398 gen_check_io(s, ot, 0, pc_start - s->cs_base);
3399 gen_op_mov_TN_reg[ot][1][R_EAX]();
3400 gen_op_out[ot]();
2c0262af
FB
3401 break;
3402
3403 /************************/
3404 /* control */
3405 case 0xc2: /* ret im */
61382a50 3406 val = ldsw_code(s->pc);
2c0262af
FB
3407 s->pc += 2;
3408 gen_pop_T0(s);
3409 gen_stack_update(s, val + (2 << s->dflag));
3410 if (s->dflag == 0)
3411 gen_op_andl_T0_ffff();
3412 gen_op_jmp_T0();
3413 gen_eob(s);
3414 break;
3415 case 0xc3: /* ret */
3416 gen_pop_T0(s);
3417 gen_pop_update(s);
3418 if (s->dflag == 0)
3419 gen_op_andl_T0_ffff();
3420 gen_op_jmp_T0();
3421 gen_eob(s);
3422 break;
3423 case 0xca: /* lret im */
61382a50 3424 val = ldsw_code(s->pc);
2c0262af
FB
3425 s->pc += 2;
3426 do_lret:
3427 if (s->pe && !s->vm86) {
3428 if (s->cc_op != CC_OP_DYNAMIC)
3429 gen_op_set_cc_op(s->cc_op);
3430 gen_op_jmp_im(pc_start - s->cs_base);
3431 gen_op_lret_protected(s->dflag, val);
3432 } else {
3433 gen_stack_A0(s);
3434 /* pop offset */
3435 gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
3436 if (s->dflag == 0)
3437 gen_op_andl_T0_ffff();
3438 /* NOTE: keeping EIP updated is not a problem in case of
3439 exception */
3440 gen_op_jmp_T0();
3441 /* pop selector */
3442 gen_op_addl_A0_im(2 << s->dflag);
3443 gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
3444 gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
3445 /* add stack offset */
3446 gen_stack_update(s, val + (4 << s->dflag));
3447 }
3448 gen_eob(s);
3449 break;
3450 case 0xcb: /* lret */
3451 val = 0;
3452 goto do_lret;
3453 case 0xcf: /* iret */
3454 if (!s->pe) {
3455 /* real mode */
3456 gen_op_iret_real(s->dflag);
3457 s->cc_op = CC_OP_EFLAGS;
f115e911
FB
3458 } else if (s->vm86) {
3459 if (s->iopl != 3) {
3460 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3461 } else {
3462 gen_op_iret_real(s->dflag);
3463 s->cc_op = CC_OP_EFLAGS;
3464 }
2c0262af
FB
3465 } else {
3466 if (s->cc_op != CC_OP_DYNAMIC)
3467 gen_op_set_cc_op(s->cc_op);
3468 gen_op_jmp_im(pc_start - s->cs_base);
08cea4ee 3469 gen_op_iret_protected(s->dflag, s->pc - s->cs_base);
2c0262af
FB
3470 s->cc_op = CC_OP_EFLAGS;
3471 }
3472 gen_eob(s);
3473 break;
3474 case 0xe8: /* call im */
3475 {
3476 unsigned int next_eip;
3477 ot = dflag ? OT_LONG : OT_WORD;
3478 val = insn_get(s, ot);
3479 next_eip = s->pc - s->cs_base;
3480 val += next_eip;
3481 if (s->dflag == 0)
3482 val &= 0xffff;
3483 gen_op_movl_T0_im(next_eip);
3484 gen_push_T0(s);
3485 gen_jmp(s, val);
3486 }
3487 break;
3488 case 0x9a: /* lcall im */
3489 {
3490 unsigned int selector, offset;
3491
3492 ot = dflag ? OT_LONG : OT_WORD;
3493 offset = insn_get(s, ot);
3494 selector = insn_get(s, OT_WORD);
3495
3496 gen_op_movl_T0_im(selector);
3497 gen_op_movl_T1_im(offset);
3498 }
3499 goto do_lcall;
3500 case 0xe9: /* jmp */
3501 ot = dflag ? OT_LONG : OT_WORD;
3502 val = insn_get(s, ot);
3503 val += s->pc - s->cs_base;
3504 if (s->dflag == 0)
3505 val = val & 0xffff;
3506 gen_jmp(s, val);
3507 break;
3508 case 0xea: /* ljmp im */
3509 {
3510 unsigned int selector, offset;
3511
3512 ot = dflag ? OT_LONG : OT_WORD;
3513 offset = insn_get(s, ot);
3514 selector = insn_get(s, OT_WORD);
3515
3516 gen_op_movl_T0_im(selector);
3517 gen_op_movl_T1_im(offset);
3518 }
3519 goto do_ljmp;
3520 case 0xeb: /* jmp Jb */
3521 val = (int8_t)insn_get(s, OT_BYTE);
3522 val += s->pc - s->cs_base;
3523 if (s->dflag == 0)
3524 val = val & 0xffff;
3525 gen_jmp(s, val);
3526 break;
3527 case 0x70 ... 0x7f: /* jcc Jb */
3528 val = (int8_t)insn_get(s, OT_BYTE);
3529 goto do_jcc;
3530 case 0x180 ... 0x18f: /* jcc Jv */
3531 if (dflag) {
3532 val = insn_get(s, OT_LONG);
3533 } else {
3534 val = (int16_t)insn_get(s, OT_WORD);
3535 }
3536 do_jcc:
3537 next_eip = s->pc - s->cs_base;
3538 val += next_eip;
3539 if (s->dflag == 0)
3540 val &= 0xffff;
3541 gen_jcc(s, b, val, next_eip);
3542 break;
3543
3544 case 0x190 ... 0x19f: /* setcc Gv */
61382a50 3545 modrm = ldub_code(s->pc++);
2c0262af
FB
3546 gen_setcc(s, b);
3547 gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
3548 break;
3549 case 0x140 ... 0x14f: /* cmov Gv, Ev */
3550 ot = dflag ? OT_LONG : OT_WORD;
61382a50 3551 modrm = ldub_code(s->pc++);
2c0262af
FB
3552 reg = (modrm >> 3) & 7;
3553 mod = (modrm >> 6) & 3;
3554 gen_setcc(s, b);
3555 if (mod != 3) {
3556 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3557 gen_op_ld_T1_A0[ot + s->mem_index]();
3558 } else {
3559 rm = modrm & 7;
3560 gen_op_mov_TN_reg[ot][1][rm]();
3561 }
3562 gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
3563 break;
3564
3565 /************************/
3566 /* flags */
3567 case 0x9c: /* pushf */
3568 if (s->vm86 && s->iopl != 3) {
3569 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3570 } else {
3571 if (s->cc_op != CC_OP_DYNAMIC)
3572 gen_op_set_cc_op(s->cc_op);
3573 gen_op_movl_T0_eflags();
3574 gen_push_T0(s);
3575 }
3576 break;
3577 case 0x9d: /* popf */
3578 if (s->vm86 && s->iopl != 3) {
3579 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3580 } else {
3581 gen_pop_T0(s);
3582 if (s->cpl == 0) {
3583 if (s->dflag) {
3584 gen_op_movl_eflags_T0_cpl0();
3585 } else {
3586 gen_op_movw_eflags_T0_cpl0();
3587 }
3588 } else {
4136f33c
FB
3589 if (s->cpl <= s->iopl) {
3590 if (s->dflag) {
3591 gen_op_movl_eflags_T0_io();
3592 } else {
3593 gen_op_movw_eflags_T0_io();
3594 }
2c0262af 3595 } else {
4136f33c
FB
3596 if (s->dflag) {
3597 gen_op_movl_eflags_T0();
3598 } else {
3599 gen_op_movw_eflags_T0();
3600 }
2c0262af
FB
3601 }
3602 }
3603 gen_pop_update(s);
3604 s->cc_op = CC_OP_EFLAGS;
3605 /* abort translation because TF flag may change */
3606 gen_op_jmp_im(s->pc - s->cs_base);
3607 gen_eob(s);
3608 }
3609 break;
3610 case 0x9e: /* sahf */
3611 gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();
3612 if (s->cc_op != CC_OP_DYNAMIC)
3613 gen_op_set_cc_op(s->cc_op);
3614 gen_op_movb_eflags_T0();
3615 s->cc_op = CC_OP_EFLAGS;
3616 break;
3617 case 0x9f: /* lahf */
3618 if (s->cc_op != CC_OP_DYNAMIC)
3619 gen_op_set_cc_op(s->cc_op);
3620 gen_op_movl_T0_eflags();
3621 gen_op_mov_reg_T0[OT_BYTE][R_AH]();
3622 break;
3623 case 0xf5: /* cmc */
3624 if (s->cc_op != CC_OP_DYNAMIC)
3625 gen_op_set_cc_op(s->cc_op);
3626 gen_op_cmc();
3627 s->cc_op = CC_OP_EFLAGS;
3628 break;
3629 case 0xf8: /* clc */
3630 if (s->cc_op != CC_OP_DYNAMIC)
3631 gen_op_set_cc_op(s->cc_op);
3632 gen_op_clc();
3633 s->cc_op = CC_OP_EFLAGS;
3634 break;
3635 case 0xf9: /* stc */
3636 if (s->cc_op != CC_OP_DYNAMIC)
3637 gen_op_set_cc_op(s->cc_op);
3638 gen_op_stc();
3639 s->cc_op = CC_OP_EFLAGS;
3640 break;
3641 case 0xfc: /* cld */
3642 gen_op_cld();
3643 break;
3644 case 0xfd: /* std */
3645 gen_op_std();
3646 break;
3647
3648 /************************/
3649 /* bit operations */
3650 case 0x1ba: /* bt/bts/btr/btc Gv, im */
3651 ot = dflag ? OT_LONG : OT_WORD;
61382a50 3652 modrm = ldub_code(s->pc++);
2c0262af
FB
3653 op = (modrm >> 3) & 7;
3654 mod = (modrm >> 6) & 3;
3655 rm = modrm & 7;
3656 if (mod != 3) {
3657 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3658 gen_op_ld_T0_A0[ot + s->mem_index]();
3659 } else {
3660 gen_op_mov_TN_reg[ot][0][rm]();
3661 }
3662 /* load shift */
61382a50 3663 val = ldub_code(s->pc++);
2c0262af
FB
3664 gen_op_movl_T1_im(val);
3665 if (op < 4)
3666 goto illegal_op;
3667 op -= 4;
3668 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
3669 s->cc_op = CC_OP_SARB + ot;
3670 if (op != 0) {
3671 if (mod != 3)
3672 gen_op_st_T0_A0[ot + s->mem_index]();
3673 else
3674 gen_op_mov_reg_T0[ot][rm]();
3675 gen_op_update_bt_cc();
3676 }
3677 break;
3678 case 0x1a3: /* bt Gv, Ev */
3679 op = 0;
3680 goto do_btx;
3681 case 0x1ab: /* bts */
3682 op = 1;
3683 goto do_btx;
3684 case 0x1b3: /* btr */
3685 op = 2;
3686 goto do_btx;
3687 case 0x1bb: /* btc */
3688 op = 3;
3689 do_btx:
3690 ot = dflag ? OT_LONG : OT_WORD;
61382a50 3691 modrm = ldub_code(s->pc++);
2c0262af
FB
3692 reg = (modrm >> 3) & 7;
3693 mod = (modrm >> 6) & 3;
3694 rm = modrm & 7;
3695 gen_op_mov_TN_reg[OT_LONG][1][reg]();
3696 if (mod != 3) {
3697 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3698 /* specific case: we need to add a displacement */
3699 if (ot == OT_WORD)
3700 gen_op_add_bitw_A0_T1();
3701 else
3702 gen_op_add_bitl_A0_T1();
3703 gen_op_ld_T0_A0[ot + s->mem_index]();
3704 } else {
3705 gen_op_mov_TN_reg[ot][0][rm]();
3706 }
3707 gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
3708 s->cc_op = CC_OP_SARB + ot;
3709 if (op != 0) {
3710 if (mod != 3)
3711 gen_op_st_T0_A0[ot + s->mem_index]();
3712 else
3713 gen_op_mov_reg_T0[ot][rm]();
3714 gen_op_update_bt_cc();
3715 }
3716 break;
3717 case 0x1bc: /* bsf */
3718 case 0x1bd: /* bsr */
3719 ot = dflag ? OT_LONG : OT_WORD;
61382a50 3720 modrm = ldub_code(s->pc++);
2c0262af
FB
3721 reg = (modrm >> 3) & 7;
3722 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
686f3f26
FB
3723 /* NOTE: in order to handle the 0 case, we must load the
3724 result. It could be optimized with a generated jump */
3725 gen_op_mov_TN_reg[ot][1][reg]();
2c0262af 3726 gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
686f3f26 3727 gen_op_mov_reg_T1[ot][reg]();
2c0262af
FB
3728 s->cc_op = CC_OP_LOGICB + ot;
3729 break;
3730 /************************/
3731 /* bcd */
3732 case 0x27: /* daa */
3733 if (s->cc_op != CC_OP_DYNAMIC)
3734 gen_op_set_cc_op(s->cc_op);
3735 gen_op_daa();
3736 s->cc_op = CC_OP_EFLAGS;
3737 break;
3738 case 0x2f: /* das */
3739 if (s->cc_op != CC_OP_DYNAMIC)
3740 gen_op_set_cc_op(s->cc_op);
3741 gen_op_das();
3742 s->cc_op = CC_OP_EFLAGS;
3743 break;
3744 case 0x37: /* aaa */
3745 if (s->cc_op != CC_OP_DYNAMIC)
3746 gen_op_set_cc_op(s->cc_op);
3747 gen_op_aaa();
3748 s->cc_op = CC_OP_EFLAGS;
3749 break;
3750 case 0x3f: /* aas */
3751 if (s->cc_op != CC_OP_DYNAMIC)
3752 gen_op_set_cc_op(s->cc_op);
3753 gen_op_aas();
3754 s->cc_op = CC_OP_EFLAGS;
3755 break;
3756 case 0xd4: /* aam */
61382a50 3757 val = ldub_code(s->pc++);
2c0262af
FB
3758 gen_op_aam(val);
3759 s->cc_op = CC_OP_LOGICB;
3760 break;
3761 case 0xd5: /* aad */
61382a50 3762 val = ldub_code(s->pc++);
2c0262af
FB
3763 gen_op_aad(val);
3764 s->cc_op = CC_OP_LOGICB;
3765 break;
3766 /************************/
3767 /* misc */
3768 case 0x90: /* nop */
ab1f142b
FB
3769 /* XXX: correct lock test for all insn */
3770 if (prefixes & PREFIX_LOCK)
3771 goto illegal_op;
2c0262af
FB
3772 break;
3773 case 0x9b: /* fwait */
7eee2a50
FB
3774 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
3775 (HF_MP_MASK | HF_TS_MASK)) {
3776 gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
2ee73ac3
FB
3777 } else {
3778 if (s->cc_op != CC_OP_DYNAMIC)
3779 gen_op_set_cc_op(s->cc_op);
3780 gen_op_jmp_im(pc_start - s->cs_base);
3781 gen_op_fwait();
7eee2a50 3782 }
2c0262af
FB
3783 break;
3784 case 0xcc: /* int3 */
3785 gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
3786 break;
3787 case 0xcd: /* int N */
61382a50 3788 val = ldub_code(s->pc++);
f115e911 3789 if (s->vm86 && s->iopl != 3) {
2c0262af 3790 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
f115e911
FB
3791 } else {
3792 gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
3793 }
2c0262af
FB
3794 break;
3795 case 0xce: /* into */
3796 if (s->cc_op != CC_OP_DYNAMIC)
3797 gen_op_set_cc_op(s->cc_op);
3798 gen_op_into(s->pc - s->cs_base);
3799 break;
3800 case 0xf1: /* icebp (undocumented, exits to external debugger) */
3801 gen_debug(s, pc_start - s->cs_base);
3802 break;
3803 case 0xfa: /* cli */
3804 if (!s->vm86) {
3805 if (s->cpl <= s->iopl) {
3806 gen_op_cli();
3807 } else {
3808 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3809 }
3810 } else {
3811 if (s->iopl == 3) {
3812 gen_op_cli();
3813 } else {
3814 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3815 }
3816 }
3817 break;
3818 case 0xfb: /* sti */
3819 if (!s->vm86) {
3820 if (s->cpl <= s->iopl) {
3821 gen_sti:
3822 gen_op_sti();
3823 /* interruptions are enabled only the first insn after sti */
a2cc3b24
FB
3824 /* If several instructions disable interrupts, only the
3825 _first_ does it */
3826 if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
3827 gen_op_set_inhibit_irq();
2c0262af
FB
3828 /* give a chance to handle pending irqs */
3829 gen_op_jmp_im(s->pc - s->cs_base);
3830 gen_eob(s);
3831 } else {
3832 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3833 }
3834 } else {
3835 if (s->iopl == 3) {
3836 goto gen_sti;
3837 } else {
3838 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3839 }
3840 }
3841 break;
3842 case 0x62: /* bound */
3843 ot = dflag ? OT_LONG : OT_WORD;
61382a50 3844 modrm = ldub_code(s->pc++);
2c0262af
FB
3845 reg = (modrm >> 3) & 7;
3846 mod = (modrm >> 6) & 3;
3847 if (mod == 3)
3848 goto illegal_op;
cabf23c3 3849 gen_op_mov_TN_reg[ot][0][reg]();
2c0262af
FB
3850 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
3851 if (ot == OT_WORD)
3852 gen_op_boundw(pc_start - s->cs_base);
3853 else
3854 gen_op_boundl(pc_start - s->cs_base);
3855 break;
3856 case 0x1c8 ... 0x1cf: /* bswap reg */
3857 reg = b & 7;
3858 gen_op_mov_TN_reg[OT_LONG][0][reg]();
3859 gen_op_bswapl_T0();
3860 gen_op_mov_reg_T0[OT_LONG][reg]();
3861 break;
3862 case 0xd6: /* salc */
3863 if (s->cc_op != CC_OP_DYNAMIC)
3864 gen_op_set_cc_op(s->cc_op);
3865 gen_op_salc();
3866 break;
3867 case 0xe0: /* loopnz */
3868 case 0xe1: /* loopz */
3869 if (s->cc_op != CC_OP_DYNAMIC)
3870 gen_op_set_cc_op(s->cc_op);
3871 /* FALL THRU */
3872 case 0xe2: /* loop */
3873 case 0xe3: /* jecxz */
3874 val = (int8_t)insn_get(s, OT_BYTE);
3875 next_eip = s->pc - s->cs_base;
3876 val += next_eip;
3877 if (s->dflag == 0)
3878 val &= 0xffff;
3879 gen_op_loop[s->aflag][b & 3](val, next_eip);
3880 gen_eob(s);
3881 break;
3882 case 0x130: /* wrmsr */
3883 case 0x132: /* rdmsr */
3884 if (s->cpl != 0) {
3885 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3886 } else {
3887 if (b & 2)
3888 gen_op_rdmsr();
3889 else
3890 gen_op_wrmsr();
3891 }
3892 break;
3893 case 0x131: /* rdtsc */
3894 gen_op_rdtsc();
3895 break;
023fe10d
FB
3896 case 0x134: /* sysenter */
3897 if (!s->pe) {
3898 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3899 } else {
3900 if (s->cc_op != CC_OP_DYNAMIC) {
3901 gen_op_set_cc_op(s->cc_op);
3902 s->cc_op = CC_OP_DYNAMIC;
3903 }
3904 gen_op_jmp_im(pc_start - s->cs_base);
3905 gen_op_sysenter();
3906 gen_eob(s);
3907 }
3908 break;
3909 case 0x135: /* sysexit */
3910 if (!s->pe) {
3911 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3912 } else {
3913 if (s->cc_op != CC_OP_DYNAMIC) {
3914 gen_op_set_cc_op(s->cc_op);
3915 s->cc_op = CC_OP_DYNAMIC;
3916 }
3917 gen_op_jmp_im(pc_start - s->cs_base);
3918 gen_op_sysexit();
3919 gen_eob(s);
3920 }
3921 break;
2c0262af
FB
3922 case 0x1a2: /* cpuid */
3923 gen_op_cpuid();
3924 break;
3925 case 0xf4: /* hlt */
3926 if (s->cpl != 0) {
3927 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3928 } else {
3929 if (s->cc_op != CC_OP_DYNAMIC)
3930 gen_op_set_cc_op(s->cc_op);
3931 gen_op_jmp_im(s->pc - s->cs_base);
3932 gen_op_hlt();
3933 s->is_jmp = 3;
3934 }
3935 break;
3936 case 0x100:
61382a50 3937 modrm = ldub_code(s->pc++);
2c0262af
FB
3938 mod = (modrm >> 6) & 3;
3939 op = (modrm >> 3) & 7;
3940 switch(op) {
3941 case 0: /* sldt */
f115e911
FB
3942 if (!s->pe || s->vm86)
3943 goto illegal_op;
2c0262af
FB
3944 gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
3945 ot = OT_WORD;
3946 if (mod == 3)
3947 ot += s->dflag;
3948 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
3949 break;
3950 case 2: /* lldt */
f115e911
FB
3951 if (!s->pe || s->vm86)
3952 goto illegal_op;
2c0262af
FB
3953 if (s->cpl != 0) {
3954 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3955 } else {
3956 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3957 gen_op_jmp_im(pc_start - s->cs_base);
3958 gen_op_lldt_T0();
3959 }
3960 break;
3961 case 1: /* str */
f115e911
FB
3962 if (!s->pe || s->vm86)
3963 goto illegal_op;
2c0262af
FB
3964 gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
3965 ot = OT_WORD;
3966 if (mod == 3)
3967 ot += s->dflag;
3968 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
3969 break;
3970 case 3: /* ltr */
f115e911
FB
3971 if (!s->pe || s->vm86)
3972 goto illegal_op;
2c0262af
FB
3973 if (s->cpl != 0) {
3974 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3975 } else {
3976 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3977 gen_op_jmp_im(pc_start - s->cs_base);
3978 gen_op_ltr_T0();
3979 }
3980 break;
3981 case 4: /* verr */
3982 case 5: /* verw */
f115e911
FB
3983 if (!s->pe || s->vm86)
3984 goto illegal_op;
3985 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3986 if (s->cc_op != CC_OP_DYNAMIC)
3987 gen_op_set_cc_op(s->cc_op);
3988 if (op == 4)
3989 gen_op_verr();
3990 else
3991 gen_op_verw();
3992 s->cc_op = CC_OP_EFLAGS;
3993 break;
2c0262af
FB
3994 default:
3995 goto illegal_op;
3996 }
3997 break;
3998 case 0x101:
61382a50 3999 modrm = ldub_code(s->pc++);
2c0262af
FB
4000 mod = (modrm >> 6) & 3;
4001 op = (modrm >> 3) & 7;
4002 switch(op) {
4003 case 0: /* sgdt */
4004 case 1: /* sidt */
4005 if (mod == 3)
4006 goto illegal_op;
4007 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
4008 if (op == 0)
4009 gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit));
4010 else
4011 gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit));
4012 gen_op_st_T0_A0[OT_WORD + s->mem_index]();
4013 gen_op_addl_A0_im(2);
4014 if (op == 0)
4015 gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base));
4016 else
4017 gen_op_movl_T0_env(offsetof(CPUX86State,idt.base));
4018 if (!s->dflag)
4019 gen_op_andl_T0_im(0xffffff);
4020 gen_op_st_T0_A0[OT_LONG + s->mem_index]();
4021 break;
4022 case 2: /* lgdt */
4023 case 3: /* lidt */
4024 if (mod == 3)
4025 goto illegal_op;
4026 if (s->cpl != 0) {
4027 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4028 } else {
4029 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
4030 gen_op_ld_T1_A0[OT_WORD + s->mem_index]();
4031 gen_op_addl_A0_im(2);
4032 gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
4033 if (!s->dflag)
4034 gen_op_andl_T0_im(0xffffff);
4035 if (op == 2) {
4036 gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base));
4037 gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit));
4038 } else {
4039 gen_op_movl_env_T0(offsetof(CPUX86State,idt.base));
4040 gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit));
4041 }
4042 }
4043 break;
4044 case 4: /* smsw */
4045 gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
4046 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
4047 break;
4048 case 6: /* lmsw */
4049 if (s->cpl != 0) {
4050 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4051 } else {
4052 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
4053 gen_op_lmsw_T0();
d71b9a8b
FB
4054 gen_op_jmp_im(s->pc - s->cs_base);
4055 gen_eob(s);
2c0262af
FB
4056 }
4057 break;
4058 case 7: /* invlpg */
4059 if (s->cpl != 0) {
4060 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4061 } else {
4062 if (mod == 3)
4063 goto illegal_op;
4064 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
4065 gen_op_invlpg_A0();
3415a4dd
FB
4066 gen_op_jmp_im(s->pc - s->cs_base);
4067 gen_eob(s);
2c0262af
FB
4068 }
4069 break;
4070 default:
4071 goto illegal_op;
4072 }
4073 break;
3415a4dd
FB
4074 case 0x108: /* invd */
4075 case 0x109: /* wbinvd */
4076 if (s->cpl != 0) {
4077 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4078 } else {
4079 /* nothing to do */
4080 }
4081 break;
f115e911
FB
4082 case 0x63: /* arpl */
4083 if (!s->pe || s->vm86)
4084 goto illegal_op;
4085 ot = dflag ? OT_LONG : OT_WORD;
4086 modrm = ldub_code(s->pc++);
4087 reg = (modrm >> 3) & 7;
4088 mod = (modrm >> 6) & 3;
4089 rm = modrm & 7;
4090 if (mod != 3) {
4091 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
4092 gen_op_ld_T0_A0[ot + s->mem_index]();
4093 } else {
4094 gen_op_mov_TN_reg[ot][0][rm]();
4095 }
4096 if (s->cc_op != CC_OP_DYNAMIC)
4097 gen_op_set_cc_op(s->cc_op);
4098 gen_op_arpl();
4099 s->cc_op = CC_OP_EFLAGS;
4100 if (mod != 3) {
4101 gen_op_st_T0_A0[ot + s->mem_index]();
4102 } else {
4103 gen_op_mov_reg_T0[ot][rm]();
4104 }
4105 gen_op_arpl_update();
4106 break;
2c0262af
FB
4107 case 0x102: /* lar */
4108 case 0x103: /* lsl */
4109 if (!s->pe || s->vm86)
4110 goto illegal_op;
4111 ot = dflag ? OT_LONG : OT_WORD;
61382a50 4112 modrm = ldub_code(s->pc++);
2c0262af
FB
4113 reg = (modrm >> 3) & 7;
4114 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
4115 gen_op_mov_TN_reg[ot][1][reg]();
4116 if (s->cc_op != CC_OP_DYNAMIC)
4117 gen_op_set_cc_op(s->cc_op);
4118 if (b == 0x102)
4119 gen_op_lar();
4120 else
4121 gen_op_lsl();
4122 s->cc_op = CC_OP_EFLAGS;
4123 gen_op_mov_reg_T1[ot][reg]();
4124 break;
4125 case 0x118:
61382a50 4126 modrm = ldub_code(s->pc++);
2c0262af
FB
4127 mod = (modrm >> 6) & 3;
4128 op = (modrm >> 3) & 7;
4129 switch(op) {
4130 case 0: /* prefetchnta */
4131 case 1: /* prefetchnt0 */
4132 case 2: /* prefetchnt0 */
4133 case 3: /* prefetchnt0 */
4134 if (mod == 3)
4135 goto illegal_op;
4136 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
4137 /* nothing more to do */
4138 break;
4139 default:
4140 goto illegal_op;
4141 }
4142 break;
4143 case 0x120: /* mov reg, crN */
4144 case 0x122: /* mov crN, reg */
4145 if (s->cpl != 0) {
4146 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4147 } else {
61382a50 4148 modrm = ldub_code(s->pc++);
2c0262af
FB
4149 if ((modrm & 0xc0) != 0xc0)
4150 goto illegal_op;
4151 rm = modrm & 7;
4152 reg = (modrm >> 3) & 7;
4153 switch(reg) {
4154 case 0:
4155 case 2:
4156 case 3:
4157 case 4:
4158 if (b & 2) {
4159 gen_op_mov_TN_reg[OT_LONG][0][rm]();
4160 gen_op_movl_crN_T0(reg);
4161 gen_op_jmp_im(s->pc - s->cs_base);
4162 gen_eob(s);
4163 } else {
4164 gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg]));
4165 gen_op_mov_reg_T0[OT_LONG][rm]();
4166 }
4167 break;
4168 default:
4169 goto illegal_op;
4170 }
4171 }
4172 break;
4173 case 0x121: /* mov reg, drN */
4174 case 0x123: /* mov drN, reg */
4175 if (s->cpl != 0) {
4176 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4177 } else {
61382a50 4178 modrm = ldub_code(s->pc++);
2c0262af
FB
4179 if ((modrm & 0xc0) != 0xc0)
4180 goto illegal_op;
4181 rm = modrm & 7;
4182 reg = (modrm >> 3) & 7;
4183 /* XXX: do it dynamically with CR4.DE bit */
4184 if (reg == 4 || reg == 5)
4185 goto illegal_op;
4186 if (b & 2) {
4187 gen_op_mov_TN_reg[OT_LONG][0][rm]();
4188 gen_op_movl_drN_T0(reg);
4189 gen_op_jmp_im(s->pc - s->cs_base);
4190 gen_eob(s);
4191 } else {
4192 gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg]));
4193 gen_op_mov_reg_T0[OT_LONG][rm]();
4194 }
4195 }
4196 break;
4197 case 0x106: /* clts */
4198 if (s->cpl != 0) {
4199 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
4200 } else {
4201 gen_op_clts();
7eee2a50
FB
4202 /* abort block because static cpu state changed */
4203 gen_op_jmp_im(s->pc - s->cs_base);
4204 gen_eob(s);
2c0262af
FB
4205 }
4206 break;
4207 default:
4208 goto illegal_op;
4209 }
4210 /* lock generation */
4211 if (s->prefix & PREFIX_LOCK)
4212 gen_op_unlock();
4213 return s->pc;
4214 illegal_op:
ab1f142b
FB
4215 if (s->prefix & PREFIX_LOCK)
4216 gen_op_unlock();
2c0262af
FB
4217 /* XXX: ensure that no lock was generated */
4218 gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
4219 return s->pc;
4220}
4221
4222#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
4223#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
4224
4225/* flags read by an operation */
4226static uint16_t opc_read_flags[NB_OPS] = {
4227 [INDEX_op_aas] = CC_A,
4228 [INDEX_op_aaa] = CC_A,
4229 [INDEX_op_das] = CC_A | CC_C,
4230 [INDEX_op_daa] = CC_A | CC_C,
4231
2c0262af
FB
4232 /* subtle: due to the incl/decl implementation, C is used */
4233 [INDEX_op_update_inc_cc] = CC_C,
4234
4235 [INDEX_op_into] = CC_O,
4236
4237 [INDEX_op_jb_subb] = CC_C,
4238 [INDEX_op_jb_subw] = CC_C,
4239 [INDEX_op_jb_subl] = CC_C,
4240
4241 [INDEX_op_jz_subb] = CC_Z,
4242 [INDEX_op_jz_subw] = CC_Z,
4243 [INDEX_op_jz_subl] = CC_Z,
4244
4245 [INDEX_op_jbe_subb] = CC_Z | CC_C,
4246 [INDEX_op_jbe_subw] = CC_Z | CC_C,
4247 [INDEX_op_jbe_subl] = CC_Z | CC_C,
4248
4249 [INDEX_op_js_subb] = CC_S,
4250 [INDEX_op_js_subw] = CC_S,
4251 [INDEX_op_js_subl] = CC_S,
4252
4253 [INDEX_op_jl_subb] = CC_O | CC_S,
4254 [INDEX_op_jl_subw] = CC_O | CC_S,
4255 [INDEX_op_jl_subl] = CC_O | CC_S,
4256
4257 [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z,
4258 [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z,
4259 [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z,
4260
4261 [INDEX_op_loopnzw] = CC_Z,
4262 [INDEX_op_loopnzl] = CC_Z,
4263 [INDEX_op_loopzw] = CC_Z,
4264 [INDEX_op_loopzl] = CC_Z,
4265
4266 [INDEX_op_seto_T0_cc] = CC_O,
4267 [INDEX_op_setb_T0_cc] = CC_C,
4268 [INDEX_op_setz_T0_cc] = CC_Z,
4269 [INDEX_op_setbe_T0_cc] = CC_Z | CC_C,
4270 [INDEX_op_sets_T0_cc] = CC_S,
4271 [INDEX_op_setp_T0_cc] = CC_P,
4272 [INDEX_op_setl_T0_cc] = CC_O | CC_S,
4273 [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z,
4274
4275 [INDEX_op_setb_T0_subb] = CC_C,
4276 [INDEX_op_setb_T0_subw] = CC_C,
4277 [INDEX_op_setb_T0_subl] = CC_C,
4278
4279 [INDEX_op_setz_T0_subb] = CC_Z,
4280 [INDEX_op_setz_T0_subw] = CC_Z,
4281 [INDEX_op_setz_T0_subl] = CC_Z,
4282
4283 [INDEX_op_setbe_T0_subb] = CC_Z | CC_C,
4284 [INDEX_op_setbe_T0_subw] = CC_Z | CC_C,
4285 [INDEX_op_setbe_T0_subl] = CC_Z | CC_C,
4286
4287 [INDEX_op_sets_T0_subb] = CC_S,
4288 [INDEX_op_sets_T0_subw] = CC_S,
4289 [INDEX_op_sets_T0_subl] = CC_S,
4290
4291 [INDEX_op_setl_T0_subb] = CC_O | CC_S,
4292 [INDEX_op_setl_T0_subw] = CC_O | CC_S,
4293 [INDEX_op_setl_T0_subl] = CC_O | CC_S,
4294
4295 [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z,
4296 [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z,
4297 [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
4298
4299 [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
4300 [INDEX_op_cmc] = CC_C,
4301 [INDEX_op_salc] = CC_C,
4302
7399c5a9
FB
4303 /* needed for correct flag optimisation before string ops */
4304 [INDEX_op_jz_ecxw] = CC_OSZAPC,
4305 [INDEX_op_jz_ecxl] = CC_OSZAPC,
4306 [INDEX_op_jz_ecxw_im] = CC_OSZAPC,
4307 [INDEX_op_jz_ecxl_im] = CC_OSZAPC,
4308
4f31916f
FB
4309#define DEF_READF(SUFFIX)\
4310 [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\
4311 [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\
4312 [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\
4313 [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\
4314 [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\
4315 [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\
4316\
4317 [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\
4318 [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\
4319 [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\
4320 [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\
4321 [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\
4322 [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,
4323
4324
4bb2fcc7 4325 DEF_READF( )
4f31916f
FB
4326 DEF_READF(_raw)
4327#ifndef CONFIG_USER_ONLY
4328 DEF_READF(_kernel)
4329 DEF_READF(_user)
4330#endif
2c0262af
FB
4331};
4332
4333/* flags written by an operation */
4334static uint16_t opc_write_flags[NB_OPS] = {
4335 [INDEX_op_update2_cc] = CC_OSZAPC,
4336 [INDEX_op_update1_cc] = CC_OSZAPC,
4337 [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
4338 [INDEX_op_update_neg_cc] = CC_OSZAPC,
4339 /* subtle: due to the incl/decl implementation, C is used */
4340 [INDEX_op_update_inc_cc] = CC_OSZAPC,
4341 [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
4342
2c0262af
FB
4343 [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
4344 [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
4345 [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
4346 [INDEX_op_imulw_AX_T0] = CC_OSZAPC,
4347 [INDEX_op_mull_EAX_T0] = CC_OSZAPC,
4348 [INDEX_op_imull_EAX_T0] = CC_OSZAPC,
4349 [INDEX_op_imulw_T0_T1] = CC_OSZAPC,
4350 [INDEX_op_imull_T0_T1] = CC_OSZAPC,
4351
4352 /* bcd */
4353 [INDEX_op_aam] = CC_OSZAPC,
4354 [INDEX_op_aad] = CC_OSZAPC,
4355 [INDEX_op_aas] = CC_OSZAPC,
4356 [INDEX_op_aaa] = CC_OSZAPC,
4357 [INDEX_op_das] = CC_OSZAPC,
4358 [INDEX_op_daa] = CC_OSZAPC,
4359
4360 [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
4361 [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
4362 [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
4136f33c
FB
4363 [INDEX_op_movw_eflags_T0_io] = CC_OSZAPC,
4364 [INDEX_op_movl_eflags_T0_io] = CC_OSZAPC,
4365 [INDEX_op_movw_eflags_T0_cpl0] = CC_OSZAPC,
4366 [INDEX_op_movl_eflags_T0_cpl0] = CC_OSZAPC,
2c0262af
FB
4367 [INDEX_op_clc] = CC_C,
4368 [INDEX_op_stc] = CC_C,
4369 [INDEX_op_cmc] = CC_C,
4370
2c0262af
FB
4371 [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
4372 [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
4373 [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
4374 [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC,
4375 [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC,
4376 [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC,
4377 [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC,
4378 [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC,
4379
4380 [INDEX_op_bsfw_T0_cc] = CC_OSZAPC,
4381 [INDEX_op_bsfl_T0_cc] = CC_OSZAPC,
4382 [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
4383 [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
4384
4385 [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
4386 [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
4387 [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
4388
2c0262af
FB
4389 [INDEX_op_cmpxchg8b] = CC_Z,
4390 [INDEX_op_lar] = CC_Z,
4391 [INDEX_op_lsl] = CC_Z,
4392 [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
4393 [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
4f31916f
FB
4394
4395#define DEF_WRITEF(SUFFIX)\
4396 [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4397 [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4398 [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4399 [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4400 [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4401 [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4402\
4403 [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4404 [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4405 [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4406 [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4407 [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4408 [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4409\
4410 [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4411 [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4412 [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4413 [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4414 [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4415 [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
4416\
4417 [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4418 [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4419 [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4420\
4421 [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4422 [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4423 [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4424\
4425 [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4426 [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4427 [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
4428\
4429 [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
4430 [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
4431 [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
4432 [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
4433\
4434 [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
4435 [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
4436 [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
4437 [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
4438\
4439 [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
4440 [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
4441 [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,
4442
4443
4bb2fcc7 4444 DEF_WRITEF( )
4f31916f
FB
4445 DEF_WRITEF(_raw)
4446#ifndef CONFIG_USER_ONLY
4447 DEF_WRITEF(_kernel)
4448 DEF_WRITEF(_user)
4449#endif
2c0262af
FB
4450};
4451
4452/* simpler form of an operation if no flags need to be generated */
4453static uint16_t opc_simpler[NB_OPS] = {
4454 [INDEX_op_update2_cc] = INDEX_op_nop,
4455 [INDEX_op_update1_cc] = INDEX_op_nop,
4456 [INDEX_op_update_neg_cc] = INDEX_op_nop,
4457#if 0
4458 /* broken: CC_OP logic must be rewritten */
4459 [INDEX_op_update_inc_cc] = INDEX_op_nop,
4460#endif
2c0262af
FB
4461
4462 [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
4463 [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
4464 [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
4465
4466 [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1,
4467 [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1,
4468 [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1,
4469
4470 [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
4471 [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
4472 [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
4f31916f
FB
4473
4474#define DEF_SIMPLER(SUFFIX)\
4475 [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\
4476 [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\
4477 [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\
4478\
4479 [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\
4480 [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\
4481 [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1,
4482
4bb2fcc7 4483 DEF_SIMPLER( )
4f31916f
FB
4484 DEF_SIMPLER(_raw)
4485#ifndef CONFIG_USER_ONLY
4486 DEF_SIMPLER(_kernel)
4487 DEF_SIMPLER(_user)
4488#endif
2c0262af
FB
4489};
4490
4491void optimize_flags_init(void)
4492{
4493 int i;
4494 /* put default values in arrays */
4495 for(i = 0; i < NB_OPS; i++) {
4496 if (opc_simpler[i] == 0)
4497 opc_simpler[i] = i;
4498 }
4499}
4500
4501/* CPU flags computation optimization: we move backward thru the
4502 generated code to see which flags are needed. The operation is
4503 modified if suitable */
4504static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
4505{
4506 uint16_t *opc_ptr;
4507 int live_flags, write_flags, op;
4508
4509 opc_ptr = opc_buf + opc_buf_len;
4510 /* live_flags contains the flags needed by the next instructions
4511 in the code. At the end of the bloc, we consider that all the
4512 flags are live. */
4513 live_flags = CC_OSZAPC;
4514 while (opc_ptr > opc_buf) {
4515 op = *--opc_ptr;
4516 /* if none of the flags written by the instruction is used,
4517 then we can try to find a simpler instruction */
4518 write_flags = opc_write_flags[op];
4519 if ((live_flags & write_flags) == 0) {
4520 *opc_ptr = opc_simpler[op];
4521 }
4522 /* compute the live flags before the instruction */
4523 live_flags &= ~write_flags;
4524 live_flags |= opc_read_flags[op];
4525 }
4526}
4527
4528/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
4529 basic block 'tb'. If search_pc is TRUE, also generate PC
4530 information for each intermediate instruction. */
4531static inline int gen_intermediate_code_internal(CPUState *env,
4532 TranslationBlock *tb,
4533 int search_pc)
4534{
4535 DisasContext dc1, *dc = &dc1;
4536 uint8_t *pc_ptr;
4537 uint16_t *gen_opc_end;
d720b93d 4538 int flags, j, lj, cflags;
2c0262af
FB
4539 uint8_t *pc_start;
4540 uint8_t *cs_base;
4541
4542 /* generate intermediate code */
4543 pc_start = (uint8_t *)tb->pc;
4544 cs_base = (uint8_t *)tb->cs_base;
4545 flags = tb->flags;
d720b93d 4546 cflags = tb->cflags;
3a1d9b8b 4547
4f31916f 4548 dc->pe = (flags >> HF_PE_SHIFT) & 1;
2c0262af
FB
4549 dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
4550 dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
4551 dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
4552 dc->f_st = 0;
4553 dc->vm86 = (flags >> VM_SHIFT) & 1;
4554 dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
4555 dc->iopl = (flags >> IOPL_SHIFT) & 3;
4556 dc->tf = (flags >> TF_SHIFT) & 1;
34865134 4557 dc->singlestep_enabled = env->singlestep_enabled;
2c0262af
FB
4558 dc->cc_op = CC_OP_DYNAMIC;
4559 dc->cs_base = cs_base;
4560 dc->tb = tb;
4561 dc->popl_esp_hack = 0;
4562 /* select memory access functions */
4563 dc->mem_index = 0;
4564 if (flags & HF_SOFTMMU_MASK) {
4565 if (dc->cpl == 3)
4566 dc->mem_index = 6;
4567 else
4568 dc->mem_index = 3;
4569 }
7eee2a50 4570 dc->flags = flags;
a2cc3b24
FB
4571 dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
4572 (flags & HF_INHIBIT_IRQ_MASK)
415fa2ea 4573#ifndef CONFIG_SOFTMMU
2c0262af
FB
4574 || (flags & HF_SOFTMMU_MASK)
4575#endif
4576 );
4f31916f
FB
4577#if 0
4578 /* check addseg logic */
dc196a57 4579 if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
4f31916f
FB
4580 printf("ERROR addseg\n");
4581#endif
4582
2c0262af
FB
4583 gen_opc_ptr = gen_opc_buf;
4584 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
4585 gen_opparam_ptr = gen_opparam_buf;
4586
4587 dc->is_jmp = DISAS_NEXT;
4588 pc_ptr = pc_start;
4589 lj = -1;
4590
2c0262af
FB
4591 for(;;) {
4592 if (env->nb_breakpoints > 0) {
4593 for(j = 0; j < env->nb_breakpoints; j++) {
4594 if (env->breakpoints[j] == (unsigned long)pc_ptr) {
4595 gen_debug(dc, pc_ptr - dc->cs_base);
4596 break;
4597 }
4598 }
4599 }
4600 if (search_pc) {
4601 j = gen_opc_ptr - gen_opc_buf;
4602 if (lj < j) {
4603 lj++;
4604 while (lj < j)
4605 gen_opc_instr_start[lj++] = 0;
4606 }
4607 gen_opc_pc[lj] = (uint32_t)pc_ptr;
4608 gen_opc_cc_op[lj] = dc->cc_op;
4609 gen_opc_instr_start[lj] = 1;
4610 }
4611 pc_ptr = disas_insn(dc, pc_ptr);
4612 /* stop translation if indicated */
4613 if (dc->is_jmp)
4614 break;
4615 /* if single step mode, we generate only one instruction and
4616 generate an exception */
a2cc3b24
FB
4617 /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
4618 the flag and abort the translation to give the irqs a
4619 change to be happen */
4620 if (dc->tf || dc->singlestep_enabled ||
d720b93d
FB
4621 (flags & HF_INHIBIT_IRQ_MASK) ||
4622 (cflags & CF_SINGLE_INSN)) {
2c0262af
FB
4623 gen_op_jmp_im(pc_ptr - dc->cs_base);
4624 gen_eob(dc);
4625 break;
4626 }
4627 /* if too long translation, stop generation too */
4628 if (gen_opc_ptr >= gen_opc_end ||
4629 (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
4630 gen_op_jmp_im(pc_ptr - dc->cs_base);
4631 gen_eob(dc);
4632 break;
4633 }
4634 }
4635 *gen_opc_ptr = INDEX_op_end;
4636 /* we don't forget to fill the last values */
4637 if (search_pc) {
4638 j = gen_opc_ptr - gen_opc_buf;
4639 lj++;
4640 while (lj <= j)
4641 gen_opc_instr_start[lj++] = 0;
4642 }
4643
4644#ifdef DEBUG_DISAS
658c8bda 4645 if (loglevel & CPU_LOG_TB_CPU) {
7fe48483 4646 cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
658c8bda 4647 }
e19e89a5 4648 if (loglevel & CPU_LOG_TB_IN_ASM) {
2c0262af
FB
4649 fprintf(logfile, "----------------\n");
4650 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
4651 disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32);
4652 fprintf(logfile, "\n");
e19e89a5
FB
4653 if (loglevel & CPU_LOG_TB_OP) {
4654 fprintf(logfile, "OP:\n");
4655 dump_ops(gen_opc_buf, gen_opparam_buf);
4656 fprintf(logfile, "\n");
4657 }
2c0262af
FB
4658 }
4659#endif
4660
4661 /* optimize flag computations */
4662 optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
4663
4664#ifdef DEBUG_DISAS
e19e89a5 4665 if (loglevel & CPU_LOG_TB_OP_OPT) {
2c0262af
FB
4666 fprintf(logfile, "AFTER FLAGS OPT:\n");
4667 dump_ops(gen_opc_buf, gen_opparam_buf);
4668 fprintf(logfile, "\n");
4669 }
4670#endif
4671 if (!search_pc)
4672 tb->size = pc_ptr - pc_start;
4673 return 0;
4674}
4675
4676int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
4677{
4678 return gen_intermediate_code_internal(env, tb, 0);
4679}
4680
4681int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
4682{
4683 return gen_intermediate_code_internal(env, tb, 1);
4684}
4685