diff options
Diffstat (limited to 'target-i386/translate.c')
-rw-r--r-- | target-i386/translate.c | 4487 |
1 files changed, 4487 insertions, 0 deletions
diff --git a/target-i386/translate.c b/target-i386/translate.c new file mode 100644 index 0000000000..4d89ccbba9 --- /dev/null +++ b/target-i386/translate.c @@ -0,0 +1,4487 @@ +/* + * i386 translation + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <signal.h> +#include <assert.h> +#include <sys/mman.h> + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" + +/* XXX: move that elsewhere */ +static uint16_t *gen_opc_ptr; +static uint32_t *gen_opparam_ptr; + +#define PREFIX_REPZ 0x01 +#define PREFIX_REPNZ 0x02 +#define PREFIX_LOCK 0x04 +#define PREFIX_DATA 0x08 +#define PREFIX_ADR 0x10 + +typedef struct DisasContext { + /* current insn context */ + int override; /* -1 if no override */ + int prefix; + int aflag, dflag; + uint8_t *pc; /* pc = eip + cs_base */ + int is_jmp; /* 1 = means jump (stop translation), 2 means CPU + static state change (stop translation) */ + /* current block context */ + uint8_t *cs_base; /* base of CS segment */ + int pe; /* protected mode */ + int code32; /* 32 bit code segment */ + int ss32; /* 32 bit stack segment */ + int cc_op; /* current CC operation */ + int addseg; /* non zero if either DS/ES/SS have a non zero base */ + int f_st; /* currently unused */ + int vm86; /* vm86 mode */ + int cpl; + int iopl; + int tf; /* TF cpu flag */ + int jmp_opt; /* use direct block chaining for direct jumps */ + int mem_index; /* select memory access functions */ + struct TranslationBlock *tb; + int popl_esp_hack; /* for correct popl with esp base handling */ +} DisasContext; + +static void gen_eob(DisasContext *s); +static void gen_jmp(DisasContext *s, unsigned int eip); + +/* i386 arith/logic operations */ +enum { + OP_ADDL, + OP_ORL, + OP_ADCL, + OP_SBBL, + OP_ANDL, + OP_SUBL, + OP_XORL, + OP_CMPL, +}; + +/* i386 shift ops */ +enum { + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SHL1, /* undocumented */ + OP_SAR = 7, +}; + +enum { +#define DEF(s, n, copy_size) INDEX_op_ ## s, +#include "opc.h" +#undef DEF + NB_OPS, +}; + +#include "gen-op.h" + +/* operand size */ +enum { + OT_BYTE = 0, + OT_WORD, + OT_LONG, + OT_QUAD, +}; + +enum { + /* I386 int registers */ + OR_EAX, /* MUST be even numbered */ + OR_ECX, + OR_EDX, + OR_EBX, + OR_ESP, + OR_EBP, + OR_ESI, + OR_EDI, + OR_TMP0, /* temporary operand register */ + OR_TMP1, + OR_A0, /* temporary register used when doing address evaluation */ + OR_ZERO, /* fixed zero register */ + NB_OREGS, +}; + +typedef void (GenOpFunc)(void); +typedef void (GenOpFunc1)(long); +typedef void (GenOpFunc2)(long, long); +typedef void (GenOpFunc3)(long, long, long); + +static GenOpFunc *gen_op_mov_reg_T0[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T0, + gen_op_movb_ECX_T0, + gen_op_movb_EDX_T0, + gen_op_movb_EBX_T0, + gen_op_movh_EAX_T0, + gen_op_movh_ECX_T0, + gen_op_movh_EDX_T0, + gen_op_movh_EBX_T0, + }, + [OT_WORD] = { + gen_op_movw_EAX_T0, + gen_op_movw_ECX_T0, + gen_op_movw_EDX_T0, + gen_op_movw_EBX_T0, + gen_op_movw_ESP_T0, + gen_op_movw_EBP_T0, + gen_op_movw_ESI_T0, + gen_op_movw_EDI_T0, + }, + [OT_LONG] = { + gen_op_movl_EAX_T0, + gen_op_movl_ECX_T0, + gen_op_movl_EDX_T0, + gen_op_movl_EBX_T0, + gen_op_movl_ESP_T0, + gen_op_movl_EBP_T0, + gen_op_movl_ESI_T0, + gen_op_movl_EDI_T0, + }, +}; + +static GenOpFunc *gen_op_mov_reg_T1[3][8] = { + [OT_BYTE] = { + gen_op_movb_EAX_T1, + gen_op_movb_ECX_T1, + gen_op_movb_EDX_T1, + gen_op_movb_EBX_T1, + gen_op_movh_EAX_T1, + gen_op_movh_ECX_T1, + gen_op_movh_EDX_T1, + gen_op_movh_EBX_T1, + }, + [OT_WORD] = { + gen_op_movw_EAX_T1, + gen_op_movw_ECX_T1, + gen_op_movw_EDX_T1, + gen_op_movw_EBX_T1, + gen_op_movw_ESP_T1, + gen_op_movw_EBP_T1, + gen_op_movw_ESI_T1, + gen_op_movw_EDI_T1, + }, + [OT_LONG] = { + gen_op_movl_EAX_T1, + gen_op_movl_ECX_T1, + gen_op_movl_EDX_T1, + gen_op_movl_EBX_T1, + gen_op_movl_ESP_T1, + gen_op_movl_EBP_T1, + gen_op_movl_ESI_T1, + gen_op_movl_EDI_T1, + }, +}; + +static GenOpFunc *gen_op_mov_reg_A0[2][8] = { + [0] = { + gen_op_movw_EAX_A0, + gen_op_movw_ECX_A0, + gen_op_movw_EDX_A0, + gen_op_movw_EBX_A0, + gen_op_movw_ESP_A0, + gen_op_movw_EBP_A0, + gen_op_movw_ESI_A0, + gen_op_movw_EDI_A0, + }, + [1] = { + gen_op_movl_EAX_A0, + gen_op_movl_ECX_A0, + gen_op_movl_EDX_A0, + gen_op_movl_EBX_A0, + gen_op_movl_ESP_A0, + gen_op_movl_EBP_A0, + gen_op_movl_ESI_A0, + gen_op_movl_EDI_A0, + }, +}; + +static GenOpFunc *gen_op_mov_TN_reg[3][2][8] = +{ + [OT_BYTE] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movh_T0_EAX, + gen_op_movh_T0_ECX, + gen_op_movh_T0_EDX, + gen_op_movh_T0_EBX, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movh_T1_EAX, + gen_op_movh_T1_ECX, + gen_op_movh_T1_EDX, + gen_op_movh_T1_EBX, + }, + }, + [OT_WORD] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, + [OT_LONG] = { + { + gen_op_movl_T0_EAX, + gen_op_movl_T0_ECX, + gen_op_movl_T0_EDX, + gen_op_movl_T0_EBX, + gen_op_movl_T0_ESP, + gen_op_movl_T0_EBP, + gen_op_movl_T0_ESI, + gen_op_movl_T0_EDI, + }, + { + gen_op_movl_T1_EAX, + gen_op_movl_T1_ECX, + gen_op_movl_T1_EDX, + gen_op_movl_T1_EBX, + gen_op_movl_T1_ESP, + gen_op_movl_T1_EBP, + gen_op_movl_T1_ESI, + gen_op_movl_T1_EDI, + }, + }, +}; + +static GenOpFunc *gen_op_movl_A0_reg[8] = { + gen_op_movl_A0_EAX, + gen_op_movl_A0_ECX, + gen_op_movl_A0_EDX, + gen_op_movl_A0_EBX, + gen_op_movl_A0_ESP, + gen_op_movl_A0_EBP, + gen_op_movl_A0_ESI, + gen_op_movl_A0_EDI, +}; + +static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { + [0] = { + gen_op_addl_A0_EAX, + gen_op_addl_A0_ECX, + gen_op_addl_A0_EDX, + gen_op_addl_A0_EBX, + gen_op_addl_A0_ESP, + gen_op_addl_A0_EBP, + gen_op_addl_A0_ESI, + gen_op_addl_A0_EDI, + }, + [1] = { + gen_op_addl_A0_EAX_s1, + gen_op_addl_A0_ECX_s1, + gen_op_addl_A0_EDX_s1, + gen_op_addl_A0_EBX_s1, + gen_op_addl_A0_ESP_s1, + gen_op_addl_A0_EBP_s1, + gen_op_addl_A0_ESI_s1, + gen_op_addl_A0_EDI_s1, + }, + [2] = { + gen_op_addl_A0_EAX_s2, + gen_op_addl_A0_ECX_s2, + gen_op_addl_A0_EDX_s2, + gen_op_addl_A0_EBX_s2, + gen_op_addl_A0_ESP_s2, + gen_op_addl_A0_EBP_s2, + gen_op_addl_A0_ESI_s2, + gen_op_addl_A0_EDI_s2, + }, + [3] = { + gen_op_addl_A0_EAX_s3, + gen_op_addl_A0_ECX_s3, + gen_op_addl_A0_EDX_s3, + gen_op_addl_A0_EBX_s3, + gen_op_addl_A0_ESP_s3, + gen_op_addl_A0_EBP_s3, + gen_op_addl_A0_ESI_s3, + gen_op_addl_A0_EDI_s3, + }, +}; + +static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { + [0] = { + gen_op_cmovw_EAX_T1_T0, + gen_op_cmovw_ECX_T1_T0, + gen_op_cmovw_EDX_T1_T0, + gen_op_cmovw_EBX_T1_T0, + gen_op_cmovw_ESP_T1_T0, + gen_op_cmovw_EBP_T1_T0, + gen_op_cmovw_ESI_T1_T0, + gen_op_cmovw_EDI_T1_T0, + }, + [1] = { + gen_op_cmovl_EAX_T1_T0, + gen_op_cmovl_ECX_T1_T0, + gen_op_cmovl_EDX_T1_T0, + gen_op_cmovl_EBX_T1_T0, + gen_op_cmovl_ESP_T1_T0, + gen_op_cmovl_EBP_T1_T0, + gen_op_cmovl_ESI_T1_T0, + gen_op_cmovl_EDI_T1_T0, + }, +}; + +static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { + NULL, + gen_op_orl_T0_T1, + NULL, + NULL, + gen_op_andl_T0_T1, + NULL, + gen_op_xorl_T0_T1, + NULL, +}; + +static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_T0_T1_cc, + gen_op_sbbb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_T0_T1_cc, + gen_op_sbbw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_T0_T1_cc, + gen_op_sbbl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_mem_T0_T1_cc, + gen_op_sbbb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_mem_T0_T1_cc, + gen_op_sbbw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_mem_T0_T1_cc, + gen_op_sbbl_mem_T0_T1_cc, + }, +}; + +static const int cc_op_arithb[8] = { + CC_OP_ADDB, + CC_OP_LOGICB, + CC_OP_ADDB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, + CC_OP_LOGICB, + CC_OP_SUBB, +}; + +static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_T0_T1_EAX_cc, + gen_op_cmpxchgw_T0_T1_EAX_cc, + gen_op_cmpxchgl_T0_T1_EAX_cc, +}; + +static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = { + gen_op_cmpxchgb_mem_T0_T1_EAX_cc, + gen_op_cmpxchgw_mem_T0_T1_EAX_cc, + gen_op_cmpxchgl_mem_T0_T1_EAX_cc, +}; + +static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_T0_T1_cc, + gen_op_rorb_T0_T1_cc, + gen_op_rclb_T0_T1_cc, + gen_op_rcrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_shrb_T0_T1_cc, + gen_op_shlb_T0_T1_cc, + gen_op_sarb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_T0_T1_cc, + gen_op_rorw_T0_T1_cc, + gen_op_rclw_T0_T1_cc, + gen_op_rcrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_shrw_T0_T1_cc, + gen_op_shlw_T0_T1_cc, + gen_op_sarw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_T0_T1_cc, + gen_op_rorl_T0_T1_cc, + gen_op_rcll_T0_T1_cc, + gen_op_rcrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_shrl_T0_T1_cc, + gen_op_shll_T0_T1_cc, + gen_op_sarl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = { + [OT_BYTE] = { + gen_op_rolb_mem_T0_T1_cc, + gen_op_rorb_mem_T0_T1_cc, + gen_op_rclb_mem_T0_T1_cc, + gen_op_rcrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_shrb_mem_T0_T1_cc, + gen_op_shlb_mem_T0_T1_cc, + gen_op_sarb_mem_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_rolw_mem_T0_T1_cc, + gen_op_rorw_mem_T0_T1_cc, + gen_op_rclw_mem_T0_T1_cc, + gen_op_rcrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_shrw_mem_T0_T1_cc, + gen_op_shlw_mem_T0_T1_cc, + gen_op_sarw_mem_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_roll_mem_T0_T1_cc, + gen_op_rorl_mem_T0_T1_cc, + gen_op_rcll_mem_T0_T1_cc, + gen_op_rcrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_shrl_mem_T0_T1_cc, + gen_op_shll_mem_T0_T1_cc, + gen_op_sarl_mem_T0_T1_cc, + }, +}; + +static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_im_cc, + gen_op_shrdw_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_T0_T1_im_cc, + gen_op_shrdl_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_T0_T1_ECX_cc, + gen_op_shrdw_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_T0_T1_ECX_cc, + gen_op_shrdl_T0_T1_ECX_cc, + }, +}; + +static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_im_cc, + gen_op_shrdw_mem_T0_T1_im_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_im_cc, + gen_op_shrdl_mem_T0_T1_im_cc, + }, +}; + +static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = { + [0] = { + gen_op_shldw_mem_T0_T1_ECX_cc, + gen_op_shrdw_mem_T0_T1_ECX_cc, + }, + [1] = { + gen_op_shldl_mem_T0_T1_ECX_cc, + gen_op_shrdl_mem_T0_T1_ECX_cc, + }, +}; + +static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { + [0] = { + gen_op_btw_T0_T1_cc, + gen_op_btsw_T0_T1_cc, + gen_op_btrw_T0_T1_cc, + gen_op_btcw_T0_T1_cc, + }, + [1] = { + gen_op_btl_T0_T1_cc, + gen_op_btsl_T0_T1_cc, + gen_op_btrl_T0_T1_cc, + gen_op_btcl_T0_T1_cc, + }, +}; + +static GenOpFunc *gen_op_bsx_T0_cc[2][2] = { + [0] = { + gen_op_bsfw_T0_cc, + gen_op_bsrw_T0_cc, + }, + [1] = { + gen_op_bsfl_T0_cc, + gen_op_bsrl_T0_cc, + }, +}; + +static GenOpFunc *gen_op_lds_T0_A0[3 * 3] = { + gen_op_ldsb_T0_A0, + gen_op_ldsw_T0_A0, + NULL, + + gen_op_ldsb_kernel_T0_A0, + gen_op_ldsw_kernel_T0_A0, + NULL, + + gen_op_ldsb_user_T0_A0, + gen_op_ldsw_user_T0_A0, + NULL, +}; + +static GenOpFunc *gen_op_ldu_T0_A0[3 * 3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, + NULL, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + NULL, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + NULL, +}; + +/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */ +static GenOpFunc *gen_op_ld_T0_A0[3 * 3] = { + gen_op_ldub_T0_A0, + gen_op_lduw_T0_A0, + gen_op_ldl_T0_A0, + + gen_op_ldub_kernel_T0_A0, + gen_op_lduw_kernel_T0_A0, + gen_op_ldl_kernel_T0_A0, + + gen_op_ldub_user_T0_A0, + gen_op_lduw_user_T0_A0, + gen_op_ldl_user_T0_A0, +}; + +static GenOpFunc *gen_op_ld_T1_A0[3 * 3] = { + gen_op_ldub_T1_A0, + gen_op_lduw_T1_A0, + gen_op_ldl_T1_A0, + + gen_op_ldub_kernel_T1_A0, + gen_op_lduw_kernel_T1_A0, + gen_op_ldl_kernel_T1_A0, + + gen_op_ldub_user_T1_A0, + gen_op_lduw_user_T1_A0, + gen_op_ldl_user_T1_A0, +}; + +static GenOpFunc *gen_op_st_T0_A0[3 * 3] = { + gen_op_stb_T0_A0, + gen_op_stw_T0_A0, + gen_op_stl_T0_A0, + + gen_op_stb_kernel_T0_A0, + gen_op_stw_kernel_T0_A0, + gen_op_stl_kernel_T0_A0, + + gen_op_stb_user_T0_A0, + gen_op_stw_user_T0_A0, + gen_op_stl_user_T0_A0, +}; + +static inline void gen_string_movl_A0_ESI(DisasContext *s) +{ + int override; + + override = s->override; + if (s->aflag) { + /* 32 bit address */ + if (s->addseg && override < 0) + override = R_DS; + if (override >= 0) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base)); + gen_op_addl_A0_reg_sN[0][R_ESI](); + } else { + gen_op_movl_A0_reg[R_ESI](); + } + } else { + /* 16 address, always override */ + if (override < 0) + override = R_DS; + gen_op_movl_A0_reg[R_ESI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } +} + +static inline void gen_string_movl_A0_EDI(DisasContext *s) +{ + if (s->aflag) { + if (s->addseg) { + gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + gen_op_addl_A0_reg_sN[0][R_EDI](); + } else { + gen_op_movl_A0_reg[R_EDI](); + } + } else { + gen_op_movl_A0_reg[R_EDI](); + gen_op_andl_A0_ffff(); + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base)); + } +} + +static GenOpFunc *gen_op_movl_T0_Dshift[3] = { + gen_op_movl_T0_Dshiftb, + gen_op_movl_T0_Dshiftw, + gen_op_movl_T0_Dshiftl, +}; + +static GenOpFunc2 *gen_op_jz_ecx[2] = { + gen_op_jz_ecxw, + gen_op_jz_ecxl, +}; + +static GenOpFunc1 *gen_op_jz_ecx_im[2] = { + gen_op_jz_ecxw_im, + gen_op_jz_ecxl_im, +}; + +static GenOpFunc *gen_op_dec_ECX[2] = { + gen_op_decw_ECX, + gen_op_decl_ECX, +}; + +static GenOpFunc1 *gen_op_string_jnz_sub[2][3] = { + { + gen_op_string_jnz_subb, + gen_op_string_jnz_subw, + gen_op_string_jnz_subl, + }, + { + gen_op_string_jz_subb, + gen_op_string_jz_subw, + gen_op_string_jz_subl, + }, +}; + +static GenOpFunc1 *gen_op_string_jnz_sub_im[2][3] = { + { + gen_op_string_jnz_subb_im, + gen_op_string_jnz_subw_im, + gen_op_string_jnz_subl_im, + }, + { + gen_op_string_jz_subb_im, + gen_op_string_jz_subw_im, + gen_op_string_jz_subl_im, + }, +}; + +static GenOpFunc *gen_op_in_DX_T0[3] = { + gen_op_inb_DX_T0, + gen_op_inw_DX_T0, + gen_op_inl_DX_T0, +}; + +static GenOpFunc *gen_op_out_DX_T0[3] = { + gen_op_outb_DX_T0, + gen_op_outw_DX_T0, + gen_op_outl_DX_T0, +}; + +static inline void gen_movs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } +} + +static inline void gen_jz_ecx_string(DisasContext *s, unsigned int next_eip) +{ + if (s->jmp_opt) { + gen_op_jz_ecx[s->aflag]((long)s->tb, next_eip); + } else { + /* XXX: does not work with gdbstub "ice" single step - not a + serious problem */ + gen_op_jz_ecx_im[s->aflag](next_eip); + } +} + +static inline void gen_stos(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_lods(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +static inline void gen_scas(DisasContext *s, int ot) +{ + gen_op_mov_TN_reg[OT_LONG][0][R_EAX](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_cmps(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_string_movl_A0_EDI(s); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_cmpl_T0_T1_cc(); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_ESI_T0(); + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_ins(DisasContext *s, int ot) +{ + gen_op_in_DX_T0[ot](); + gen_string_movl_A0_EDI(s); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_EDI_T0(); + } else { + gen_op_addw_EDI_T0(); + } +} + +static inline void gen_outs(DisasContext *s, int ot) +{ + gen_string_movl_A0_ESI(s); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_out_DX_T0[ot](); + gen_op_movl_T0_Dshift[ot](); + if (s->aflag) { + gen_op_addl_ESI_T0(); + } else { + gen_op_addw_ESI_T0(); + } +} + +/* same method as Valgrind : we generate jumps to current or next + instruction */ +#define GEN_REPZ(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, unsigned int next_eip) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + /* a loop would cause two single step exceptions if ECX = 1 \ + before rep string_insn */ \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ +} + +#define GEN_REPZ2(op) \ +static inline void gen_repz_ ## op(DisasContext *s, int ot, \ + unsigned int cur_eip, \ + unsigned int next_eip, \ + int nz) \ +{ \ + gen_update_cc_op(s); \ + gen_jz_ecx_string(s, next_eip); \ + gen_ ## op(s, ot); \ + gen_op_dec_ECX[s->aflag](); \ + gen_op_set_cc_op(CC_OP_SUBB + ot); \ + if (!s->jmp_opt) \ + gen_op_string_jnz_sub_im[nz][ot](next_eip); \ + else \ + gen_op_string_jnz_sub[nz][ot]((long)s->tb); \ + if (!s->jmp_opt) \ + gen_op_jz_ecx_im[s->aflag](next_eip); \ + gen_jmp(s, cur_eip); \ +} + +GEN_REPZ(movs) +GEN_REPZ(stos) +GEN_REPZ(lods) +GEN_REPZ(ins) +GEN_REPZ(outs) +GEN_REPZ2(scas) +GEN_REPZ2(cmps) + +static GenOpFunc *gen_op_in[3] = { + gen_op_inb_T0_T1, + gen_op_inw_T0_T1, + gen_op_inl_T0_T1, +}; + +static GenOpFunc *gen_op_out[3] = { + gen_op_outb_T0_T1, + gen_op_outw_T0_T1, + gen_op_outl_T0_T1, +}; + +enum { + JCC_O, + JCC_B, + JCC_Z, + JCC_BE, + JCC_S, + JCC_P, + JCC_L, + JCC_LE, +}; + +static GenOpFunc3 *gen_jcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_jb_subb, + gen_op_jz_subb, + gen_op_jbe_subb, + gen_op_js_subb, + NULL, + gen_op_jl_subb, + gen_op_jle_subb, + }, + [OT_WORD] = { + NULL, + gen_op_jb_subw, + gen_op_jz_subw, + gen_op_jbe_subw, + gen_op_js_subw, + NULL, + gen_op_jl_subw, + gen_op_jle_subw, + }, + [OT_LONG] = { + NULL, + gen_op_jb_subl, + gen_op_jz_subl, + gen_op_jbe_subl, + gen_op_js_subl, + NULL, + gen_op_jl_subl, + gen_op_jle_subl, + }, +}; +static GenOpFunc2 *gen_op_loop[2][4] = { + [0] = { + gen_op_loopnzw, + gen_op_loopzw, + gen_op_loopw, + gen_op_jecxzw, + }, + [1] = { + gen_op_loopnzl, + gen_op_loopzl, + gen_op_loopl, + gen_op_jecxzl, + }, +}; + +static GenOpFunc *gen_setcc_slow[8] = { + gen_op_seto_T0_cc, + gen_op_setb_T0_cc, + gen_op_setz_T0_cc, + gen_op_setbe_T0_cc, + gen_op_sets_T0_cc, + gen_op_setp_T0_cc, + gen_op_setl_T0_cc, + gen_op_setle_T0_cc, +}; + +static GenOpFunc *gen_setcc_sub[3][8] = { + [OT_BYTE] = { + NULL, + gen_op_setb_T0_subb, + gen_op_setz_T0_subb, + gen_op_setbe_T0_subb, + gen_op_sets_T0_subb, + NULL, + gen_op_setl_T0_subb, + gen_op_setle_T0_subb, + }, + [OT_WORD] = { + NULL, + gen_op_setb_T0_subw, + gen_op_setz_T0_subw, + gen_op_setbe_T0_subw, + gen_op_sets_T0_subw, + NULL, + gen_op_setl_T0_subw, + gen_op_setle_T0_subw, + }, + [OT_LONG] = { + NULL, + gen_op_setb_T0_subl, + gen_op_setz_T0_subl, + gen_op_setbe_T0_subl, + gen_op_sets_T0_subl, + NULL, + gen_op_setl_T0_subl, + gen_op_setle_T0_subl, + }, +}; + +static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = { + gen_op_fadd_ST0_FT0, + gen_op_fmul_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fcom_ST0_FT0, + gen_op_fsub_ST0_FT0, + gen_op_fsubr_ST0_FT0, + gen_op_fdiv_ST0_FT0, + gen_op_fdivr_ST0_FT0, +}; + +/* NOTE the exception in "r" op ordering */ +static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = { + gen_op_fadd_STN_ST0, + gen_op_fmul_STN_ST0, + NULL, + NULL, + gen_op_fsubr_STN_ST0, + gen_op_fsub_STN_ST0, + gen_op_fdivr_STN_ST0, + gen_op_fdiv_STN_ST0, +}; + +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_op(DisasContext *s1, int op, int ot, int d) +{ + GenOpFunc *gen_update_cc; + + if (d != OR_TMP0) { + gen_op_mov_TN_reg[ot][0][d](); + } else { + gen_op_ld_T0_A0[ot + s1->mem_index](); + } + switch(op) { + case OP_ADCL: + case OP_SBBL: + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (d != OR_TMP0) { + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + gen_op_mov_reg_T0[ot][d](); + } else { + gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL](); + } + s1->cc_op = CC_OP_DYNAMIC; + goto the_end; + case OP_ADDL: + gen_op_addl_T0_T1(); + s1->cc_op = CC_OP_ADDB + ot; + gen_update_cc = gen_op_update2_cc; + break; + case OP_SUBL: + gen_op_subl_T0_T1(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = gen_op_update2_cc; + break; + default: + case OP_ANDL: + case OP_ORL: + case OP_XORL: + gen_op_arith_T0_T1_cc[op](); + s1->cc_op = CC_OP_LOGICB + ot; + gen_update_cc = gen_op_update1_cc; + break; + case OP_CMPL: + gen_op_cmpl_T0_T1_cc(); + s1->cc_op = CC_OP_SUBB + ot; + gen_update_cc = NULL; + break; + } + if (op != OP_CMPL) { + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot + s1->mem_index](); + } + /* the flags update must happen after the memory write (precise + exception support) */ + if (gen_update_cc) + gen_update_cc(); + the_end: ; +} + +/* if d == OR_TMP0, it means memory operand (address in A0) */ +static void gen_inc(DisasContext *s1, int ot, int d, int c) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot + s1->mem_index](); + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + if (c > 0) { + gen_op_incl_T0(); + s1->cc_op = CC_OP_INCB + ot; + } else { + gen_op_decl_T0(); + s1->cc_op = CC_OP_DECB + ot; + } + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + else + gen_op_st_T0_A0[ot + s1->mem_index](); + gen_op_update_inc_cc(); +} + +static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) +{ + if (d != OR_TMP0) + gen_op_mov_TN_reg[ot][0][d](); + else + gen_op_ld_T0_A0[ot + s1->mem_index](); + if (s != OR_TMP1) + gen_op_mov_TN_reg[ot][1][s](); + /* for zero counts, flags are not updated, so must do it dynamically */ + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + + if (d != OR_TMP0) + gen_op_shift_T0_T1_cc[ot][op](); + else + gen_op_shift_mem_T0_T1_cc[ot][op](); + if (d != OR_TMP0) + gen_op_mov_reg_T0[ot][d](); + s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ +} + +static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c) +{ + /* currently not optimized */ + gen_op_movl_T1_im(c); + gen_shift(s1, op, ot, d, OR_TMP1); +} + +static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr) +{ + int havesib; + int base, disp; + int index; + int scale; + int opreg; + int mod, rm, code, override, must_add_seg; + + override = s->override; + must_add_seg = s->addseg; + if (override >= 0) + must_add_seg = 1; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (s->aflag) { + + havesib = 0; + base = rm; + index = 0; + scale = 0; + + if (base == 4) { + havesib = 1; + code = ldub(s->pc++); + scale = (code >> 6) & 3; + index = (code >> 3) & 7; + base = code & 7; + } + + switch (mod) { + case 0: + if (base == 5) { + base = -1; + disp = ldl(s->pc); + s->pc += 4; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = ldl(s->pc); + s->pc += 4; + break; + } + + if (base >= 0) { + /* for correct popl handling with esp */ + if (base == 4 && s->popl_esp_hack) + disp += s->popl_esp_hack; + gen_op_movl_A0_reg[base](); + if (disp != 0) + gen_op_addl_A0_im(disp); + } else { + gen_op_movl_A0_im(disp); + } + /* XXX: index == 4 is always invalid */ + if (havesib && (index != 4 || scale != 0)) { + gen_op_addl_A0_reg_sN[scale][index](); + } + if (must_add_seg) { + if (override < 0) { + if (base == R_EBP || base == R_ESP) + override = R_SS; + else + override = R_DS; + } + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } else { + switch (mod) { + case 0: + if (rm == 6) { + disp = lduw(s->pc); + s->pc += 2; + gen_op_movl_A0_im(disp); + rm = 0; /* avoid SS override */ + goto no_rm; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = lduw(s->pc); + s->pc += 2; + break; + } + switch(rm) { + case 0: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 1: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 2: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 3: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 4: + gen_op_movl_A0_reg[R_ESI](); + break; + case 5: + gen_op_movl_A0_reg[R_EDI](); + break; + case 6: + gen_op_movl_A0_reg[R_EBP](); + break; + default: + case 7: + gen_op_movl_A0_reg[R_EBX](); + break; + } + if (disp != 0) + gen_op_addl_A0_im(disp); + gen_op_andl_A0_ffff(); + no_rm: + if (must_add_seg) { + if (override < 0) { + if (rm == 2 || rm == 3 || rm == 6) + override = R_SS; + else + override = R_DS; + } + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + + opreg = OR_A0; + disp = 0; + *reg_ptr = opreg; + *offset_ptr = disp; +} + +/* generate modrm memory load or store of 'reg'. TMP0 is used if reg != + OR_TMP0 */ +static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store) +{ + int mod, rm, opreg, disp; + + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod == 3) { + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } else { + gen_lea_modrm(s, modrm, &opreg, &disp); + if (is_store) { + if (reg != OR_TMP0) + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_ld_T0_A0[ot + s->mem_index](); + if (reg != OR_TMP0) + gen_op_mov_reg_T0[ot][reg](); + } + } +} + +static inline uint32_t insn_get(DisasContext *s, int ot) +{ + uint32_t ret; + + switch(ot) { + case OT_BYTE: + ret = ldub(s->pc); + s->pc++; + break; + case OT_WORD: + ret = lduw(s->pc); + s->pc += 2; + break; + default: + case OT_LONG: + ret = ldl(s->pc); + s->pc += 4; + break; + } + return ret; +} + +static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip) +{ + TranslationBlock *tb; + int inv, jcc_op; + GenOpFunc3 *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + + if (s->jmp_opt) { + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: + switch(jcc_op) { + case JCC_Z: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + func = NULL; + break; + } + break; + default: + func = NULL; + break; + } + + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + + if (!func) { + gen_setcc_slow[jcc_op](); + func = gen_op_jcc; + } + + tb = s->tb; + if (!inv) { + func((long)tb, val, next_eip); + } else { + func((long)tb, next_eip, val); + } + s->is_jmp = 3; + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_setcc_slow[jcc_op](); + if (!inv) { + gen_op_jcc_im(val, next_eip); + } else { + gen_op_jcc_im(next_eip, val); + } + gen_eob(s); + } +} + +static void gen_setcc(DisasContext *s, int b) +{ + int inv, jcc_op; + GenOpFunc *func; + + inv = b & 1; + jcc_op = (b >> 1) & 7; + switch(s->cc_op) { + /* we optimize the cmp/jcc case */ + case CC_OP_SUBB: + case CC_OP_SUBW: + case CC_OP_SUBL: + func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op]; + if (!func) + goto slow_jcc; + break; + + /* some jumps are easy to compute */ + case CC_OP_ADDB: + case CC_OP_ADDW: + case CC_OP_ADDL: + case CC_OP_LOGICB: + case CC_OP_LOGICW: + case CC_OP_LOGICL: + case CC_OP_INCB: + case CC_OP_INCW: + case CC_OP_INCL: + case CC_OP_DECB: + case CC_OP_DECW: + case CC_OP_DECL: + case CC_OP_SHLB: + case CC_OP_SHLW: + case CC_OP_SHLL: + switch(jcc_op) { + case JCC_Z: + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + case JCC_S: + func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; + break; + default: + goto slow_jcc; + } + break; + default: + slow_jcc: + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + func = gen_setcc_slow[jcc_op]; + break; + } + func(); + if (inv) { + gen_op_xor_T0_1(); + } +} + +/* move T0 to seg_reg and compute if the CPU state may change. Never + call this function with seg_reg == R_CS */ +static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) +{ + if (s->pe && !s->vm86) + gen_op_movl_seg_T0(seg_reg, cur_eip); + else + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); + /* abort translation because the register may have a non zero base + or because ss32 may change. For R_SS, translation must always + stop as a special handling must be done to disable hardware + interrupts for the next instruction */ + if (seg_reg == R_SS || (!s->addseg && seg_reg < R_FS)) + s->is_jmp = 3; +} + +/* generate a push. It depends on ss32, addseg and dflag */ +static void gen_push_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_pushl_T0(); + else + gen_op_pushw_T0(); + } else { + if (s->dflag) + gen_op_pushl_ss32_T0(); + else + gen_op_pushw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_pushl_ss16_T0(); + else + gen_op_pushw_ss16_T0(); + } +} + +/* two step pop is necessary for precise exceptions */ +static void gen_pop_T0(DisasContext *s) +{ + if (s->ss32) { + if (!s->addseg) { + if (s->dflag) + gen_op_popl_T0(); + else + gen_op_popw_T0(); + } else { + if (s->dflag) + gen_op_popl_ss32_T0(); + else + gen_op_popw_ss32_T0(); + } + } else { + if (s->dflag) + gen_op_popl_ss16_T0(); + else + gen_op_popw_ss16_T0(); + } +} + +static inline void gen_stack_update(DisasContext *s, int addend) +{ + if (s->ss32) { + if (addend == 2) + gen_op_addl_ESP_2(); + else if (addend == 4) + gen_op_addl_ESP_4(); + else + gen_op_addl_ESP_im(addend); + } else { + if (addend == 2) + gen_op_addw_ESP_2(); + else if (addend == 4) + gen_op_addw_ESP_4(); + else + gen_op_addw_ESP_im(addend); + } +} + +static void gen_pop_update(DisasContext *s) +{ + gen_stack_update(s, 2 << s->dflag); +} + +static void gen_stack_A0(DisasContext *s) +{ + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_pusha(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-16 << s->dflag); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + for(i = 0;i < 8; i++) { + gen_op_mov_TN_reg[OT_LONG][0][7 - i](); + gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index](); + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +static void gen_popa(DisasContext *s) +{ + int i; + gen_op_movl_A0_ESP(); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + gen_op_addl_T1_im(16 << s->dflag); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + for(i = 0;i < 8; i++) { + /* ESP is not reloaded */ + if (i != 3) { + gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index](); + gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i](); + } + gen_op_addl_A0_im(2 << s->dflag); + } + gen_op_mov_reg_T1[OT_WORD + s->dflag][R_ESP](); +} + +/* NOTE: wrap around in 16 bit not fully handled */ +/* XXX: check this */ +static void gen_enter(DisasContext *s, int esp_addend, int level) +{ + int ot, level1, addend, opsize; + + ot = s->dflag + OT_WORD; + level &= 0x1f; + level1 = level; + opsize = 2 << s->dflag; + + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-opsize); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + while (level--) { + gen_op_addl_A0_im(-opsize); + gen_op_addl_T0_im(-opsize); + gen_op_st_T0_A0[ot + s->mem_index](); + } + gen_op_addl_A0_im(-opsize); + /* XXX: add st_T1_A0 ? */ + gen_op_movl_T0_T1(); + gen_op_st_T0_A0[ot + s->mem_index](); + } + gen_op_mov_reg_T1[ot][R_EBP](); + addend = -esp_addend; + if (level1) + addend -= opsize * (level1 + 1); + gen_op_addl_T1_im(addend); + gen_op_mov_reg_T1[ot][R_ESP](); +} + +static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_exception(trapno); + s->is_jmp = 3; +} + +/* an interrupt is different from an exception because of the + priviledge checks */ +static void gen_interrupt(DisasContext *s, int intno, + unsigned int cur_eip, unsigned int next_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_raise_interrupt(intno, next_eip); + s->is_jmp = 3; +} + +static void gen_debug(DisasContext *s, unsigned int cur_eip) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(cur_eip); + gen_op_debug(); + s->is_jmp = 3; +} + +/* generate a generic end of block. Trace exception is also generated + if needed */ +static void gen_eob(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (s->tf) { + gen_op_raise_exception(EXCP01_SSTP); + } else { + gen_op_movl_T0_0(); + gen_op_exit_tb(); + } + s->is_jmp = 3; +} + +/* generate a jump to eip. No segment change must happen before as a + direct call to the next block may occur */ +static void gen_jmp(DisasContext *s, unsigned int eip) +{ + TranslationBlock *tb = s->tb; + + if (s->jmp_opt) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp((long)tb, eip); + s->is_jmp = 3; + } else { + gen_op_jmp_im(eip); + gen_eob(s); + } +} + +/* convert one instruction. s->is_jmp is set if the translation must + be stopped. Return the next pc value */ +static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) +{ + int b, prefixes, aflag, dflag; + int shift, ot; + int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val; + unsigned int next_eip; + + s->pc = pc_start; + prefixes = 0; + aflag = s->code32; + dflag = s->code32; + s->override = -1; + next_byte: + b = ldub(s->pc); + s->pc++; + /* check prefixes */ + switch (b) { + case 0xf3: + prefixes |= PREFIX_REPZ; + goto next_byte; + case 0xf2: + prefixes |= PREFIX_REPNZ; + goto next_byte; + case 0xf0: + prefixes |= PREFIX_LOCK; + goto next_byte; + case 0x2e: + s->override = R_CS; + goto next_byte; + case 0x36: + s->override = R_SS; + goto next_byte; + case 0x3e: + s->override = R_DS; + goto next_byte; + case 0x26: + s->override = R_ES; + goto next_byte; + case 0x64: + s->override = R_FS; + goto next_byte; + case 0x65: + s->override = R_GS; + goto next_byte; + case 0x66: + prefixes |= PREFIX_DATA; + goto next_byte; + case 0x67: + prefixes |= PREFIX_ADR; + goto next_byte; + } + + if (prefixes & PREFIX_DATA) + dflag ^= 1; + if (prefixes & PREFIX_ADR) + aflag ^= 1; + + s->prefix = prefixes; + s->aflag = aflag; + s->dflag = dflag; + + /* lock generation */ + if (prefixes & PREFIX_LOCK) + gen_op_lock(); + + /* now check op code */ + reswitch: + switch(b) { + case 0x0f: + /**************************/ + /* extended op code */ + b = ldub(s->pc++) | 0x100; + goto reswitch; + + /**************************/ + /* arith & logic */ + case 0x00 ... 0x05: + case 0x08 ... 0x0d: + case 0x10 ... 0x15: + case 0x18 ... 0x1d: + case 0x20 ... 0x25: + case 0x28 ... 0x2d: + case 0x30 ... 0x35: + case 0x38 ... 0x3d: + { + int op, f, val; + op = (b >> 3) & 7; + f = (b >> 1) & 3; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + switch(f) { + case 0: /* OP Ev, Gv */ + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else if (op == OP_XORL && rm == reg) { + xor_zero: + /* xor reg, reg optimisation */ + gen_op_movl_T0_0(); + s->cc_op = CC_OP_LOGICB + ot; + gen_op_mov_reg_T0[ot][reg](); + gen_op_update1_cc(); + break; + } else { + opreg = rm; + } + gen_op_mov_TN_reg[ot][1][reg](); + gen_op(s, op, ot, opreg); + break; + case 1: /* OP Gv, Ev */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + reg = ((modrm >> 3) & 7); + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + } else if (op == OP_XORL && rm == reg) { + goto xor_zero; + } else { + gen_op_mov_TN_reg[ot][1][rm](); + } + gen_op(s, op, ot, reg); + break; + case 2: /* OP A, Iv */ + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + gen_op(s, op, ot, OR_EAX); + break; + } + } + break; + + case 0x80: /* GRP1 */ + case 0x81: + case 0x83: + { + int val; + + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + switch(b) { + default: + case 0x80: + case 0x81: + val = insn_get(s, ot); + break; + case 0x83: + val = (int8_t)insn_get(s, OT_BYTE); + break; + } + gen_op_movl_T1_im(val); + gen_op(s, op, ot, opreg); + } + break; + + /**************************/ + /* inc, dec, and other misc arith */ + case 0x40 ... 0x47: /* inc Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), 1); + break; + case 0x48 ... 0x4f: /* dec Gv */ + ot = dflag ? OT_LONG : OT_WORD; + gen_inc(s, ot, OR_EAX + (b & 7), -1); + break; + case 0xf6: /* GRP3 */ + case 0xf7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* test */ + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + case 2: /* not */ + gen_op_notl_T0(); + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + break; + case 3: /* neg */ + gen_op_negl_T0(); + if (mod != 3) { + gen_op_st_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_reg_T0[ot][rm](); + } + gen_op_update_neg_cc(); + s->cc_op = CC_OP_SUBB + ot; + break; + case 4: /* mul */ + switch(ot) { + case OT_BYTE: + gen_op_mulb_AL_T0(); + break; + case OT_WORD: + gen_op_mulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_mull_EAX_T0(); + break; + } + s->cc_op = CC_OP_MUL; + break; + case 5: /* imul */ + switch(ot) { + case OT_BYTE: + gen_op_imulb_AL_T0(); + break; + case OT_WORD: + gen_op_imulw_AX_T0(); + break; + default: + case OT_LONG: + gen_op_imull_EAX_T0(); + break; + } + s->cc_op = CC_OP_MUL; + break; + case 6: /* div */ + switch(ot) { + case OT_BYTE: + gen_op_divb_AL_T0(pc_start - s->cs_base); + break; + case OT_WORD: + gen_op_divw_AX_T0(pc_start - s->cs_base); + break; + default: + case OT_LONG: + gen_op_divl_EAX_T0(pc_start - s->cs_base); + break; + } + break; + case 7: /* idiv */ + switch(ot) { + case OT_BYTE: + gen_op_idivb_AL_T0(pc_start - s->cs_base); + break; + case OT_WORD: + gen_op_idivw_AX_T0(pc_start - s->cs_base); + break; + default: + case OT_LONG: + gen_op_idivl_EAX_T0(pc_start - s->cs_base); + break; + } + break; + default: + goto illegal_op; + } + break; + + case 0xfe: /* GRP4 */ + case 0xff: /* GRP5 */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + if (op >= 2 && b == 0xfe) { + goto illegal_op; + } + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op >= 2 && op != 3 && op != 5) + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + + switch(op) { + case 0: /* inc Ev */ + if (mod != 3) + opreg = OR_TMP0; + else + opreg = rm; + gen_inc(s, ot, opreg, 1); + break; + case 1: /* dec Ev */ + if (mod != 3) + opreg = OR_TMP0; + else + opreg = rm; + gen_inc(s, ot, opreg, -1); + break; + case 2: /* call Ev */ + /* XXX: optimize if memory (no and is necessary) */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + next_eip = s->pc - s->cs_base; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + gen_eob(s); + break; + case 3: /*< lcall Ev */ + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_ld_T0_A0[OT_WORD + s->mem_index](); + do_lcall: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lcall_protected_T0_T1(dflag, s->pc - s->cs_base); + } else { + gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base); + } + gen_eob(s); + break; + case 4: /* jmp Ev */ + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 5: /* ljmp Ev */ + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + gen_op_lduw_T0_A0(); + do_ljmp: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ljmp_protected_T0_T1(); + } else { + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + gen_op_movl_T0_T1(); + gen_op_jmp_T0(); + } + gen_eob(s); + break; + case 6: /* push Ev */ + gen_push_T0(s); + break; + default: + goto illegal_op; + } + break; + + case 0x84: /* test Ev, Gv */ + case 0x85: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg + OR_EAX](); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0xa8: /* test eAX, Iv */ + case 0xa9: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + + gen_op_mov_TN_reg[ot][0][OR_EAX](); + gen_op_movl_T1_im(val); + gen_op_testl_T0_T1_cc(); + s->cc_op = CC_OP_LOGICB + ot; + break; + + case 0x98: /* CWDE/CBW */ + if (dflag) + gen_op_movswl_EAX_AX(); + else + gen_op_movsbw_AX_AL(); + break; + case 0x99: /* CDQ/CWD */ + if (dflag) + gen_op_movslq_EDX_EAX(); + else + gen_op_movswl_DX_AX(); + break; + case 0x1af: /* imul Gv, Ev */ + case 0x69: /* imul Gv, Ev, I */ + case 0x6b: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + if (b == 0x69) { + val = insn_get(s, ot); + gen_op_movl_T1_im(val); + } else if (b == 0x6b) { + val = insn_get(s, OT_BYTE); + gen_op_movl_T1_im(val); + } else { + gen_op_mov_TN_reg[ot][1][reg](); + } + + if (ot == OT_LONG) { + gen_op_imull_T0_T1(); + } else { + gen_op_imulw_T0_T1(); + } + gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_MUL; + break; + case 0x1c0: + case 0x1c1: /* xadd Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_addl_T0_T1(); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_T0_T1(); + gen_op_st_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T1[ot][reg](); + } + gen_op_update2_cc(); + s->cc_op = CC_OP_ADDB + ot; + break; + case 0x1b0: + case 0x1b1: /* cmpxchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_op_mov_TN_reg[ot][1][reg](); + if (mod == 3) { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][0][rm](); + gen_op_cmpxchg_T0_T1_EAX_cc[ot](); + gen_op_mov_reg_T0[ot][rm](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot](); + } + s->cc_op = CC_OP_SUBB + ot; + break; + case 0x1c7: /* cmpxchg8b */ + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_cmpxchg8b(); + s->cc_op = CC_OP_EFLAGS; + break; + + /**************************/ + /* push/pop */ + case 0x50 ... 0x57: /* push */ + gen_op_mov_TN_reg[OT_LONG][0][b & 7](); + gen_push_T0(s); + break; + case 0x58 ... 0x5f: /* pop */ + ot = dflag ? OT_LONG : OT_WORD; + gen_pop_T0(s); + gen_op_mov_reg_T0[ot][b & 7](); + gen_pop_update(s); + break; + case 0x60: /* pusha */ + gen_pusha(s); + break; + case 0x61: /* popa */ + gen_popa(s); + break; + case 0x68: /* push Iv */ + case 0x6a: + ot = dflag ? OT_LONG : OT_WORD; + if (b == 0x68) + val = insn_get(s, ot); + else + val = (int8_t)insn_get(s, OT_BYTE); + gen_op_movl_T0_im(val); + gen_push_T0(s); + break; + case 0x8f: /* pop Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + gen_pop_T0(s); + s->popl_esp_hack = 2 << dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + s->popl_esp_hack = 0; + gen_pop_update(s); + break; + case 0xc8: /* enter */ + { + int level; + val = lduw(s->pc); + s->pc += 2; + level = ldub(s->pc++); + gen_enter(s, val, level); + } + break; + case 0xc9: /* leave */ + /* XXX: exception not precise (ESP is updated before potential exception) */ + if (s->ss32) { + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_mov_reg_T0[OT_LONG][R_ESP](); + } else { + gen_op_mov_TN_reg[OT_WORD][0][R_EBP](); + gen_op_mov_reg_T0[OT_WORD][R_ESP](); + } + gen_pop_T0(s); + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_reg_T0[ot][R_EBP](); + gen_pop_update(s); + break; + case 0x06: /* push es */ + case 0x0e: /* push cs */ + case 0x16: /* push ss */ + case 0x1e: /* push ds */ + gen_op_movl_T0_seg(b >> 3); + gen_push_T0(s); + break; + case 0x1a0: /* push fs */ + case 0x1a8: /* push gs */ + gen_op_movl_T0_seg((b >> 3) & 7); + gen_push_T0(s); + break; + case 0x07: /* pop es */ + case 0x17: /* pop ss */ + case 0x1f: /* pop ds */ + reg = b >> 3; + gen_pop_T0(s); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); + gen_pop_update(s); + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x1a1: /* pop fs */ + case 0x1a9: /* pop gs */ + gen_pop_T0(s); + gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base); + gen_pop_update(s); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + + /**************************/ + /* mov */ + case 0x88: + case 0x89: /* mov Gv, Ev */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + /* generate a generic store */ + gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1); + break; + case 0xc6: + case 0xc7: /* mov Ev, Iv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + if (mod != 3) + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + val = insn_get(s, ot); + gen_op_movl_T0_im(val); + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][modrm & 7](); + break; + case 0x8a: + case 0x8b: /* mov Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_reg_T0[ot][reg](); + break; + case 0x8e: /* mov seg, Gv */ + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + if (reg >= 6 || reg == R_CS) + goto illegal_op; + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_movl_seg_T0(s, reg, pc_start - s->cs_base); + if (reg == R_SS) { + /* if reg == SS, inhibit interrupts/trace */ + gen_op_set_inhibit_irq(); + s->tf = 0; + } + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x8c: /* mov Gv, seg */ + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (reg >= 6) + goto illegal_op; + gen_op_movl_T0_seg(reg); + ot = OT_WORD; + if (mod == 3 && dflag) + ot = OT_LONG; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + + case 0x1b6: /* movzbS Gv, Eb */ + case 0x1b7: /* movzwS Gv, Eb */ + case 0x1be: /* movsbS Gv, Eb */ + case 0x1bf: /* movswS Gv, Eb */ + { + int d_ot; + /* d_ot is the size of destination */ + d_ot = dflag + OT_WORD; + /* ot is the size of source */ + ot = (b & 1) + OT_BYTE; + modrm = ldub(s->pc++); + reg = ((modrm >> 3) & 7) + OR_EAX; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + + if (mod == 3) { + gen_op_mov_TN_reg[ot][0][rm](); + switch(ot | (b & 8)) { + case OT_BYTE: + gen_op_movzbl_T0_T0(); + break; + case OT_BYTE | 8: + gen_op_movsbl_T0_T0(); + break; + case OT_WORD: + gen_op_movzwl_T0_T0(); + break; + default: + case OT_WORD | 8: + gen_op_movswl_T0_T0(); + break; + } + gen_op_mov_reg_T0[d_ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (b & 8) { + gen_op_lds_T0_A0[ot + s->mem_index](); + } else { + gen_op_ldu_T0_A0[ot + s->mem_index](); + } + gen_op_mov_reg_T0[d_ot][reg](); + } + } + break; + + case 0x8d: /* lea */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + /* we must ensure that no segment is added */ + s->override = -1; + val = s->addseg; + s->addseg = 0; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + s->addseg = val; + gen_op_mov_reg_A0[ot - OT_WORD][reg](); + break; + + case 0xa0: /* mov EAX, Ov */ + case 0xa1: + case 0xa2: /* mov Ov, EAX */ + case 0xa3: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (s->aflag) + offset_addr = insn_get(s, OT_LONG); + else + offset_addr = insn_get(s, OT_WORD); + gen_op_movl_A0_im(offset_addr); + /* handle override */ + { + int override, must_add_seg; + must_add_seg = s->addseg; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + if ((b & 2) == 0) { + gen_op_ld_T0_A0[ot + s->mem_index](); + gen_op_mov_reg_T0[ot][R_EAX](); + } else { + gen_op_mov_TN_reg[ot][0][R_EAX](); + gen_op_st_T0_A0[ot + s->mem_index](); + } + break; + case 0xd7: /* xlat */ + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + /* handle override */ + { + int override, must_add_seg; + must_add_seg = s->addseg; + override = R_DS; + if (s->override >= 0) { + override = s->override; + must_add_seg = 1; + } else { + override = R_DS; + } + if (must_add_seg) { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } + } + gen_op_ldu_T0_A0[OT_BYTE + s->mem_index](); + gen_op_mov_reg_T0[OT_BYTE][R_EAX](); + break; + case 0xb0 ... 0xb7: /* mov R, Ib */ + val = insn_get(s, OT_BYTE); + gen_op_movl_T0_im(val); + gen_op_mov_reg_T0[OT_BYTE][b & 7](); + break; + case 0xb8 ... 0xbf: /* mov R, Iv */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + reg = OR_EAX + (b & 7); + gen_op_movl_T0_im(val); + gen_op_mov_reg_T0[ot][reg](); + break; + + case 0x91 ... 0x97: /* xchg R, EAX */ + ot = dflag ? OT_LONG : OT_WORD; + reg = b & 7; + rm = R_EAX; + goto do_xchg_reg; + case 0x86: + case 0x87: /* xchg Ev, Gv */ + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) { + rm = modrm & 7; + do_xchg_reg: + gen_op_mov_TN_reg[ot][0][reg](); + gen_op_mov_TN_reg[ot][1][rm](); + gen_op_mov_reg_T0[ot][rm](); + gen_op_mov_reg_T1[ot][reg](); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_mov_TN_reg[ot][0][reg](); + /* for xchg, lock is implicit */ + if (!(prefixes & PREFIX_LOCK)) + gen_op_lock(); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (!(prefixes & PREFIX_LOCK)) + gen_op_unlock(); + gen_op_mov_reg_T1[ot][reg](); + } + break; + case 0xc4: /* les Gv */ + op = R_ES; + goto do_lxx; + case 0xc5: /* lds Gv */ + op = R_DS; + goto do_lxx; + case 0x1b2: /* lss Gv */ + op = R_SS; + goto do_lxx; + case 0x1b4: /* lfs Gv */ + op = R_FS; + goto do_lxx; + case 0x1b5: /* lgs Gv */ + op = R_GS; + do_lxx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); + /* load the segment first to handle exceptions properly */ + gen_op_lduw_T0_A0(); + gen_movl_seg_T0(s, op, pc_start - s->cs_base); + /* then put the data */ + gen_op_mov_reg_T1[ot][reg](); + if (s->is_jmp) { + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + + /************************/ + /* shifts */ + case 0xc0: + case 0xc1: + /* shift Ev,Ib */ + shift = 2; + grp2: + { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + opreg = OR_TMP0; + } else { + opreg = rm + OR_EAX; + } + + /* simpler op */ + if (shift == 0) { + gen_shift(s, op, ot, opreg, OR_ECX); + } else { + if (shift == 2) { + shift = ldub(s->pc++); + } + gen_shifti(s, op, ot, opreg, shift); + } + } + break; + case 0xd0: + case 0xd1: + /* shift Ev,1 */ + shift = 1; + goto grp2; + case 0xd2: + case 0xd3: + /* shift Ev,cl */ + shift = 0; + goto grp2; + + case 0x1a4: /* shld imm */ + op = 0; + shift = 1; + goto do_shiftd; + case 0x1a5: /* shld cl */ + op = 0; + shift = 0; + goto do_shiftd; + case 0x1ac: /* shrd imm */ + op = 1; + shift = 1; + goto do_shiftd; + case 0x1ad: /* shrd cl */ + op = 1; + shift = 0; + do_shiftd: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_mov_TN_reg[ot][1][reg](); + + if (shift) { + val = ldub(s->pc++); + val &= 0x1f; + if (val) { + if (mod == 3) + gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val); + else + gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val); + if (op == 0 && ot != OT_WORD) + s->cc_op = CC_OP_SHLB + ot; + else + s->cc_op = CC_OP_SARB + ot; + } + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (mod == 3) + gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op](); + else + gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ + } + if (mod == 3) { + gen_op_mov_reg_T0[ot][rm](); + } + break; + + /************************/ + /* floats */ + case 0xd8 ... 0xdf: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + rm = modrm & 7; + op = ((b & 7) << 3) | ((modrm >> 3) & 7); + + if (mod != 3) { + /* memory op */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + switch(op) { + case 0x00 ... 0x07: /* fxxxs */ + case 0x10 ... 0x17: /* fixxxl */ + case 0x20 ... 0x27: /* fxxxl */ + case 0x30 ... 0x37: /* fixxx */ + { + int op1; + op1 = op & 7; + + switch(op >> 4) { + case 0: + gen_op_flds_FT0_A0(); + break; + case 1: + gen_op_fildl_FT0_A0(); + break; + case 2: + gen_op_fldl_FT0_A0(); + break; + case 3: + default: + gen_op_fild_FT0_A0(); + break; + } + + gen_op_fp_arith_ST0_FT0[op1](); + if (op1 == 3) { + /* fcomp needs pop */ + gen_op_fpop(); + } + } + break; + case 0x08: /* flds */ + case 0x0a: /* fsts */ + case 0x0b: /* fstps */ + case 0x18: /* fildl */ + case 0x1a: /* fistl */ + case 0x1b: /* fistpl */ + case 0x28: /* fldl */ + case 0x2a: /* fstl */ + case 0x2b: /* fstpl */ + case 0x38: /* filds */ + case 0x3a: /* fists */ + case 0x3b: /* fistps */ + + switch(op & 7) { + case 0: + switch(op >> 4) { + case 0: + gen_op_flds_ST0_A0(); + break; + case 1: + gen_op_fildl_ST0_A0(); + break; + case 2: + gen_op_fldl_ST0_A0(); + break; + case 3: + default: + gen_op_fild_ST0_A0(); + break; + } + break; + default: + switch(op >> 4) { + case 0: + gen_op_fsts_ST0_A0(); + break; + case 1: + gen_op_fistl_ST0_A0(); + break; + case 2: + gen_op_fstl_ST0_A0(); + break; + case 3: + default: + gen_op_fist_ST0_A0(); + break; + } + if ((op & 7) == 3) + gen_op_fpop(); + break; + } + break; + case 0x0c: /* fldenv mem */ + gen_op_fldenv_A0(s->dflag); + break; + case 0x0d: /* fldcw mem */ + gen_op_fldcw_A0(); + break; + case 0x0e: /* fnstenv mem */ + gen_op_fnstenv_A0(s->dflag); + break; + case 0x0f: /* fnstcw mem */ + gen_op_fnstcw_A0(); + break; + case 0x1d: /* fldt mem */ + gen_op_fldt_ST0_A0(); + break; + case 0x1f: /* fstpt mem */ + gen_op_fstt_ST0_A0(); + gen_op_fpop(); + break; + case 0x2c: /* frstor mem */ + gen_op_frstor_A0(s->dflag); + break; + case 0x2e: /* fnsave mem */ + gen_op_fnsave_A0(s->dflag); + break; + case 0x2f: /* fnstsw mem */ + gen_op_fnstsw_A0(); + break; + case 0x3c: /* fbld */ + gen_op_fbld_ST0_A0(); + break; + case 0x3e: /* fbstp */ + gen_op_fbst_ST0_A0(); + gen_op_fpop(); + break; + case 0x3d: /* fildll */ + gen_op_fildll_ST0_A0(); + break; + case 0x3f: /* fistpll */ + gen_op_fistll_ST0_A0(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + } else { + /* register float ops */ + opreg = rm; + + switch(op) { + case 0x08: /* fld sti */ + gen_op_fpush(); + gen_op_fmov_ST0_STN((opreg + 1) & 7); + break; + case 0x09: /* fxchg sti */ + gen_op_fxchg_ST0_STN(opreg); + break; + case 0x0a: /* grp d9/2 */ + switch(rm) { + case 0: /* fnop */ + break; + default: + goto illegal_op; + } + break; + case 0x0c: /* grp d9/4 */ + switch(rm) { + case 0: /* fchs */ + gen_op_fchs_ST0(); + break; + case 1: /* fabs */ + gen_op_fabs_ST0(); + break; + case 4: /* ftst */ + gen_op_fldz_FT0(); + gen_op_fcom_ST0_FT0(); + break; + case 5: /* fxam */ + gen_op_fxam_ST0(); + break; + default: + goto illegal_op; + } + break; + case 0x0d: /* grp d9/5 */ + { + switch(rm) { + case 0: + gen_op_fpush(); + gen_op_fld1_ST0(); + break; + case 1: + gen_op_fpush(); + gen_op_fldl2t_ST0(); + break; + case 2: + gen_op_fpush(); + gen_op_fldl2e_ST0(); + break; + case 3: + gen_op_fpush(); + gen_op_fldpi_ST0(); + break; + case 4: + gen_op_fpush(); + gen_op_fldlg2_ST0(); + break; + case 5: + gen_op_fpush(); + gen_op_fldln2_ST0(); + break; + case 6: + gen_op_fpush(); + gen_op_fldz_ST0(); + break; + default: + goto illegal_op; + } + } + break; + case 0x0e: /* grp d9/6 */ + switch(rm) { + case 0: /* f2xm1 */ + gen_op_f2xm1(); + break; + case 1: /* fyl2x */ + gen_op_fyl2x(); + break; + case 2: /* fptan */ + gen_op_fptan(); + break; + case 3: /* fpatan */ + gen_op_fpatan(); + break; + case 4: /* fxtract */ + gen_op_fxtract(); + break; + case 5: /* fprem1 */ + gen_op_fprem1(); + break; + case 6: /* fdecstp */ + gen_op_fdecstp(); + break; + default: + case 7: /* fincstp */ + gen_op_fincstp(); + break; + } + break; + case 0x0f: /* grp d9/7 */ + switch(rm) { + case 0: /* fprem */ + gen_op_fprem(); + break; + case 1: /* fyl2xp1 */ + gen_op_fyl2xp1(); + break; + case 2: /* fsqrt */ + gen_op_fsqrt(); + break; + case 3: /* fsincos */ + gen_op_fsincos(); + break; + case 5: /* fscale */ + gen_op_fscale(); + break; + case 4: /* frndint */ + gen_op_frndint(); + break; + case 6: /* fsin */ + gen_op_fsin(); + break; + default: + case 7: /* fcos */ + gen_op_fcos(); + break; + } + break; + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ + { + int op1; + + op1 = op & 7; + if (op >= 0x20) { + gen_op_fp_arith_STN_ST0[op1](opreg); + if (op >= 0x30) + gen_op_fpop(); + } else { + gen_op_fmov_FT0_STN(opreg); + gen_op_fp_arith_ST0_FT0[op1](); + } + } + break; + case 0x02: /* fcom */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + break; + case 0x03: /* fcomp */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x15: /* da/5 */ + switch(rm) { + case 1: /* fucompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x1c: + switch(rm) { + case 0: /* feni (287 only, just do nop here) */ + break; + case 1: /* fdisi (287 only, just do nop here) */ + break; + case 2: /* fclex */ + gen_op_fclex(); + break; + case 3: /* fninit */ + gen_op_fninit(); + break; + case 4: /* fsetpm (287 only, just do nop here) */ + break; + default: + goto illegal_op; + } + break; + case 0x1d: /* fucomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x1e: /* fcomi */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2a: /* fst sti */ + gen_op_fmov_STN_ST0(opreg); + break; + case 0x2b: /* fstp sti */ + gen_op_fmov_STN_ST0(opreg); + gen_op_fpop(); + break; + case 0x2c: /* fucom st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + break; + case 0x2d: /* fucomp st(i) */ + gen_op_fmov_FT0_STN(opreg); + gen_op_fucom_ST0_FT0(); + gen_op_fpop(); + break; + case 0x33: /* de/3 */ + switch(rm) { + case 1: /* fcompp */ + gen_op_fmov_FT0_STN(1); + gen_op_fcom_ST0_FT0(); + gen_op_fpop(); + gen_op_fpop(); + break; + default: + goto illegal_op; + } + break; + case 0x3c: /* df/4 */ + switch(rm) { + case 0: + gen_op_fnstsw_EAX(); + break; + default: + goto illegal_op; + } + break; + case 0x3d: /* fucomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fucomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3e: /* fcomip */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_fmov_FT0_STN(opreg); + gen_op_fcomi_ST0_FT0(); + gen_op_fpop(); + s->cc_op = CC_OP_EFLAGS; + break; + default: + goto illegal_op; + } + } + break; + /************************/ + /* string ops */ + + case 0xa4: /* movsS */ + case 0xa5: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_movs(s, ot); + } + break; + + case 0xaa: /* stosS */ + case 0xab: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_stos(s, ot); + } + break; + case 0xac: /* lodsS */ + case 0xad: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_lods(s, ot); + } + break; + case 0xae: /* scasS */ + case 0xaf: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + } else if (prefixes & PREFIX_REPZ) { + gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + } else { + gen_scas(s, ot); + s->cc_op = CC_OP_SUBB + ot; + } + break; + + case 0xa6: /* cmpsS */ + case 0xa7: + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & PREFIX_REPNZ) { + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1); + } else if (prefixes & PREFIX_REPZ) { + gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0); + } else { + gen_cmps(s, ot); + s->cc_op = CC_OP_SUBB + ot; + } + break; + case 0x6c: /* insS */ + case 0x6d: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_ins(s, ot); + } + } + break; + case 0x6e: /* outsS */ + case 0x6f: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + /* NOTE: even for (E)CX = 0 the exception is raised */ + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) { + gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base); + } else { + gen_outs(s, ot); + } + } + break; + + /************************/ + /* port I/O */ + case 0xe4: + case 0xe5: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } + break; + case 0xe6: + case 0xe7: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + val = ldub(s->pc++); + gen_op_movl_T0_im(val); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } + break; + case 0xec: + case 0xed: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_in[ot](); + gen_op_mov_reg_T1[ot][R_EAX](); + } + break; + case 0xee: + case 0xef: + if (s->pe && (s->cpl > s->iopl || s->vm86)) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if ((b & 1) == 0) + ot = OT_BYTE; + else + ot = dflag ? OT_LONG : OT_WORD; + gen_op_mov_TN_reg[OT_WORD][0][R_EDX](); + gen_op_mov_TN_reg[ot][1][R_EAX](); + gen_op_out[ot](); + } + break; + + /************************/ + /* control */ + case 0xc2: /* ret im */ + val = ldsw(s->pc); + s->pc += 2; + gen_pop_T0(s); + gen_stack_update(s, val + (2 << s->dflag)); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 0xc3: /* ret */ + gen_pop_T0(s); + gen_pop_update(s); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + gen_op_jmp_T0(); + gen_eob(s); + break; + case 0xca: /* lret im */ + val = ldsw(s->pc); + s->pc += 2; + do_lret: + if (s->pe && !s->vm86) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lret_protected(s->dflag, val); + } else { + gen_stack_A0(s); + /* pop offset */ + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); + if (s->dflag == 0) + gen_op_andl_T0_ffff(); + /* NOTE: keeping EIP updated is not a problem in case of + exception */ + gen_op_jmp_T0(); + /* pop selector */ + gen_op_addl_A0_im(2 << s->dflag); + gen_op_ld_T0_A0[1 + s->dflag + s->mem_index](); + gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS])); + /* add stack offset */ + gen_stack_update(s, val + (4 << s->dflag)); + } + gen_eob(s); + break; + case 0xcb: /* lret */ + val = 0; + goto do_lret; + case 0xcf: /* iret */ + if (!s->pe) { + /* real mode */ + gen_op_iret_real(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } else if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_iret_protected(s->dflag); + s->cc_op = CC_OP_EFLAGS; + } + gen_eob(s); + break; + case 0xe8: /* call im */ + { + unsigned int next_eip; + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_movl_T0_im(next_eip); + gen_push_T0(s); + gen_jmp(s, val); + } + break; + case 0x9a: /* lcall im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + gen_op_movl_T0_im(selector); + gen_op_movl_T1_im(offset); + } + goto do_lcall; + case 0xe9: /* jmp */ + ot = dflag ? OT_LONG : OT_WORD; + val = insn_get(s, ot); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + break; + case 0xea: /* ljmp im */ + { + unsigned int selector, offset; + + ot = dflag ? OT_LONG : OT_WORD; + offset = insn_get(s, ot); + selector = insn_get(s, OT_WORD); + + gen_op_movl_T0_im(selector); + gen_op_movl_T1_im(offset); + } + goto do_ljmp; + case 0xeb: /* jmp Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + val += s->pc - s->cs_base; + if (s->dflag == 0) + val = val & 0xffff; + gen_jmp(s, val); + break; + case 0x70 ... 0x7f: /* jcc Jb */ + val = (int8_t)insn_get(s, OT_BYTE); + goto do_jcc; + case 0x180 ... 0x18f: /* jcc Jv */ + if (dflag) { + val = insn_get(s, OT_LONG); + } else { + val = (int16_t)insn_get(s, OT_WORD); + } + do_jcc: + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_jcc(s, b, val, next_eip); + break; + + case 0x190 ... 0x19f: /* setcc Gv */ + modrm = ldub(s->pc++); + gen_setcc(s, b); + gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); + break; + case 0x140 ... 0x14f: /* cmov Gv, Ev */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + gen_setcc(s, b); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[ot + s->mem_index](); + } else { + rm = modrm & 7; + gen_op_mov_TN_reg[ot][1][rm](); + } + gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); + break; + + /************************/ + /* flags */ + case 0x9c: /* pushf */ + if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movl_T0_eflags(); + gen_push_T0(s); + } + break; + case 0x9d: /* popf */ + if (s->vm86 && s->iopl != 3) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_pop_T0(s); + if (s->cpl == 0) { + if (s->dflag) { + gen_op_movl_eflags_T0_cpl0(); + } else { + gen_op_movw_eflags_T0_cpl0(); + } + } else { + if (s->dflag) { + gen_op_movl_eflags_T0(); + } else { + gen_op_movw_eflags_T0(); + } + } + gen_pop_update(s); + s->cc_op = CC_OP_EFLAGS; + /* abort translation because TF flag may change */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } + break; + case 0x9e: /* sahf */ + gen_op_mov_TN_reg[OT_BYTE][0][R_AH](); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movb_eflags_T0(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x9f: /* lahf */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_movl_T0_eflags(); + gen_op_mov_reg_T0[OT_BYTE][R_AH](); + break; + case 0xf5: /* cmc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_cmc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf8: /* clc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_clc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xf9: /* stc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_stc(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xfc: /* cld */ + gen_op_cld(); + break; + case 0xfd: /* std */ + gen_op_std(); + break; + + /************************/ + /* bit operations */ + case 0x1ba: /* bt/bts/btr/btc Gv, im */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + op = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + /* load shift */ + val = ldub(s->pc++); + gen_op_movl_T1_im(val); + if (op < 4) + goto illegal_op; + op -= 4; + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SARB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); + } + break; + case 0x1a3: /* bt Gv, Ev */ + op = 0; + goto do_btx; + case 0x1ab: /* bts */ + op = 1; + goto do_btx; + case 0x1b3: /* btr */ + op = 2; + goto do_btx; + case 0x1bb: /* btc */ + op = 3; + do_btx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + gen_op_mov_TN_reg[OT_LONG][1][reg](); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* specific case: we need to add a displacement */ + if (ot == OT_WORD) + gen_op_add_bitw_A0_T1(); + else + gen_op_add_bitl_A0_T1(); + gen_op_ld_T0_A0[ot + s->mem_index](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SARB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot + s->mem_index](); + else + gen_op_mov_reg_T0[ot][rm](); + gen_op_update_bt_cc(); + } + break; + case 0x1bc: /* bsf */ + case 0x1bd: /* bsr */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_bsx_T0_cc[ot - OT_WORD][b & 1](); + /* NOTE: we always write back the result. Intel doc says it is + undefined if T0 == 0 */ + gen_op_mov_reg_T0[ot][reg](); + s->cc_op = CC_OP_LOGICB + ot; + break; + /************************/ + /* bcd */ + case 0x27: /* daa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_daa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x2f: /* das */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_das(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x37: /* aaa */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aaa(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0x3f: /* aas */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_aas(); + s->cc_op = CC_OP_EFLAGS; + break; + case 0xd4: /* aam */ + val = ldub(s->pc++); + gen_op_aam(val); + s->cc_op = CC_OP_LOGICB; + break; + case 0xd5: /* aad */ + val = ldub(s->pc++); + gen_op_aad(val); + s->cc_op = CC_OP_LOGICB; + break; + /************************/ + /* misc */ + case 0x90: /* nop */ + break; + case 0x9b: /* fwait */ + break; + case 0xcc: /* int3 */ + gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base); + break; + case 0xcd: /* int N */ + val = ldub(s->pc++); + /* XXX: add error code for vm86 GPF */ + if (!s->vm86) + gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base); + else + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + break; + case 0xce: /* into */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_into(s->pc - s->cs_base); + break; + case 0xf1: /* icebp (undocumented, exits to external debugger) */ + gen_debug(s, pc_start - s->cs_base); + break; + case 0xfa: /* cli */ + if (!s->vm86) { + if (s->cpl <= s->iopl) { + gen_op_cli(); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } else { + if (s->iopl == 3) { + gen_op_cli(); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } + break; + case 0xfb: /* sti */ + if (!s->vm86) { + if (s->cpl <= s->iopl) { + gen_sti: + gen_op_sti(); + /* interruptions are enabled only the first insn after sti */ + gen_op_set_inhibit_irq(); + /* give a chance to handle pending irqs */ + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } else { + if (s->iopl == 3) { + goto gen_sti; + } else { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } + } + break; + case 0x62: /* bound */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + if (mod == 3) + goto illegal_op; + gen_op_mov_reg_T0[ot][reg](); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (ot == OT_WORD) + gen_op_boundw(pc_start - s->cs_base); + else + gen_op_boundl(pc_start - s->cs_base); + break; + case 0x1c8 ... 0x1cf: /* bswap reg */ + reg = b & 7; + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + case 0xd6: /* salc */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_salc(); + break; + case 0xe0: /* loopnz */ + case 0xe1: /* loopz */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + /* FALL THRU */ + case 0xe2: /* loop */ + case 0xe3: /* jecxz */ + val = (int8_t)insn_get(s, OT_BYTE); + next_eip = s->pc - s->cs_base; + val += next_eip; + if (s->dflag == 0) + val &= 0xffff; + gen_op_loop[s->aflag][b & 3](val, next_eip); + gen_eob(s); + break; + case 0x130: /* wrmsr */ + case 0x132: /* rdmsr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (b & 2) + gen_op_rdmsr(); + else + gen_op_wrmsr(); + } + break; + case 0x131: /* rdtsc */ + gen_op_rdtsc(); + break; + case 0x1a2: /* cpuid */ + gen_op_cpuid(); + break; + case 0xf4: /* hlt */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(s->pc - s->cs_base); + gen_op_hlt(); + s->is_jmp = 3; + } + break; + case 0x100: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sldt */ + gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 2: /* lldt */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_lldt_T0(); + } + break; + case 1: /* str */ + gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector)); + ot = OT_WORD; + if (mod == 3) + ot += s->dflag; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); + break; + case 3: /* ltr */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_ltr_T0(); + } + break; + case 4: /* verr */ + case 5: /* verw */ + default: + goto illegal_op; + } + break; + case 0x101: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* sgdt */ + case 1: /* sidt */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_op_addl_A0_im(2); + if (op == 0) + gen_op_movl_T0_env(offsetof(CPUX86State,gdt.base)); + else + gen_op_movl_T0_env(offsetof(CPUX86State,idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[OT_LONG + s->mem_index](); + break; + case 2: /* lgdt */ + case 3: /* lidt */ + if (mod == 3) + goto illegal_op; + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T1_A0[OT_WORD + s->mem_index](); + gen_op_addl_A0_im(2); + gen_op_ld_T0_A0[OT_LONG + s->mem_index](); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + if (op == 2) { + gen_op_movl_env_T0(offsetof(CPUX86State,gdt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit)); + } else { + gen_op_movl_env_T0(offsetof(CPUX86State,idt.base)); + gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit)); + } + } + break; + case 4: /* smsw */ + gen_op_movl_T0_env(offsetof(CPUX86State,cr[0])); + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1); + break; + case 6: /* lmsw */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); + gen_op_lmsw_T0(); + } + break; + case 7: /* invlpg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_invlpg_A0(); + } + break; + default: + goto illegal_op; + } + break; + case 0x102: /* lar */ + case 0x103: /* lsl */ + if (!s->pe || s->vm86) + goto illegal_op; + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); + gen_op_mov_TN_reg[ot][1][reg](); + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + if (b == 0x102) + gen_op_lar(); + else + gen_op_lsl(); + s->cc_op = CC_OP_EFLAGS; + gen_op_mov_reg_T1[ot][reg](); + break; + case 0x118: + modrm = ldub(s->pc++); + mod = (modrm >> 6) & 3; + op = (modrm >> 3) & 7; + switch(op) { + case 0: /* prefetchnta */ + case 1: /* prefetchnt0 */ + case 2: /* prefetchnt0 */ + case 3: /* prefetchnt0 */ + if (mod == 3) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* nothing more to do */ + break; + default: + goto illegal_op; + } + break; + case 0x120: /* mov reg, crN */ + case 0x122: /* mov crN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + switch(reg) { + case 0: + case 2: + case 3: + case 4: + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_crN_T0(reg); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,cr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + break; + default: + goto illegal_op; + } + } + break; + case 0x121: /* mov reg, drN */ + case 0x123: /* mov drN, reg */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + modrm = ldub(s->pc++); + if ((modrm & 0xc0) != 0xc0) + goto illegal_op; + rm = modrm & 7; + reg = (modrm >> 3) & 7; + /* XXX: do it dynamically with CR4.DE bit */ + if (reg == 4 || reg == 5) + goto illegal_op; + if (b & 2) { + gen_op_mov_TN_reg[OT_LONG][0][rm](); + gen_op_movl_drN_T0(reg); + gen_op_jmp_im(s->pc - s->cs_base); + gen_eob(s); + } else { + gen_op_movl_T0_env(offsetof(CPUX86State,dr[reg])); + gen_op_mov_reg_T0[OT_LONG][rm](); + } + } + break; + case 0x106: /* clts */ + if (s->cpl != 0) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + gen_op_clts(); + } + break; + default: + goto illegal_op; + } + /* lock generation */ + if (s->prefix & PREFIX_LOCK) + gen_op_unlock(); + return s->pc; + illegal_op: + /* XXX: ensure that no lock was generated */ + gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); + return s->pc; +} + +#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) +#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P) + +/* flags read by an operation */ +static uint16_t opc_read_flags[NB_OPS] = { + [INDEX_op_aas] = CC_A, + [INDEX_op_aaa] = CC_A, + [INDEX_op_das] = CC_A | CC_C, + [INDEX_op_daa] = CC_A | CC_C, + + [INDEX_op_adcb_T0_T1_cc] = CC_C, + [INDEX_op_adcw_T0_T1_cc] = CC_C, + [INDEX_op_adcl_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_T0_T1_cc] = CC_C, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_C, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C, + + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_C, + + [INDEX_op_into] = CC_O, + + [INDEX_op_jb_subb] = CC_C, + [INDEX_op_jb_subw] = CC_C, + [INDEX_op_jb_subl] = CC_C, + + [INDEX_op_jz_subb] = CC_Z, + [INDEX_op_jz_subw] = CC_Z, + [INDEX_op_jz_subl] = CC_Z, + + [INDEX_op_jbe_subb] = CC_Z | CC_C, + [INDEX_op_jbe_subw] = CC_Z | CC_C, + [INDEX_op_jbe_subl] = CC_Z | CC_C, + + [INDEX_op_js_subb] = CC_S, + [INDEX_op_js_subw] = CC_S, + [INDEX_op_js_subl] = CC_S, + + [INDEX_op_jl_subb] = CC_O | CC_S, + [INDEX_op_jl_subw] = CC_O | CC_S, + [INDEX_op_jl_subl] = CC_O | CC_S, + + [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_loopnzw] = CC_Z, + [INDEX_op_loopnzl] = CC_Z, + [INDEX_op_loopzw] = CC_Z, + [INDEX_op_loopzl] = CC_Z, + + [INDEX_op_seto_T0_cc] = CC_O, + [INDEX_op_setb_T0_cc] = CC_C, + [INDEX_op_setz_T0_cc] = CC_Z, + [INDEX_op_setbe_T0_cc] = CC_Z | CC_C, + [INDEX_op_sets_T0_cc] = CC_S, + [INDEX_op_setp_T0_cc] = CC_P, + [INDEX_op_setl_T0_cc] = CC_O | CC_S, + [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z, + + [INDEX_op_setb_T0_subb] = CC_C, + [INDEX_op_setb_T0_subw] = CC_C, + [INDEX_op_setb_T0_subl] = CC_C, + + [INDEX_op_setz_T0_subb] = CC_Z, + [INDEX_op_setz_T0_subw] = CC_Z, + [INDEX_op_setz_T0_subl] = CC_Z, + + [INDEX_op_setbe_T0_subb] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subw] = CC_Z | CC_C, + [INDEX_op_setbe_T0_subl] = CC_Z | CC_C, + + [INDEX_op_sets_T0_subb] = CC_S, + [INDEX_op_sets_T0_subw] = CC_S, + [INDEX_op_sets_T0_subl] = CC_S, + + [INDEX_op_setl_T0_subb] = CC_O | CC_S, + [INDEX_op_setl_T0_subw] = CC_O | CC_S, + [INDEX_op_setl_T0_subl] = CC_O | CC_S, + + [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z, + [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z, + + [INDEX_op_movl_T0_eflags] = CC_OSZAPC, + [INDEX_op_cmc] = CC_C, + [INDEX_op_salc] = CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C, +}; + +/* flags written by an operation */ +static uint16_t opc_write_flags[NB_OPS] = { + [INDEX_op_update2_cc] = CC_OSZAPC, + [INDEX_op_update1_cc] = CC_OSZAPC, + [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_update_neg_cc] = CC_OSZAPC, + /* subtle: due to the incl/decl implementation, C is used */ + [INDEX_op_update_inc_cc] = CC_OSZAPC, + [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_mulb_AL_T0] = CC_OSZAPC, + [INDEX_op_imulb_AL_T0] = CC_OSZAPC, + [INDEX_op_mulw_AX_T0] = CC_OSZAPC, + [INDEX_op_imulw_AX_T0] = CC_OSZAPC, + [INDEX_op_mull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imull_EAX_T0] = CC_OSZAPC, + [INDEX_op_imulw_T0_T1] = CC_OSZAPC, + [INDEX_op_imull_T0_T1] = CC_OSZAPC, + + /* bcd */ + [INDEX_op_aam] = CC_OSZAPC, + [INDEX_op_aad] = CC_OSZAPC, + [INDEX_op_aas] = CC_OSZAPC, + [INDEX_op_aaa] = CC_OSZAPC, + [INDEX_op_das] = CC_OSZAPC, + [INDEX_op_daa] = CC_OSZAPC, + + [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C, + [INDEX_op_movw_eflags_T0] = CC_OSZAPC, + [INDEX_op_movl_eflags_T0] = CC_OSZAPC, + [INDEX_op_clc] = CC_C, + [INDEX_op_stc] = CC_C, + [INDEX_op_cmc] = CC_C, + + [INDEX_op_rolb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C, + [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C, + + [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC, + [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC, + [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC, + + [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC, + [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC, + + [INDEX_op_bsfw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsfl_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrw_T0_cc] = CC_OSZAPC, + [INDEX_op_bsrl_T0_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC, + [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC, + + [INDEX_op_cmpxchg8b] = CC_Z, + [INDEX_op_lar] = CC_Z, + [INDEX_op_lsl] = CC_Z, + [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C, + [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C, +}; + +/* simpler form of an operation if no flags need to be generated */ +static uint16_t opc_simpler[NB_OPS] = { + [INDEX_op_update2_cc] = INDEX_op_nop, + [INDEX_op_update1_cc] = INDEX_op_nop, + [INDEX_op_update_neg_cc] = INDEX_op_nop, +#if 0 + /* broken: CC_OP logic must be rewritten */ + [INDEX_op_update_inc_cc] = INDEX_op_nop, +#endif + [INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1, + [INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1, + [INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1, + + [INDEX_op_rorb_T0_T1_cc] = INDEX_op_rorb_T0_T1, + [INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1, + [INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1, + + [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1, + [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1, + [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1, + + [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1, + [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1, + [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1, + + [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1, + [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1, + [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1, + + [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1, + [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1, + [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1, + + [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1, + [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1, + [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1, +}; + +void optimize_flags_init(void) +{ + int i; + /* put default values in arrays */ + for(i = 0; i < NB_OPS; i++) { + if (opc_simpler[i] == 0) + opc_simpler[i] = i; + } +} + +/* CPU flags computation optimization: we move backward thru the + generated code to see which flags are needed. The operation is + modified if suitable */ +static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) +{ + uint16_t *opc_ptr; + int live_flags, write_flags, op; + + opc_ptr = opc_buf + opc_buf_len; + /* live_flags contains the flags needed by the next instructions + in the code. At the end of the bloc, we consider that all the + flags are live. */ + live_flags = CC_OSZAPC; + while (opc_ptr > opc_buf) { + op = *--opc_ptr; + /* if none of the flags written by the instruction is used, + then we can try to find a simpler instruction */ + write_flags = opc_write_flags[op]; + if ((live_flags & write_flags) == 0) { + *opc_ptr = opc_simpler[op]; + } + /* compute the live flags before the instruction */ + live_flags &= ~write_flags; + live_flags |= opc_read_flags[op]; + } +} + +/* generate intermediate code in gen_opc_buf and gen_opparam_buf for + basic block 'tb'. If search_pc is TRUE, also generate PC + information for each intermediate instruction. */ +static inline int gen_intermediate_code_internal(CPUState *env, + TranslationBlock *tb, + int search_pc) +{ + DisasContext dc1, *dc = &dc1; + uint8_t *pc_ptr; + uint16_t *gen_opc_end; + int flags, j, lj; + uint8_t *pc_start; + uint8_t *cs_base; + + /* generate intermediate code */ + pc_start = (uint8_t *)tb->pc; + cs_base = (uint8_t *)tb->cs_base; + flags = tb->flags; + + dc->pe = env->cr[0] & CR0_PE_MASK; + dc->code32 = (flags >> HF_CS32_SHIFT) & 1; + dc->ss32 = (flags >> HF_SS32_SHIFT) & 1; + dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1; + dc->f_st = 0; + dc->vm86 = (flags >> VM_SHIFT) & 1; + dc->cpl = (flags >> HF_CPL_SHIFT) & 3; + dc->iopl = (flags >> IOPL_SHIFT) & 3; + dc->tf = (flags >> TF_SHIFT) & 1; + dc->cc_op = CC_OP_DYNAMIC; + dc->cs_base = cs_base; + dc->tb = tb; + dc->popl_esp_hack = 0; + /* select memory access functions */ + dc->mem_index = 0; + if (flags & HF_SOFTMMU_MASK) { + if (dc->cpl == 3) + dc->mem_index = 6; + else + dc->mem_index = 3; + } + dc->jmp_opt = !(dc->tf || env->singlestep_enabled +#ifndef CONFIG_SOFT_MMU + || (flags & HF_SOFTMMU_MASK) +#endif + ); + gen_opc_ptr = gen_opc_buf; + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + gen_opparam_ptr = gen_opparam_buf; + + dc->is_jmp = DISAS_NEXT; + pc_ptr = pc_start; + lj = -1; + + /* if irq were inhibited for the next instruction, we can disable + them here as it is simpler (otherwise jumps would have to + handled as special case) */ + if (flags & HF_INHIBIT_IRQ_MASK) { + gen_op_reset_inhibit_irq(); + } + for(;;) { + if (env->nb_breakpoints > 0) { + for(j = 0; j < env->nb_breakpoints; j++) { + if (env->breakpoints[j] == (unsigned long)pc_ptr) { + gen_debug(dc, pc_ptr - dc->cs_base); + break; + } + } + } + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = (uint32_t)pc_ptr; + gen_opc_cc_op[lj] = dc->cc_op; + gen_opc_instr_start[lj] = 1; + } + pc_ptr = disas_insn(dc, pc_ptr); + /* stop translation if indicated */ + if (dc->is_jmp) + break; + /* if single step mode, we generate only one instruction and + generate an exception */ + if (dc->tf) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } + /* if too long translation, stop generation too */ + if (gen_opc_ptr >= gen_opc_end || + (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) { + gen_op_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } + } + *gen_opc_ptr = INDEX_op_end; + /* we don't forget to fill the last values */ + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "----------------\n"); + fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); + disas(logfile, pc_start, pc_ptr - pc_start, 0, !dc->code32); + fprintf(logfile, "\n"); + + fprintf(logfile, "OP:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + + /* optimize flag computations */ + optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf); + +#ifdef DEBUG_DISAS + if (loglevel) { + fprintf(logfile, "AFTER FLAGS OPT:\n"); + dump_ops(gen_opc_buf, gen_opparam_buf); + fprintf(logfile, "\n"); + } +#endif + if (!search_pc) + tb->size = pc_ptr - pc_start; + return 0; +} + +int gen_intermediate_code(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 0); +} + +int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb) +{ + return gen_intermediate_code_internal(env, tb, 1); +} + |