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