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