summaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-09-30 20:34:21 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-09-30 20:34:21 +0000
commit2c0262afa75d7d6cb68217f9a7587170ed3cd5b3 (patch)
tree4f8130ebaf041129d5aabede251eb87f3a1fa559 /target-i386
parent196ad10903ee4c2148f296600f537d7028ea845d (diff)
downloadqemu-2c0262afa75d7d6cb68217f9a7587170ed3cd5b3.tar.gz
new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@385 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.h401
-rw-r--r--target-i386/exec.h416
-rw-r--r--target-i386/helper.c1803
-rw-r--r--target-i386/helper2.c390
-rw-r--r--target-i386/op.c2054
-rw-r--r--target-i386/opreg_template.h134
-rw-r--r--target-i386/ops_mem.h66
-rw-r--r--target-i386/ops_template.h617
-rw-r--r--target-i386/ops_template_mem.h429
-rw-r--r--target-i386/translate.c4487
10 files changed, 10797 insertions, 0 deletions
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
new file mode 100644
index 0000000000..ffc4654d34
--- /dev/null
+++ b/target-i386/cpu.h
@@ -0,0 +1,401 @@
+/*
+ * i386 virtual CPU header
+ *
+ * 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
+ */
+#ifndef CPU_I386_H
+#define CPU_I386_H
+
+#include "cpu-defs.h"
+
+#define R_EAX 0
+#define R_ECX 1
+#define R_EDX 2
+#define R_EBX 3
+#define R_ESP 4
+#define R_EBP 5
+#define R_ESI 6
+#define R_EDI 7
+
+#define R_AL 0
+#define R_CL 1
+#define R_DL 2
+#define R_BL 3
+#define R_AH 4
+#define R_CH 5
+#define R_DH 6
+#define R_BH 7
+
+#define R_ES 0
+#define R_CS 1
+#define R_SS 2
+#define R_DS 3
+#define R_FS 4
+#define R_GS 5
+
+/* segment descriptor fields */
+#define DESC_G_MASK (1 << 23)
+#define DESC_B_SHIFT 22
+#define DESC_B_MASK (1 << DESC_B_SHIFT)
+#define DESC_AVL_MASK (1 << 20)
+#define DESC_P_MASK (1 << 15)
+#define DESC_DPL_SHIFT 13
+#define DESC_S_MASK (1 << 12)
+#define DESC_TYPE_SHIFT 8
+#define DESC_A_MASK (1 << 8)
+
+#define DESC_CS_MASK (1 << 11)
+#define DESC_C_MASK (1 << 10)
+#define DESC_R_MASK (1 << 9)
+
+#define DESC_E_MASK (1 << 10)
+#define DESC_W_MASK (1 << 9)
+
+/* eflags masks */
+#define CC_C 0x0001
+#define CC_P 0x0004
+#define CC_A 0x0010
+#define CC_Z 0x0040
+#define CC_S 0x0080
+#define CC_O 0x0800
+
+#define TF_SHIFT 8
+#define IOPL_SHIFT 12
+#define VM_SHIFT 17
+
+#define TF_MASK 0x00000100
+#define IF_MASK 0x00000200
+#define DF_MASK 0x00000400
+#define IOPL_MASK 0x00003000
+#define NT_MASK 0x00004000
+#define RF_MASK 0x00010000
+#define VM_MASK 0x00020000
+#define AC_MASK 0x00040000
+#define VIF_MASK 0x00080000
+#define VIP_MASK 0x00100000
+#define ID_MASK 0x00200000
+
+/* hidden flags - used internally by qemu to represent additionnal cpu
+ states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid
+ using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
+ with eflags. */
+/* current cpl */
+#define HF_CPL_SHIFT 0
+/* true if soft mmu is being used */
+#define HF_SOFTMMU_SHIFT 2
+/* true if hardware interrupts must be disabled for next instruction */
+#define HF_INHIBIT_IRQ_SHIFT 3
+/* 16 or 32 segments */
+#define HF_CS32_SHIFT 4
+#define HF_SS32_SHIFT 5
+/* zero base for DS, ES and SS */
+#define HF_ADDSEG_SHIFT 6
+
+#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
+#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
+#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
+#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
+#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
+#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
+
+#define CR0_PE_MASK (1 << 0)
+#define CR0_TS_MASK (1 << 3)
+#define CR0_WP_MASK (1 << 16)
+#define CR0_AM_MASK (1 << 18)
+#define CR0_PG_MASK (1 << 31)
+
+#define CR4_VME_MASK (1 << 0)
+#define CR4_PVI_MASK (1 << 1)
+#define CR4_TSD_MASK (1 << 2)
+#define CR4_DE_MASK (1 << 3)
+#define CR4_PSE_MASK (1 << 4)
+
+#define PG_PRESENT_BIT 0
+#define PG_RW_BIT 1
+#define PG_USER_BIT 2
+#define PG_PWT_BIT 3
+#define PG_PCD_BIT 4
+#define PG_ACCESSED_BIT 5
+#define PG_DIRTY_BIT 6
+#define PG_PSE_BIT 7
+#define PG_GLOBAL_BIT 8
+
+#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
+#define PG_RW_MASK (1 << PG_RW_BIT)
+#define PG_USER_MASK (1 << PG_USER_BIT)
+#define PG_PWT_MASK (1 << PG_PWT_BIT)
+#define PG_PCD_MASK (1 << PG_PCD_BIT)
+#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
+#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
+#define PG_PSE_MASK (1 << PG_PSE_BIT)
+#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
+
+#define PG_ERROR_W_BIT 1
+
+#define PG_ERROR_P_MASK 0x01
+#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
+#define PG_ERROR_U_MASK 0x04
+#define PG_ERROR_RSVD_MASK 0x08
+
+#define MSR_IA32_APICBASE 0x1b
+#define MSR_IA32_APICBASE_BSP (1<<8)
+#define MSR_IA32_APICBASE_ENABLE (1<<11)
+#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+
+#define MSR_IA32_SYSENTER_CS 0x174
+#define MSR_IA32_SYSENTER_ESP 0x175
+#define MSR_IA32_SYSENTER_EIP 0x176
+
+#define EXCP00_DIVZ 0
+#define EXCP01_SSTP 1
+#define EXCP02_NMI 2
+#define EXCP03_INT3 3
+#define EXCP04_INTO 4
+#define EXCP05_BOUND 5
+#define EXCP06_ILLOP 6
+#define EXCP07_PREX 7
+#define EXCP08_DBLE 8
+#define EXCP09_XERR 9
+#define EXCP0A_TSS 10
+#define EXCP0B_NOSEG 11
+#define EXCP0C_STACK 12
+#define EXCP0D_GPF 13
+#define EXCP0E_PAGE 14
+#define EXCP10_COPR 16
+#define EXCP11_ALGN 17
+#define EXCP12_MCHK 18
+
+enum {
+ CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
+ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
+ CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
+
+ CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+ CC_OP_ADDW,
+ CC_OP_ADDL,
+
+ CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+ CC_OP_ADCW,
+ CC_OP_ADCL,
+
+ CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+ CC_OP_SUBW,
+ CC_OP_SUBL,
+
+ CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+ CC_OP_SBBW,
+ CC_OP_SBBL,
+
+ CC_OP_LOGICB, /* modify all flags, CC_DST = res */
+ CC_OP_LOGICW,
+ CC_OP_LOGICL,
+
+ CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
+ CC_OP_INCW,
+ CC_OP_INCL,
+
+ CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
+ CC_OP_DECW,
+ CC_OP_DECL,
+
+ CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
+ CC_OP_SHLW,
+ CC_OP_SHLL,
+
+ CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
+ CC_OP_SARW,
+ CC_OP_SARL,
+
+ CC_OP_NB,
+};
+
+#ifdef __i386__
+#define USE_X86LDOUBLE
+#endif
+
+#ifdef USE_X86LDOUBLE
+typedef long double CPU86_LDouble;
+#else
+typedef double CPU86_LDouble;
+#endif
+
+typedef struct SegmentCache {
+ uint32_t selector;
+ uint8_t *base;
+ uint32_t limit;
+ uint32_t flags;
+} SegmentCache;
+
+typedef struct CPUX86State {
+ /* standard registers */
+ uint32_t regs[8];
+ uint32_t eip;
+ uint32_t eflags; /* eflags register. During CPU emulation, CC
+ flags and DF are set to zero because they are
+ stored elsewhere */
+
+ /* emulator internal eflags handling */
+ uint32_t cc_src;
+ uint32_t cc_dst;
+ uint32_t cc_op;
+ int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
+ uint32_t hflags; /* hidden flags, see HF_xxx constants */
+
+ /* FPU state */
+ unsigned int fpstt; /* top of stack index */
+ unsigned int fpus;
+ unsigned int fpuc;
+ uint8_t fptags[8]; /* 0 = valid, 1 = empty */
+ CPU86_LDouble fpregs[8];
+
+ /* emulator internal variables */
+ CPU86_LDouble ft0;
+ union {
+ float f;
+ double d;
+ int i32;
+ int64_t i64;
+ } fp_convert;
+
+ /* segments */
+ SegmentCache segs[6]; /* selector values */
+ SegmentCache ldt;
+ SegmentCache tr;
+ SegmentCache gdt; /* only base and limit are used */
+ SegmentCache idt; /* only base and limit are used */
+
+ /* sysenter registers */
+ uint32_t sysenter_cs;
+ uint32_t sysenter_esp;
+ uint32_t sysenter_eip;
+
+ /* exception/interrupt handling */
+ jmp_buf jmp_env;
+ int exception_index;
+ int error_code;
+ int exception_is_int;
+ int exception_next_eip;
+ struct TranslationBlock *current_tb; /* currently executing TB */
+ uint32_t cr[5]; /* NOTE: cr1 is unused */
+ uint32_t dr[8]; /* debug registers */
+ int interrupt_request;
+ int user_mode_only; /* user mode only simulation */
+
+ /* soft mmu support */
+ /* 0 = kernel, 1 = user */
+ CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
+ CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
+
+ /* ice debug support */
+ uint32_t breakpoints[MAX_BREAKPOINTS];
+ int nb_breakpoints;
+ int singlestep_enabled;
+
+ /* user data */
+ void *opaque;
+} CPUX86State;
+
+#ifndef IN_OP_I386
+void cpu_x86_outb(CPUX86State *env, int addr, int val);
+void cpu_x86_outw(CPUX86State *env, int addr, int val);
+void cpu_x86_outl(CPUX86State *env, int addr, int val);
+int cpu_x86_inb(CPUX86State *env, int addr);
+int cpu_x86_inw(CPUX86State *env, int addr);
+int cpu_x86_inl(CPUX86State *env, int addr);
+#endif
+
+CPUX86State *cpu_x86_init(void);
+int cpu_x86_exec(CPUX86State *s);
+void cpu_x86_close(CPUX86State *s);
+int cpu_x86_get_pic_interrupt(CPUX86State *s);
+
+/* this function must always be used to load data in the segment
+ cache: it synchronizes the hflags with the segment cache values */
+static inline void cpu_x86_load_seg_cache(CPUX86State *env,
+ int seg_reg, unsigned int selector,
+ uint8_t *base, unsigned int limit,
+ unsigned int flags)
+{
+ SegmentCache *sc;
+ unsigned int new_hflags;
+
+ sc = &env->segs[seg_reg];
+ sc->selector = selector;
+ sc->base = base;
+ sc->limit = limit;
+ sc->flags = flags;
+
+ /* update the hidden flags */
+ new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
+ >> (DESC_B_SHIFT - HF_CS32_SHIFT);
+ new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
+ >> (DESC_B_SHIFT - HF_SS32_SHIFT);
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ /* XXX: try to avoid this test. The problem comes from the
+ fact that is real mode or vm86 mode we only modify the
+ 'base' and 'selector' fields of the segment cache to go
+ faster. A solution may be to force addseg to one in
+ translate-i386.c. */
+ new_hflags |= HF_ADDSEG_MASK;
+ } else {
+ new_hflags |= (((unsigned long)env->segs[R_DS].base |
+ (unsigned long)env->segs[R_ES].base |
+ (unsigned long)env->segs[R_SS].base) != 0) <<
+ HF_ADDSEG_SHIFT;
+ }
+ env->hflags = (env->hflags &
+ ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
+}
+
+/* wrapper, just in case memory mappings must be changed */
+static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
+{
+#if HF_CPL_MASK == 3
+ s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
+#else
+#error HF_CPL_MASK is hardcoded
+#endif
+}
+
+/* the following helpers are only usable in user mode simulation as
+ they can trigger unexpected exceptions */
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
+void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
+void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
+
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+ signal handlers to inform the virtual CPU of exceptions. non zero
+ is returned if the signal was handled by the virtual CPU. */
+struct siginfo;
+int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
+ void *puc);
+
+/* MMU defines */
+void cpu_x86_init_mmu(CPUX86State *env);
+extern int phys_ram_size;
+extern int phys_ram_fd;
+extern uint8_t *phys_ram_base;
+
+/* used to debug */
+#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
+#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
+void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
+
+#define TARGET_PAGE_BITS 12
+#include "cpu-all.h"
+
+#endif /* CPU_I386_H */
diff --git a/target-i386/exec.h b/target-i386/exec.h
new file mode 100644
index 0000000000..b53928c98e
--- /dev/null
+++ b/target-i386/exec.h
@@ -0,0 +1,416 @@
+/*
+ * i386 execution defines
+ *
+ * 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 "dyngen-exec.h"
+
+/* at least 4 register variables are defines */
+register struct CPUX86State *env asm(AREG0);
+register uint32_t T0 asm(AREG1);
+register uint32_t T1 asm(AREG2);
+register uint32_t T2 asm(AREG3);
+
+#define A0 T2
+
+/* if more registers are available, we define some registers too */
+#ifdef AREG4
+register uint32_t EAX asm(AREG4);
+#define reg_EAX
+#endif
+
+#ifdef AREG5
+register uint32_t ESP asm(AREG5);
+#define reg_ESP
+#endif
+
+#ifdef AREG6
+register uint32_t EBP asm(AREG6);
+#define reg_EBP
+#endif
+
+#ifdef AREG7
+register uint32_t ECX asm(AREG7);
+#define reg_ECX
+#endif
+
+#ifdef AREG8
+register uint32_t EDX asm(AREG8);
+#define reg_EDX
+#endif
+
+#ifdef AREG9
+register uint32_t EBX asm(AREG9);
+#define reg_EBX
+#endif
+
+#ifdef AREG10
+register uint32_t ESI asm(AREG10);
+#define reg_ESI
+#endif
+
+#ifdef AREG11
+register uint32_t EDI asm(AREG11);
+#define reg_EDI
+#endif
+
+extern FILE *logfile;
+extern int loglevel;
+
+#ifndef reg_EAX
+#define EAX (env->regs[R_EAX])
+#endif
+#ifndef reg_ECX
+#define ECX (env->regs[R_ECX])
+#endif
+#ifndef reg_EDX
+#define EDX (env->regs[R_EDX])
+#endif
+#ifndef reg_EBX
+#define EBX (env->regs[R_EBX])
+#endif
+#ifndef reg_ESP
+#define ESP (env->regs[R_ESP])
+#endif
+#ifndef reg_EBP
+#define EBP (env->regs[R_EBP])
+#endif
+#ifndef reg_ESI
+#define ESI (env->regs[R_ESI])
+#endif
+#ifndef reg_EDI
+#define EDI (env->regs[R_EDI])
+#endif
+#define EIP (env->eip)
+#define DF (env->df)
+
+#define CC_SRC (env->cc_src)
+#define CC_DST (env->cc_dst)
+#define CC_OP (env->cc_op)
+
+/* float macros */
+#define FT0 (env->ft0)
+#define ST0 (env->fpregs[env->fpstt])
+#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
+#define ST1 ST(1)
+
+#ifdef USE_FP_CONVERT
+#define FP_CONVERT (env->fp_convert)
+#endif
+
+#include "cpu.h"
+#include "exec-all.h"
+
+typedef struct CCTable {
+ int (*compute_all)(void); /* return all the flags */
+ int (*compute_c)(void); /* return the C flag */
+} CCTable;
+
+extern CCTable cc_table[];
+
+void load_seg(int seg_reg, int selector, unsigned cur_eip);
+void helper_ljmp_protected_T0_T1(void);
+void helper_lcall_real_T0_T1(int shift, int next_eip);
+void helper_lcall_protected_T0_T1(int shift, int next_eip);
+void helper_iret_real(int shift);
+void helper_iret_protected(int shift);
+void helper_lret_protected(int shift, int addend);
+void helper_lldt_T0(void);
+void helper_ltr_T0(void);
+void helper_movl_crN_T0(int reg);
+void helper_movl_drN_T0(int reg);
+void helper_invlpg(unsigned int addr);
+void cpu_x86_update_cr0(CPUX86State *env);
+void cpu_x86_update_cr3(CPUX86State *env);
+void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr);
+int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write);
+void tlb_fill(unsigned long addr, int is_write, void *retaddr);
+void __hidden cpu_lock(void);
+void __hidden cpu_unlock(void);
+void do_interrupt(int intno, int is_int, int error_code,
+ unsigned int next_eip, int is_hw);
+void do_interrupt_user(int intno, int is_int, int error_code,
+ unsigned int next_eip);
+void raise_interrupt(int intno, int is_int, int error_code,
+ unsigned int next_eip);
+void raise_exception_err(int exception_index, int error_code);
+void raise_exception(int exception_index);
+void __hidden cpu_loop_exit(void);
+void helper_fsave(uint8_t *ptr, int data32);
+void helper_frstor(uint8_t *ptr, int data32);
+
+void OPPROTO op_movl_eflags_T0(void);
+void OPPROTO op_movl_T0_eflags(void);
+void raise_interrupt(int intno, int is_int, int error_code,
+ unsigned int next_eip);
+void raise_exception_err(int exception_index, int error_code);
+void raise_exception(int exception_index);
+void helper_divl_EAX_T0(uint32_t eip);
+void helper_idivl_EAX_T0(uint32_t eip);
+void helper_cmpxchg8b(void);
+void helper_cpuid(void);
+void helper_rdtsc(void);
+void helper_rdmsr(void);
+void helper_wrmsr(void);
+void helper_lsl(void);
+void helper_lar(void);
+
+#ifdef USE_X86LDOUBLE
+/* use long double functions */
+#define lrint lrintl
+#define llrint llrintl
+#define fabs fabsl
+#define sin sinl
+#define cos cosl
+#define sqrt sqrtl
+#define pow powl
+#define log logl
+#define tan tanl
+#define atan2 atan2l
+#define floor floorl
+#define ceil ceill
+#define rint rintl
+#endif
+
+extern int lrint(CPU86_LDouble x);
+extern int64_t llrint(CPU86_LDouble x);
+extern CPU86_LDouble fabs(CPU86_LDouble x);
+extern CPU86_LDouble sin(CPU86_LDouble x);
+extern CPU86_LDouble cos(CPU86_LDouble x);
+extern CPU86_LDouble sqrt(CPU86_LDouble x);
+extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
+extern CPU86_LDouble log(CPU86_LDouble x);
+extern CPU86_LDouble tan(CPU86_LDouble x);
+extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
+extern CPU86_LDouble floor(CPU86_LDouble x);
+extern CPU86_LDouble ceil(CPU86_LDouble x);
+extern CPU86_LDouble rint(CPU86_LDouble x);
+
+#define RC_MASK 0xc00
+#define RC_NEAR 0x000
+#define RC_DOWN 0x400
+#define RC_UP 0x800
+#define RC_CHOP 0xc00
+
+#define MAXTAN 9223372036854775808.0
+
+#ifdef __arm__
+/* we have no way to do correct rounding - a FPU emulator is needed */
+#define FE_DOWNWARD FE_TONEAREST
+#define FE_UPWARD FE_TONEAREST
+#define FE_TOWARDZERO FE_TONEAREST
+#endif
+
+#ifdef USE_X86LDOUBLE
+
+/* only for x86 */
+typedef union {
+ long double d;
+ struct {
+ unsigned long long lower;
+ unsigned short upper;
+ } l;
+} CPU86_LDoubleU;
+
+/* the following deal with x86 long double-precision numbers */
+#define MAXEXPD 0x7fff
+#define EXPBIAS 16383
+#define EXPD(fp) (fp.l.upper & 0x7fff)
+#define SIGND(fp) ((fp.l.upper) & 0x8000)
+#define MANTD(fp) (fp.l.lower)
+#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
+
+#else
+
+/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
+typedef union {
+ double d;
+#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
+ struct {
+ uint32_t lower;
+ int32_t upper;
+ } l;
+#else
+ struct {
+ int32_t upper;
+ uint32_t lower;
+ } l;
+#endif
+#ifndef __arm__
+ int64_t ll;
+#endif
+} CPU86_LDoubleU;
+
+/* the following deal with IEEE double-precision numbers */
+#define MAXEXPD 0x7ff
+#define EXPBIAS 1023
+#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
+#define SIGND(fp) ((fp.l.upper) & 0x80000000)
+#ifdef __arm__
+#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
+#else
+#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
+#endif
+#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
+#endif
+
+static inline void fpush(void)
+{
+ env->fpstt = (env->fpstt - 1) & 7;
+ env->fptags[env->fpstt] = 0; /* validate stack entry */
+}
+
+static inline void fpop(void)
+{
+ env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
+ env->fpstt = (env->fpstt + 1) & 7;
+}
+
+#ifndef USE_X86LDOUBLE
+static inline CPU86_LDouble helper_fldt(uint8_t *ptr)
+{
+ CPU86_LDoubleU temp;
+ int upper, e;
+ uint64_t ll;
+
+ /* mantissa */
+ upper = lduw(ptr + 8);
+ /* XXX: handle overflow ? */
+ e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
+ e |= (upper >> 4) & 0x800; /* sign */
+ ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
+#ifdef __arm__
+ temp.l.upper = (e << 20) | (ll >> 32);
+ temp.l.lower = ll;
+#else
+ temp.ll = ll | ((uint64_t)e << 52);
+#endif
+ return temp.d;
+}
+
+static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr)
+{
+ CPU86_LDoubleU temp;
+ int e;
+
+ temp.d = f;
+ /* mantissa */
+ stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
+ /* exponent + sign */
+ e = EXPD(temp) - EXPBIAS + 16383;
+ e |= SIGND(temp) >> 16;
+ stw(ptr + 8, e);
+}
+#endif
+
+const CPU86_LDouble f15rk[7];
+
+void helper_fldt_ST0_A0(void);
+void helper_fstt_ST0_A0(void);
+void helper_fbld_ST0_A0(void);
+void helper_fbst_ST0_A0(void);
+void helper_f2xm1(void);
+void helper_fyl2x(void);
+void helper_fptan(void);
+void helper_fpatan(void);
+void helper_fxtract(void);
+void helper_fprem1(void);
+void helper_fprem(void);
+void helper_fyl2xp1(void);
+void helper_fsqrt(void);
+void helper_fsincos(void);
+void helper_frndint(void);
+void helper_fscale(void);
+void helper_fsin(void);
+void helper_fcos(void);
+void helper_fxam_ST0(void);
+void helper_fstenv(uint8_t *ptr, int data32);
+void helper_fldenv(uint8_t *ptr, int data32);
+void helper_fsave(uint8_t *ptr, int data32);
+void helper_frstor(uint8_t *ptr, int data32);
+
+const uint8_t parity_table[256];
+const uint8_t rclw_table[32];
+const uint8_t rclb_table[32];
+
+static inline uint32_t compute_eflags(void)
+{
+ return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
+}
+
+#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
+
+#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \
+ RF_MASK | AC_MASK | ID_MASK)
+
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
+static inline void load_eflags(int eflags, int update_mask)
+{
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ env->eflags = (env->eflags & ~update_mask) |
+ (eflags & update_mask);
+}
+
+/* memory access macros */
+
+#define ldul ldl
+#define lduq ldq
+#define ldul_user ldl_user
+#define ldul_kernel ldl_kernel
+
+#define ldub_raw ldub
+#define ldsb_raw ldsb
+#define lduw_raw lduw
+#define ldsw_raw ldsw
+#define ldl_raw ldl
+#define ldq_raw ldq
+
+#define stb_raw stb
+#define stw_raw stw
+#define stl_raw stl
+#define stq_raw stq
+
+#define MEMUSER 0
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+
+#undef MEMUSER
+#define MEMUSER 1
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+
+#undef MEMUSER
+
diff --git a/target-i386/helper.c b/target-i386/helper.c
new file mode 100644
index 0000000000..075a99f255
--- /dev/null
+++ b/target-i386/helper.c
@@ -0,0 +1,1803 @@
+/*
+ * i386 helpers
+ *
+ * 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 "exec.h"
+
+const uint8_t parity_table[256] = {
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
+ 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
+};
+
+/* modulo 17 table */
+const uint8_t rclw_table[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9,10,11,12,13,14,15,
+ 16, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9,10,11,12,13,14,
+};
+
+/* modulo 9 table */
+const uint8_t rclb_table[32] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 0, 1, 2, 3, 4,
+};
+
+const CPU86_LDouble f15rk[7] =
+{
+ 0.00000000000000000000L,
+ 1.00000000000000000000L,
+ 3.14159265358979323851L, /*pi*/
+ 0.30102999566398119523L, /*lg2*/
+ 0.69314718055994530943L, /*ln2*/
+ 1.44269504088896340739L, /*l2e*/
+ 3.32192809488736234781L, /*l2t*/
+};
+
+/* thread support */
+
+spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+
+void cpu_lock(void)
+{
+ spin_lock(&global_cpu_lock);
+}
+
+void cpu_unlock(void)
+{
+ spin_unlock(&global_cpu_lock);
+}
+
+void cpu_loop_exit(void)
+{
+ /* NOTE: the register at this point must be saved by hand because
+ longjmp restore them */
+#ifdef reg_EAX
+ env->regs[R_EAX] = EAX;
+#endif
+#ifdef reg_ECX
+ env->regs[R_ECX] = ECX;
+#endif
+#ifdef reg_EDX
+ env->regs[R_EDX] = EDX;
+#endif
+#ifdef reg_EBX
+ env->regs[R_EBX] = EBX;
+#endif
+#ifdef reg_ESP
+ env->regs[R_ESP] = ESP;
+#endif
+#ifdef reg_EBP
+ env->regs[R_EBP] = EBP;
+#endif
+#ifdef reg_ESI
+ env->regs[R_ESI] = ESI;
+#endif
+#ifdef reg_EDI
+ env->regs[R_EDI] = EDI;
+#endif
+ longjmp(env->jmp_env, 1);
+}
+
+static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
+ uint32_t *esp_ptr, int dpl)
+{
+ int type, index, shift;
+
+#if 0
+ {
+ int i;
+ printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
+ for(i=0;i<env->tr.limit;i++) {
+ printf("%02x ", env->tr.base[i]);
+ if ((i & 7) == 7) printf("\n");
+ }
+ printf("\n");
+ }
+#endif
+
+ if (!(env->tr.flags & DESC_P_MASK))
+ cpu_abort(env, "invalid tss");
+ type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
+ if ((type & 7) != 1)
+ cpu_abort(env, "invalid tss type");
+ shift = type >> 3;
+ index = (dpl * 4 + 2) << shift;
+ if (index + (4 << shift) - 1 > env->tr.limit)
+ raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
+ if (shift == 0) {
+ *esp_ptr = lduw(env->tr.base + index);
+ *ss_ptr = lduw(env->tr.base + index + 2);
+ } else {
+ *esp_ptr = ldl(env->tr.base + index);
+ *ss_ptr = lduw(env->tr.base + index + 4);
+ }
+}
+
+/* return non zero if error */
+static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
+ int selector)
+{
+ SegmentCache *dt;
+ int index;
+ uint8_t *ptr;
+
+ if (selector & 0x4)
+ dt = &env->ldt;
+ else
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ return -1;
+ ptr = dt->base + index;
+ *e1_ptr = ldl(ptr);
+ *e2_ptr = ldl(ptr + 4);
+ return 0;
+}
+
+static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
+{
+ unsigned int limit;
+ limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+ if (e2 & DESC_G_MASK)
+ limit = (limit << 12) | 0xfff;
+ return limit;
+}
+
+static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2)
+{
+ return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
+}
+
+static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
+{
+ sc->base = get_seg_base(e1, e2);
+ sc->limit = get_seg_limit(e1, e2);
+ sc->flags = e2;
+}
+
+/* init the segment cache in vm86 mode. */
+static inline void load_seg_vm(int seg, int selector)
+{
+ selector &= 0xffff;
+ cpu_x86_load_seg_cache(env, seg, selector,
+ (uint8_t *)(selector << 4), 0xffff, 0);
+}
+
+/* protected mode interrupt */
+static void do_interrupt_protected(int intno, int is_int, int error_code,
+ unsigned int next_eip, int is_hw)
+{
+ SegmentCache *dt;
+ uint8_t *ptr, *ssp;
+ int type, dpl, selector, ss_dpl, cpl;
+ int has_error_code, new_stack, shift;
+ uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size;
+ uint32_t old_cs, old_ss, old_esp, old_eip;
+
+ dt = &env->idt;
+ if (intno * 8 + 7 > dt->limit)
+ raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+ ptr = dt->base + intno * 8;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ /* check gate type */
+ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+ switch(type) {
+ case 5: /* task gate */
+ cpu_abort(env, "task gate not supported");
+ break;
+ case 6: /* 286 interrupt gate */
+ case 7: /* 286 trap gate */
+ case 14: /* 386 interrupt gate */
+ case 15: /* 386 trap gate */
+ break;
+ default:
+ raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+ break;
+ }
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ cpl = env->hflags & HF_CPL_MASK;
+ /* check privledge if software int */
+ if (is_int && dpl < cpl)
+ raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+ /* check valid bit */
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
+ selector = e1 >> 16;
+ offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+ if ((selector & 0xfffc) == 0)
+ raise_exception_err(EXCP0D_GPF, 0);
+
+ if (load_segment(&e1, &e2, selector) != 0)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+ /* to inner priviledge */
+ get_ss_esp_from_tss(&ss, &esp, dpl);
+ if ((ss & 0xfffc) == 0)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if ((ss & 3) != dpl)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+ if (ss_dpl != dpl)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (!(ss_e2 & DESC_S_MASK) ||
+ (ss_e2 & DESC_CS_MASK) ||
+ !(ss_e2 & DESC_W_MASK))
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (!(ss_e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ new_stack = 1;
+ } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
+ /* to same priviledge */
+ new_stack = 0;
+ } else {
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ new_stack = 0; /* avoid warning */
+ }
+
+ shift = type >> 3;
+ has_error_code = 0;
+ if (!is_int && !is_hw) {
+ switch(intno) {
+ case 8:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 17:
+ has_error_code = 1;
+ break;
+ }
+ }
+ push_size = 6 + (new_stack << 2) + (has_error_code << 1);
+ if (env->eflags & VM_MASK)
+ push_size += 8;
+ push_size <<= shift;
+
+ /* XXX: check that enough room is available */
+ if (new_stack) {
+ old_esp = ESP;
+ old_ss = env->segs[R_SS].selector;
+ ss = (ss & ~3) | dpl;
+ cpu_x86_load_seg_cache(env, R_SS, ss,
+ get_seg_base(ss_e1, ss_e2),
+ get_seg_limit(ss_e1, ss_e2),
+ ss_e2);
+ } else {
+ old_esp = 0;
+ old_ss = 0;
+ esp = ESP;
+ }
+ if (is_int)
+ old_eip = next_eip;
+ else
+ old_eip = env->eip;
+ old_cs = env->segs[R_CS].selector;
+ selector = (selector & ~3) | dpl;
+ cpu_x86_load_seg_cache(env, R_CS, selector,
+ get_seg_base(e1, e2),
+ get_seg_limit(e1, e2),
+ e2);
+ cpu_x86_set_cpl(env, dpl);
+ env->eip = offset;
+ ESP = esp - push_size;
+ ssp = env->segs[R_SS].base + esp;
+ if (shift == 1) {
+ int old_eflags;
+ if (env->eflags & VM_MASK) {
+ ssp -= 4;
+ stl(ssp, env->segs[R_GS].selector);
+ ssp -= 4;
+ stl(ssp, env->segs[R_FS].selector);
+ ssp -= 4;
+ stl(ssp, env->segs[R_DS].selector);
+ ssp -= 4;
+ stl(ssp, env->segs[R_ES].selector);
+ }
+ if (new_stack) {
+ ssp -= 4;
+ stl(ssp, old_ss);
+ ssp -= 4;
+ stl(ssp, old_esp);
+ }
+ ssp -= 4;
+ old_eflags = compute_eflags();
+ stl(ssp, old_eflags);
+ ssp -= 4;
+ stl(ssp, old_cs);
+ ssp -= 4;
+ stl(ssp, old_eip);
+ if (has_error_code) {
+ ssp -= 4;
+ stl(ssp, error_code);
+ }
+ } else {
+ if (new_stack) {
+ ssp -= 2;
+ stw(ssp, old_ss);
+ ssp -= 2;
+ stw(ssp, old_esp);
+ }
+ ssp -= 2;
+ stw(ssp, compute_eflags());
+ ssp -= 2;
+ stw(ssp, old_cs);
+ ssp -= 2;
+ stw(ssp, old_eip);
+ if (has_error_code) {
+ ssp -= 2;
+ stw(ssp, error_code);
+ }
+ }
+
+ /* interrupt gate clear IF mask */
+ if ((type & 1) == 0) {
+ env->eflags &= ~IF_MASK;
+ }
+ env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
+}
+
+/* real mode interrupt */
+static void do_interrupt_real(int intno, int is_int, int error_code,
+ unsigned int next_eip)
+{
+ SegmentCache *dt;
+ uint8_t *ptr, *ssp;
+ int selector;
+ uint32_t offset, esp;
+ uint32_t old_cs, old_eip;
+
+ /* real mode (simpler !) */
+ dt = &env->idt;
+ if (intno * 4 + 3 > dt->limit)
+ raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+ ptr = dt->base + intno * 4;
+ offset = lduw(ptr);
+ selector = lduw(ptr + 2);
+ esp = ESP;
+ ssp = env->segs[R_SS].base;
+ if (is_int)
+ old_eip = next_eip;
+ else
+ old_eip = env->eip;
+ old_cs = env->segs[R_CS].selector;
+ esp -= 2;
+ stw(ssp + (esp & 0xffff), compute_eflags());
+ esp -= 2;
+ stw(ssp + (esp & 0xffff), old_cs);
+ esp -= 2;
+ stw(ssp + (esp & 0xffff), old_eip);
+
+ /* update processor state */
+ ESP = (ESP & ~0xffff) | (esp & 0xffff);
+ env->eip = offset;
+ env->segs[R_CS].selector = selector;
+ env->segs[R_CS].base = (uint8_t *)(selector << 4);
+ env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
+}
+
+/* fake user mode interrupt */
+void do_interrupt_user(int intno, int is_int, int error_code,
+ unsigned int next_eip)
+{
+ SegmentCache *dt;
+ uint8_t *ptr;
+ int dpl, cpl;
+ uint32_t e2;
+
+ dt = &env->idt;
+ ptr = dt->base + (intno * 8);
+ e2 = ldl(ptr + 4);
+
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ cpl = env->hflags & HF_CPL_MASK;
+ /* check privledge if software int */
+ if (is_int && dpl < cpl)
+ raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
+
+ /* Since we emulate only user space, we cannot do more than
+ exiting the emulation with the suitable exception and error
+ code */
+ if (is_int)
+ EIP = next_eip;
+}
+
+/*
+ * Begin excution of an interruption. is_int is TRUE if coming from
+ * the int instruction. next_eip is the EIP value AFTER the interrupt
+ * instruction. It is only relevant if is_int is TRUE.
+ */
+void do_interrupt(int intno, int is_int, int error_code,
+ unsigned int next_eip, int is_hw)
+{
+ if (env->cr[0] & CR0_PE_MASK) {
+ do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
+ } else {
+ do_interrupt_real(intno, is_int, error_code, next_eip);
+ }
+}
+
+/*
+ * Signal an interruption. It is executed in the main CPU loop.
+ * is_int is TRUE if coming from the int instruction. next_eip is the
+ * EIP value AFTER the interrupt instruction. It is only relevant if
+ * is_int is TRUE.
+ */
+void raise_interrupt(int intno, int is_int, int error_code,
+ unsigned int next_eip)
+{
+ env->exception_index = intno;
+ env->error_code = error_code;
+ env->exception_is_int = is_int;
+ env->exception_next_eip = next_eip;
+ cpu_loop_exit();
+}
+
+/* shortcuts to generate exceptions */
+void raise_exception_err(int exception_index, int error_code)
+{
+ raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+void raise_exception(int exception_index)
+{
+ raise_interrupt(exception_index, 0, 0, 0);
+}
+
+#ifdef BUGGY_GCC_DIV64
+/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
+ call it from another function */
+uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den)
+{
+ *q_ptr = num / den;
+ return num % den;
+}
+
+int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den)
+{
+ *q_ptr = num / den;
+ return num % den;
+}
+#endif
+
+void helper_divl_EAX_T0(uint32_t eip)
+{
+ unsigned int den, q, r;
+ uint64_t num;
+
+ num = EAX | ((uint64_t)EDX << 32);
+ den = T0;
+ if (den == 0) {
+ EIP = eip;
+ raise_exception(EXCP00_DIVZ);
+ }
+#ifdef BUGGY_GCC_DIV64
+ r = div64(&q, num, den);
+#else
+ q = (num / den);
+ r = (num % den);
+#endif
+ EAX = q;
+ EDX = r;
+}
+
+void helper_idivl_EAX_T0(uint32_t eip)
+{
+ int den, q, r;
+ int64_t num;
+
+ num = EAX | ((uint64_t)EDX << 32);
+ den = T0;
+ if (den == 0) {
+ EIP = eip;
+ raise_exception(EXCP00_DIVZ);
+ }
+#ifdef BUGGY_GCC_DIV64
+ r = idiv64(&q, num, den);
+#else
+ q = (num / den);
+ r = (num % den);
+#endif
+ EAX = q;
+ EDX = r;
+}
+
+void helper_cmpxchg8b(void)
+{
+ uint64_t d;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ d = ldq((uint8_t *)A0);
+ if (d == (((uint64_t)EDX << 32) | EAX)) {
+ stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX);
+ eflags |= CC_Z;
+ } else {
+ EDX = d >> 32;
+ EAX = d;
+ eflags &= ~CC_Z;
+ }
+ CC_SRC = eflags;
+}
+
+/* We simulate a pre-MMX pentium as in valgrind */
+#define CPUID_FP87 (1 << 0)
+#define CPUID_VME (1 << 1)
+#define CPUID_DE (1 << 2)
+#define CPUID_PSE (1 << 3)
+#define CPUID_TSC (1 << 4)
+#define CPUID_MSR (1 << 5)
+#define CPUID_PAE (1 << 6)
+#define CPUID_MCE (1 << 7)
+#define CPUID_CX8 (1 << 8)
+#define CPUID_APIC (1 << 9)
+#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
+#define CPUID_MTRR (1 << 12)
+#define CPUID_PGE (1 << 13)
+#define CPUID_MCA (1 << 14)
+#define CPUID_CMOV (1 << 15)
+/* ... */
+#define CPUID_MMX (1 << 23)
+#define CPUID_FXSR (1 << 24)
+#define CPUID_SSE (1 << 25)
+#define CPUID_SSE2 (1 << 26)
+
+void helper_cpuid(void)
+{
+ if (EAX == 0) {
+ EAX = 1; /* max EAX index supported */
+ EBX = 0x756e6547;
+ ECX = 0x6c65746e;
+ EDX = 0x49656e69;
+ } else if (EAX == 1) {
+ int family, model, stepping;
+ /* EAX = 1 info */
+#if 0
+ /* pentium 75-200 */
+ family = 5;
+ model = 2;
+ stepping = 11;
+#else
+ /* pentium pro */
+ family = 6;
+ model = 1;
+ stepping = 3;
+#endif
+ EAX = (family << 8) | (model << 4) | stepping;
+ EBX = 0;
+ ECX = 0;
+ EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE |
+ CPUID_TSC | CPUID_MSR | CPUID_MCE |
+ CPUID_CX8 | CPUID_PGE | CPUID_CMOV;
+ }
+}
+
+void helper_lldt_T0(void)
+{
+ int selector;
+ SegmentCache *dt;
+ uint32_t e1, e2;
+ int index;
+ uint8_t *ptr;
+
+ selector = T0 & 0xffff;
+ if ((selector & 0xfffc) == 0) {
+ /* XXX: NULL selector case: invalid LDT */
+ env->ldt.base = NULL;
+ env->ldt.limit = 0;
+ } else {
+ if (selector & 0x4)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ ptr = dt->base + index;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache_raw_dt(&env->ldt, e1, e2);
+ }
+ env->ldt.selector = selector;
+}
+
+void helper_ltr_T0(void)
+{
+ int selector;
+ SegmentCache *dt;
+ uint32_t e1, e2;
+ int index, type;
+ uint8_t *ptr;
+
+ selector = T0 & 0xffff;
+ if ((selector & 0xfffc) == 0) {
+ /* NULL selector case: invalid LDT */
+ env->tr.base = NULL;
+ env->tr.limit = 0;
+ env->tr.flags = 0;
+ } else {
+ if (selector & 0x4)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dt = &env->gdt;
+ index = selector & ~7;
+ if ((index + 7) > dt->limit)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ ptr = dt->base + index;
+ e1 = ldl(ptr);
+ e2 = ldl(ptr + 4);
+ type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
+ if ((e2 & DESC_S_MASK) ||
+ (type != 2 && type != 9))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ load_seg_cache_raw_dt(&env->tr, e1, e2);
+ e2 |= 0x00000200; /* set the busy bit */
+ stl(ptr + 4, e2);
+ }
+ env->tr.selector = selector;
+}
+
+/* only works if protected mode and not VM86. Calling load_seg with
+ seg_reg == R_CS is discouraged */
+void load_seg(int seg_reg, int selector, unsigned int cur_eip)
+{
+ uint32_t e1, e2;
+
+ if ((selector & 0xfffc) == 0) {
+ /* null selector case */
+ if (seg_reg == R_SS) {
+ EIP = cur_eip;
+ raise_exception_err(EXCP0D_GPF, 0);
+ } else {
+ cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0);
+ }
+ } else {
+ if (load_segment(&e1, &e2, selector) != 0) {
+ EIP = cur_eip;
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+ if (!(e2 & DESC_S_MASK) ||
+ (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
+ EIP = cur_eip;
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+
+ if (seg_reg == R_SS) {
+ if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) {
+ EIP = cur_eip;
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+ } else {
+ if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) {
+ EIP = cur_eip;
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ }
+ }
+
+ if (!(e2 & DESC_P_MASK)) {
+ EIP = cur_eip;
+ if (seg_reg == R_SS)
+ raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
+ else
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+ }
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ get_seg_base(e1, e2),
+ get_seg_limit(e1, e2),
+ e2);
+#if 0
+ fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
+ selector, (unsigned long)sc->base, sc->limit, sc->flags);
+#endif
+ }
+}
+
+/* protected mode jump */
+void helper_ljmp_protected_T0_T1(void)
+{
+ int new_cs, new_eip;
+ uint32_t e1, e2, cpl, dpl, rpl, limit;
+
+ new_cs = T0;
+ new_eip = T1;
+ if ((new_cs & 0xfffc) == 0)
+ raise_exception_err(EXCP0D_GPF, 0);
+ if (load_segment(&e1, &e2, new_cs) != 0)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ cpl = env->hflags & HF_CPL_MASK;
+ if (e2 & DESC_S_MASK) {
+ if (!(e2 & DESC_CS_MASK))
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (e2 & DESC_CS_MASK) {
+ /* conforming code segment */
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ } else {
+ /* non conforming code segment */
+ rpl = new_cs & 3;
+ if (rpl > cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ if (dpl != cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ }
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+ limit = get_seg_limit(e1, e2);
+ if (new_eip > limit)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+ get_seg_base(e1, e2), limit, e2);
+ EIP = new_eip;
+ } else {
+ cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x",
+ new_cs, new_eip);
+ }
+}
+
+/* real mode call */
+void helper_lcall_real_T0_T1(int shift, int next_eip)
+{
+ int new_cs, new_eip;
+ uint32_t esp, esp_mask;
+ uint8_t *ssp;
+
+ new_cs = T0;
+ new_eip = T1;
+ esp = ESP;
+ esp_mask = 0xffffffff;
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ esp_mask = 0xffff;
+ ssp = env->segs[R_SS].base;
+ if (shift) {
+ esp -= 4;
+ stl(ssp + (esp & esp_mask), env->segs[R_CS].selector);
+ esp -= 4;
+ stl(ssp + (esp & esp_mask), next_eip);
+ } else {
+ esp -= 2;
+ stw(ssp + (esp & esp_mask), env->segs[R_CS].selector);
+ esp -= 2;
+ stw(ssp + (esp & esp_mask), next_eip);
+ }
+
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ ESP = (ESP & ~0xffff) | (esp & 0xffff);
+ else
+ ESP = esp;
+ env->eip = new_eip;
+ env->segs[R_CS].selector = new_cs;
+ env->segs[R_CS].base = (uint8_t *)(new_cs << 4);
+}
+
+/* protected mode call */
+void helper_lcall_protected_T0_T1(int shift, int next_eip)
+{
+ int new_cs, new_eip;
+ uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
+ uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl;
+ uint32_t old_ss, old_esp, val, i, limit;
+ uint8_t *ssp, *old_ssp;
+
+ new_cs = T0;
+ new_eip = T1;
+ if ((new_cs & 0xfffc) == 0)
+ raise_exception_err(EXCP0D_GPF, 0);
+ if (load_segment(&e1, &e2, new_cs) != 0)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ cpl = env->hflags & HF_CPL_MASK;
+ if (e2 & DESC_S_MASK) {
+ if (!(e2 & DESC_CS_MASK))
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (e2 & DESC_CS_MASK) {
+ /* conforming code segment */
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ } else {
+ /* non conforming code segment */
+ rpl = new_cs & 3;
+ if (rpl > cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ if (dpl != cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ }
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+ sp = ESP;
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ sp &= 0xffff;
+ ssp = env->segs[R_SS].base + sp;
+ if (shift) {
+ ssp -= 4;
+ stl(ssp, env->segs[R_CS].selector);
+ ssp -= 4;
+ stl(ssp, next_eip);
+ } else {
+ ssp -= 2;
+ stw(ssp, env->segs[R_CS].selector);
+ ssp -= 2;
+ stw(ssp, next_eip);
+ }
+ sp -= (4 << shift);
+
+ limit = get_seg_limit(e1, e2);
+ if (new_eip > limit)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ /* from this point, not restartable */
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ ESP = (ESP & 0xffff0000) | (sp & 0xffff);
+ else
+ ESP = sp;
+ cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
+ get_seg_base(e1, e2), limit, e2);
+ EIP = new_eip;
+ } else {
+ /* check gate type */
+ type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
+ switch(type) {
+ case 1: /* available 286 TSS */
+ case 9: /* available 386 TSS */
+ case 5: /* task gate */
+ cpu_abort(env, "task gate not supported");
+ break;
+ case 4: /* 286 call gate */
+ case 12: /* 386 call gate */
+ break;
+ default:
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ break;
+ }
+ shift = type >> 3;
+
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ rpl = new_cs & 3;
+ if (dpl < cpl || dpl < rpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ /* check valid bit */
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+ selector = e1 >> 16;
+ offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
+ if ((selector & 0xfffc) == 0)
+ raise_exception_err(EXCP0D_GPF, 0);
+
+ if (load_segment(&e1, &e2, selector) != 0)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (dpl > cpl)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
+
+ if (!(e2 & DESC_C_MASK) && dpl < cpl) {
+ /* to inner priviledge */
+ get_ss_esp_from_tss(&ss, &sp, dpl);
+ if ((ss & 0xfffc) == 0)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if ((ss & 3) != dpl)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (load_segment(&ss_e1, &ss_e2, ss) != 0)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+ if (ss_dpl != dpl)
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (!(ss_e2 & DESC_S_MASK) ||
+ (ss_e2 & DESC_CS_MASK) ||
+ !(ss_e2 & DESC_W_MASK))
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+ if (!(ss_e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
+
+ param_count = e2 & 0x1f;
+ push_size = ((param_count * 2) + 8) << shift;
+
+ old_esp = ESP;
+ old_ss = env->segs[R_SS].selector;
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ old_esp &= 0xffff;
+ old_ssp = env->segs[R_SS].base + old_esp;
+
+ /* XXX: from this point not restartable */
+ ss = (ss & ~3) | dpl;
+ cpu_x86_load_seg_cache(env, R_SS, ss,
+ get_seg_base(ss_e1, ss_e2),
+ get_seg_limit(ss_e1, ss_e2),
+ ss_e2);
+
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ sp &= 0xffff;
+ ssp = env->segs[R_SS].base + sp;
+ if (shift) {
+ ssp -= 4;
+ stl(ssp, old_ss);
+ ssp -= 4;
+ stl(ssp, old_esp);
+ ssp -= 4 * param_count;
+ for(i = 0; i < param_count; i++) {
+ val = ldl(old_ssp + i * 4);
+ stl(ssp + i * 4, val);
+ }
+ } else {
+ ssp -= 2;
+ stw(ssp, old_ss);
+ ssp -= 2;
+ stw(ssp, old_esp);
+ ssp -= 2 * param_count;
+ for(i = 0; i < param_count; i++) {
+ val = lduw(old_ssp + i * 2);
+ stw(ssp + i * 2, val);
+ }
+ }
+ } else {
+ /* to same priviledge */
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ sp &= 0xffff;
+ ssp = env->segs[R_SS].base + sp;
+ push_size = (4 << shift);
+ }
+
+ if (shift) {
+ ssp -= 4;
+ stl(ssp, env->segs[R_CS].selector);
+ ssp -= 4;
+ stl(ssp, next_eip);
+ } else {
+ ssp -= 2;
+ stw(ssp, env->segs[R_CS].selector);
+ ssp -= 2;
+ stw(ssp, next_eip);
+ }
+
+ sp -= push_size;
+ selector = (selector & ~3) | dpl;
+ cpu_x86_load_seg_cache(env, R_CS, selector,
+ get_seg_base(e1, e2),
+ get_seg_limit(e1, e2),
+ e2);
+ cpu_x86_set_cpl(env, dpl);
+
+ /* from this point, not restartable if same priviledge */
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ ESP = (ESP & 0xffff0000) | (sp & 0xffff);
+ else
+ ESP = sp;
+ EIP = offset;
+ }
+}
+
+/* real mode iret */
+void helper_iret_real(int shift)
+{
+ uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
+ uint8_t *ssp;
+ int eflags_mask;
+
+ sp = ESP & 0xffff;
+ ssp = env->segs[R_SS].base + sp;
+ if (shift == 1) {
+ /* 32 bits */
+ new_eflags = ldl(ssp + 8);
+ new_cs = ldl(ssp + 4) & 0xffff;
+ new_eip = ldl(ssp) & 0xffff;
+ } else {
+ /* 16 bits */
+ new_eflags = lduw(ssp + 4);
+ new_cs = lduw(ssp + 2);
+ new_eip = lduw(ssp);
+ }
+ new_esp = sp + (6 << shift);
+ ESP = (ESP & 0xffff0000) |
+ (new_esp & 0xffff);
+ load_seg_vm(R_CS, new_cs);
+ env->eip = new_eip;
+ eflags_mask = FL_UPDATE_CPL0_MASK;
+ if (shift == 0)
+ eflags_mask &= 0xffff;
+ load_eflags(new_eflags, eflags_mask);
+}
+
+/* protected mode iret */
+static inline void helper_ret_protected(int shift, int is_iret, int addend)
+{
+ uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss;
+ uint32_t new_es, new_ds, new_fs, new_gs;
+ uint32_t e1, e2, ss_e1, ss_e2;
+ int cpl, dpl, rpl, eflags_mask;
+ uint8_t *ssp;
+
+ sp = ESP;
+ if (!(env->segs[R_SS].flags & DESC_B_MASK))
+ sp &= 0xffff;
+ ssp = env->segs[R_SS].base + sp;
+ if (shift == 1) {
+ /* 32 bits */
+ if (is_iret)
+ new_eflags = ldl(ssp + 8);
+ new_cs = ldl(ssp + 4) & 0xffff;
+ new_eip = ldl(ssp);
+ if (is_iret && (new_eflags & VM_MASK))
+ goto return_to_vm86;
+ } else {
+ /* 16 bits */
+ if (is_iret)
+ new_eflags = lduw(ssp + 4);
+ new_cs = lduw(ssp + 2);
+ new_eip = lduw(ssp);
+ }
+ if ((new_cs & 0xfffc) == 0)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ if (load_segment(&e1, &e2, new_cs) != 0)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ if (!(e2 & DESC_S_MASK) ||
+ !(e2 & DESC_CS_MASK))
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ cpl = env->hflags & HF_CPL_MASK;
+ rpl = new_cs & 3;
+ if (rpl < cpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ dpl = (e2 >> DESC_DPL_SHIFT) & 3;
+ if (e2 & DESC_CS_MASK) {
+ if (dpl > rpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ } else {
+ if (dpl != rpl)
+ raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
+ }
+ if (!(e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
+
+ if (rpl == cpl) {
+ /* return to same priledge level */
+ cpu_x86_load_seg_cache(env, R_CS, new_cs,
+ get_seg_base(e1, e2),
+ get_seg_limit(e1, e2),
+ e2);
+ new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend;
+ } else {
+ /* return to different priviledge level */
+ ssp += (4 << shift) + ((2 * is_iret) << shift) + addend;
+ if (shift == 1) {
+ /* 32 bits */
+ new_esp = ldl(ssp);
+ new_ss = ldl(ssp + 4) & 0xffff;
+ } else {
+ /* 16 bits */
+ new_esp = lduw(ssp);
+ new_ss = lduw(ssp + 2);
+ }
+
+ if ((new_ss & 3) != rpl)
+ raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+ if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
+ raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+ if (!(ss_e2 & DESC_S_MASK) ||
+ (ss_e2 & DESC_CS_MASK) ||
+ !(ss_e2 & DESC_W_MASK))
+ raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+ dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
+ if (dpl != rpl)
+ raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
+ if (!(ss_e2 & DESC_P_MASK))
+ raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
+
+ cpu_x86_load_seg_cache(env, R_CS, new_cs,
+ get_seg_base(e1, e2),
+ get_seg_limit(e1, e2),
+ e2);
+ cpu_x86_load_seg_cache(env, R_SS, new_ss,
+ get_seg_base(ss_e1, ss_e2),
+ get_seg_limit(ss_e1, ss_e2),
+ ss_e2);
+ cpu_x86_set_cpl(env, rpl);
+ }
+ if (env->segs[R_SS].flags & DESC_B_MASK)
+ ESP = new_esp;
+ else
+ ESP = (ESP & 0xffff0000) |
+ (new_esp & 0xffff);
+ env->eip = new_eip;
+ if (is_iret) {
+ /* NOTE: 'cpl' can be different from the current CPL */
+ if (cpl == 0)
+ eflags_mask = FL_UPDATE_CPL0_MASK;
+ else
+ eflags_mask = FL_UPDATE_MASK32;
+ if (shift == 0)
+ eflags_mask &= 0xffff;
+ load_eflags(new_eflags, eflags_mask);
+ }
+ return;
+
+ return_to_vm86:
+ new_esp = ldl(ssp + 12);
+ new_ss = ldl(ssp + 16);
+ new_es = ldl(ssp + 20);
+ new_ds = ldl(ssp + 24);
+ new_fs = ldl(ssp + 28);
+ new_gs = ldl(ssp + 32);
+
+ /* modify processor state */
+ load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK);
+ load_seg_vm(R_CS, new_cs);
+ cpu_x86_set_cpl(env, 3);
+ load_seg_vm(R_SS, new_ss);
+ load_seg_vm(R_ES, new_es);
+ load_seg_vm(R_DS, new_ds);
+ load_seg_vm(R_FS, new_fs);
+ load_seg_vm(R_GS, new_gs);
+
+ env->eip = new_eip;
+ ESP = new_esp;
+}
+
+void helper_iret_protected(int shift)
+{
+ helper_ret_protected(shift, 1, 0);
+}
+
+void helper_lret_protected(int shift, int addend)
+{
+ helper_ret_protected(shift, 0, addend);
+}
+
+void helper_movl_crN_T0(int reg)
+{
+ env->cr[reg] = T0;
+ switch(reg) {
+ case 0:
+ cpu_x86_update_cr0(env);
+ break;
+ case 3:
+ cpu_x86_update_cr3(env);
+ break;
+ }
+}
+
+/* XXX: do more */
+void helper_movl_drN_T0(int reg)
+{
+ env->dr[reg] = T0;
+}
+
+void helper_invlpg(unsigned int addr)
+{
+ cpu_x86_flush_tlb(env, addr);
+}
+
+/* rdtsc */
+#ifndef __i386__
+uint64_t emu_time;
+#endif
+
+void helper_rdtsc(void)
+{
+ uint64_t val;
+#ifdef __i386__
+ asm("rdtsc" : "=A" (val));
+#else
+ /* better than nothing: the time increases */
+ val = emu_time++;
+#endif
+ EAX = val;
+ EDX = val >> 32;
+}
+
+void helper_wrmsr(void)
+{
+ switch(ECX) {
+ case MSR_IA32_SYSENTER_CS:
+ env->sysenter_cs = EAX & 0xffff;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ env->sysenter_esp = EAX;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ env->sysenter_eip = EAX;
+ break;
+ default:
+ /* XXX: exception ? */
+ break;
+ }
+}
+
+void helper_rdmsr(void)
+{
+ switch(ECX) {
+ case MSR_IA32_SYSENTER_CS:
+ EAX = env->sysenter_cs;
+ EDX = 0;
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ EAX = env->sysenter_esp;
+ EDX = 0;
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ EAX = env->sysenter_eip;
+ EDX = 0;
+ break;
+ default:
+ /* XXX: exception ? */
+ break;
+ }
+}
+
+void helper_lsl(void)
+{
+ unsigned int selector, limit;
+ uint32_t e1, e2;
+
+ CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
+ selector = T0 & 0xffff;
+ if (load_segment(&e1, &e2, selector) != 0)
+ return;
+ limit = (e1 & 0xffff) | (e2 & 0x000f0000);
+ if (e2 & (1 << 23))
+ limit = (limit << 12) | 0xfff;
+ T1 = limit;
+ CC_SRC |= CC_Z;
+}
+
+void helper_lar(void)
+{
+ unsigned int selector;
+ uint32_t e1, e2;
+
+ CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z;
+ selector = T0 & 0xffff;
+ if (load_segment(&e1, &e2, selector) != 0)
+ return;
+ T1 = e2 & 0x00f0ff00;
+ CC_SRC |= CC_Z;
+}
+
+/* FPU helpers */
+
+#ifndef USE_X86LDOUBLE
+void helper_fldt_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+ env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fstt_ST0_A0(void)
+{
+ helper_fstt(ST0, (uint8_t *)A0);
+}
+#endif
+
+/* BCD ops */
+
+#define MUL10(iv) ( iv + iv + (iv << 3) )
+
+void helper_fbld_ST0_A0(void)
+{
+ CPU86_LDouble tmp;
+ uint64_t val;
+ unsigned int v;
+ int i;
+
+ val = 0;
+ for(i = 8; i >= 0; i--) {
+ v = ldub((uint8_t *)A0 + i);
+ val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
+ }
+ tmp = val;
+ if (ldub((uint8_t *)A0 + 9) & 0x80)
+ tmp = -tmp;
+ fpush();
+ ST0 = tmp;
+}
+
+void helper_fbst_ST0_A0(void)
+{
+ CPU86_LDouble tmp;
+ int v;
+ uint8_t *mem_ref, *mem_end;
+ int64_t val;
+
+ tmp = rint(ST0);
+ val = (int64_t)tmp;
+ mem_ref = (uint8_t *)A0;
+ mem_end = mem_ref + 9;
+ if (val < 0) {
+ stb(mem_end, 0x80);
+ val = -val;
+ } else {
+ stb(mem_end, 0x00);
+ }
+ while (mem_ref < mem_end) {
+ if (val == 0)
+ break;
+ v = val % 100;
+ val = val / 100;
+ v = ((v / 10) << 4) | (v % 10);
+ stb(mem_ref++, v);
+ }
+ while (mem_ref < mem_end) {
+ stb(mem_ref++, 0);
+ }
+}
+
+void helper_f2xm1(void)
+{
+ ST0 = pow(2.0,ST0) - 1.0;
+}
+
+void helper_fyl2x(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if (fptemp>0.0){
+ fptemp = log(fptemp)/log(2.0); /* log2(ST) */
+ ST1 *= fptemp;
+ fpop();
+ } else {
+ env->fpus &= (~0x4700);
+ env->fpus |= 0x400;
+ }
+}
+
+void helper_fptan(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+ env->fpus |= 0x400;
+ } else {
+ ST0 = tan(fptemp);
+ fpush();
+ ST0 = 1.0;
+ env->fpus &= (~0x400); /* C2 <-- 0 */
+ /* the above code is for |arg| < 2**52 only */
+ }
+}
+
+void helper_fpatan(void)
+{
+ CPU86_LDouble fptemp, fpsrcop;
+
+ fpsrcop = ST1;
+ fptemp = ST0;
+ ST1 = atan2(fpsrcop,fptemp);
+ fpop();
+}
+
+void helper_fxtract(void)
+{
+ CPU86_LDoubleU temp;
+ unsigned int expdif;
+
+ temp.d = ST0;
+ expdif = EXPD(temp) - EXPBIAS;
+ /*DP exponent bias*/
+ ST0 = expdif;
+ fpush();
+ BIASEXPONENT(temp);
+ ST0 = temp.d;
+}
+
+void helper_fprem1(void)
+{
+ CPU86_LDouble dblq, fpsrcop, fptemp;
+ CPU86_LDoubleU fpsrcop1, fptemp1;
+ int expdif;
+ int q;
+
+ fpsrcop = ST0;
+ fptemp = ST1;
+ fpsrcop1.d = fpsrcop;
+ fptemp1.d = fptemp;
+ expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+ if (expdif < 53) {
+ dblq = fpsrcop / fptemp;
+ dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
+ ST0 = fpsrcop - fptemp*dblq;
+ q = (int)dblq; /* cutting off top bits is assumed here */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ /* (C0,C1,C3) <-- (q2,q1,q0) */
+ env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
+ env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
+ env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+ } else {
+ env->fpus |= 0x400; /* C2 <-- 1 */
+ fptemp = pow(2.0, expdif-50);
+ fpsrcop = (ST0 / ST1) / fptemp;
+ /* fpsrcop = integer obtained by rounding to the nearest */
+ fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
+ floor(fpsrcop): ceil(fpsrcop);
+ ST0 -= (ST1 * fpsrcop * fptemp);
+ }
+}
+
+void helper_fprem(void)
+{
+ CPU86_LDouble dblq, fpsrcop, fptemp;
+ CPU86_LDoubleU fpsrcop1, fptemp1;
+ int expdif;
+ int q;
+
+ fpsrcop = ST0;
+ fptemp = ST1;
+ fpsrcop1.d = fpsrcop;
+ fptemp1.d = fptemp;
+ expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+ if ( expdif < 53 ) {
+ dblq = fpsrcop / fptemp;
+ dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
+ ST0 = fpsrcop - fptemp*dblq;
+ q = (int)dblq; /* cutting off top bits is assumed here */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ /* (C0,C1,C3) <-- (q2,q1,q0) */
+ env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
+ env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
+ env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+ } else {
+ env->fpus |= 0x400; /* C2 <-- 1 */
+ fptemp = pow(2.0, expdif-50);
+ fpsrcop = (ST0 / ST1) / fptemp;
+ /* fpsrcop = integer obtained by chopping */
+ fpsrcop = (fpsrcop < 0.0)?
+ -(floor(fabs(fpsrcop))): floor(fpsrcop);
+ ST0 -= (ST1 * fpsrcop * fptemp);
+ }
+}
+
+void helper_fyl2xp1(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if ((fptemp+1.0)>0.0) {
+ fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
+ ST1 *= fptemp;
+ fpop();
+ } else {
+ env->fpus &= (~0x4700);
+ env->fpus |= 0x400;
+ }
+}
+
+void helper_fsqrt(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if (fptemp<0.0) {
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ env->fpus |= 0x400;
+ }
+ ST0 = sqrt(fptemp);
+}
+
+void helper_fsincos(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+ env->fpus |= 0x400;
+ } else {
+ ST0 = sin(fptemp);
+ fpush();
+ ST0 = cos(fptemp);
+ env->fpus &= (~0x400); /* C2 <-- 0 */
+ /* the above code is for |arg| < 2**63 only */
+ }
+}
+
+void helper_frndint(void)
+{
+ CPU86_LDouble a;
+
+ a = ST0;
+#ifdef __arm__
+ switch(env->fpuc & RC_MASK) {
+ default:
+ case RC_NEAR:
+ asm("rndd %0, %1" : "=f" (a) : "f"(a));
+ break;
+ case RC_DOWN:
+ asm("rnddm %0, %1" : "=f" (a) : "f"(a));
+ break;
+ case RC_UP:
+ asm("rnddp %0, %1" : "=f" (a) : "f"(a));
+ break;
+ case RC_CHOP:
+ asm("rnddz %0, %1" : "=f" (a) : "f"(a));
+ break;
+ }
+#else
+ a = rint(a);
+#endif
+ ST0 = a;
+}
+
+void helper_fscale(void)
+{
+ CPU86_LDouble fpsrcop, fptemp;
+
+ fpsrcop = 2.0;
+ fptemp = pow(fpsrcop,ST1);
+ ST0 *= fptemp;
+}
+
+void helper_fsin(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+ env->fpus |= 0x400;
+ } else {
+ ST0 = sin(fptemp);
+ env->fpus &= (~0x400); /* C2 <-- 0 */
+ /* the above code is for |arg| < 2**53 only */
+ }
+}
+
+void helper_fcos(void)
+{
+ CPU86_LDouble fptemp;
+
+ fptemp = ST0;
+ if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
+ env->fpus |= 0x400;
+ } else {
+ ST0 = cos(fptemp);
+ env->fpus &= (~0x400); /* C2 <-- 0 */
+ /* the above code is for |arg5 < 2**63 only */
+ }
+}
+
+void helper_fxam_ST0(void)
+{
+ CPU86_LDoubleU temp;
+ int expdif;
+
+ temp.d = ST0;
+
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ if (SIGND(temp))
+ env->fpus |= 0x200; /* C1 <-- 1 */
+
+ expdif = EXPD(temp);
+ if (expdif == MAXEXPD) {
+ if (MANTD(temp) == 0)
+ env->fpus |= 0x500 /*Infinity*/;
+ else
+ env->fpus |= 0x100 /*NaN*/;
+ } else if (expdif == 0) {
+ if (MANTD(temp) == 0)
+ env->fpus |= 0x4000 /*Zero*/;
+ else
+ env->fpus |= 0x4400 /*Denormal*/;
+ } else {
+ env->fpus |= 0x400;
+ }
+}
+
+void helper_fstenv(uint8_t *ptr, int data32)
+{
+ int fpus, fptag, exp, i;
+ uint64_t mant;
+ CPU86_LDoubleU tmp;
+
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ fptag = 0;
+ for (i=7; i>=0; i--) {
+ fptag <<= 2;
+ if (env->fptags[i]) {
+ fptag |= 3;
+ } else {
+ tmp.d = env->fpregs[i];
+ exp = EXPD(tmp);
+ mant = MANTD(tmp);
+ if (exp == 0 && mant == 0) {
+ /* zero */
+ fptag |= 1;
+ } else if (exp == 0 || exp == MAXEXPD
+#ifdef USE_X86LDOUBLE
+ || (mant & (1LL << 63)) == 0
+#endif
+ ) {
+ /* NaNs, infinity, denormal */
+ fptag |= 2;
+ }
+ }
+ }
+ if (data32) {
+ /* 32 bit */
+ stl(ptr, env->fpuc);
+ stl(ptr + 4, fpus);
+ stl(ptr + 8, fptag);
+ stl(ptr + 12, 0);
+ stl(ptr + 16, 0);
+ stl(ptr + 20, 0);
+ stl(ptr + 24, 0);
+ } else {
+ /* 16 bit */
+ stw(ptr, env->fpuc);
+ stw(ptr + 2, fpus);
+ stw(ptr + 4, fptag);
+ stw(ptr + 6, 0);
+ stw(ptr + 8, 0);
+ stw(ptr + 10, 0);
+ stw(ptr + 12, 0);
+ }
+}
+
+void helper_fldenv(uint8_t *ptr, int data32)
+{
+ int i, fpus, fptag;
+
+ if (data32) {
+ env->fpuc = lduw(ptr);
+ fpus = lduw(ptr + 4);
+ fptag = lduw(ptr + 8);
+ }
+ else {
+ env->fpuc = lduw(ptr);
+ fpus = lduw(ptr + 2);
+ fptag = lduw(ptr + 4);
+ }
+ env->fpstt = (fpus >> 11) & 7;
+ env->fpus = fpus & ~0x3800;
+ for(i = 0;i < 7; i++) {
+ env->fptags[i] = ((fptag & 3) == 3);
+ fptag >>= 2;
+ }
+}
+
+void helper_fsave(uint8_t *ptr, int data32)
+{
+ CPU86_LDouble tmp;
+ int i;
+
+ helper_fstenv(ptr, data32);
+
+ ptr += (14 << data32);
+ for(i = 0;i < 8; i++) {
+ tmp = ST(i);
+#ifdef USE_X86LDOUBLE
+ *(long double *)ptr = tmp;
+#else
+ helper_fstt(tmp, ptr);
+#endif
+ ptr += 10;
+ }
+
+ /* fninit */
+ env->fpus = 0;
+ env->fpstt = 0;
+ env->fpuc = 0x37f;
+ env->fptags[0] = 1;
+ env->fptags[1] = 1;
+ env->fptags[2] = 1;
+ env->fptags[3] = 1;
+ env->fptags[4] = 1;
+ env->fptags[5] = 1;
+ env->fptags[6] = 1;
+ env->fptags[7] = 1;
+}
+
+void helper_frstor(uint8_t *ptr, int data32)
+{
+ CPU86_LDouble tmp;
+ int i;
+
+ helper_fldenv(ptr, data32);
+ ptr += (14 << data32);
+
+ for(i = 0;i < 8; i++) {
+#ifdef USE_X86LDOUBLE
+ tmp = *(long double *)ptr;
+#else
+ tmp = helper_fldt(ptr);
+#endif
+ ST(i) = tmp;
+ ptr += 10;
+ }
+}
+
+#define SHIFT 0
+#include "softmmu_template.h"
+
+#define SHIFT 1
+#include "softmmu_template.h"
+
+#define SHIFT 2
+#include "softmmu_template.h"
+
+#define SHIFT 3
+#include "softmmu_template.h"
+
+/* try to fill the TLB and return an exception if error */
+void tlb_fill(unsigned long addr, int is_write, void *retaddr)
+{
+ TranslationBlock *tb;
+ int ret;
+ unsigned long pc;
+ ret = cpu_x86_handle_mmu_fault(env, addr, is_write);
+ if (ret) {
+ /* now we have a real cpu fault */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc);
+ }
+ raise_exception_err(EXCP0E_PAGE, env->error_code);
+ }
+}
diff --git a/target-i386/helper2.c b/target-i386/helper2.c
new file mode 100644
index 0000000000..bc0d426bc1
--- /dev/null
+++ b/target-i386/helper2.c
@@ -0,0 +1,390 @@
+/*
+ * i386 helpers (without register variable usage)
+ *
+ * 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"
+
+//#define DEBUG_MMU
+
+CPUX86State *cpu_x86_init(void)
+{
+ CPUX86State *env;
+ int i;
+ static int inited;
+
+ cpu_exec_init();
+
+ env = malloc(sizeof(CPUX86State));
+ if (!env)
+ return NULL;
+ memset(env, 0, sizeof(CPUX86State));
+ /* basic FPU init */
+ for(i = 0;i < 8; i++)
+ env->fptags[i] = 1;
+ env->fpuc = 0x37f;
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags = 0x2 | IF_MASK;
+
+ tlb_flush(env);
+#ifdef CONFIG_SOFTMMU
+ env->hflags |= HF_SOFTMMU_MASK;
+#endif
+ /* init various static tables */
+ if (!inited) {
+ inited = 1;
+ optimize_flags_init();
+ }
+ return env;
+}
+
+void cpu_x86_close(CPUX86State *env)
+{
+ free(env);
+}
+
+/***********************************************************/
+/* x86 debug */
+
+static const char *cc_op_str[] = {
+ "DYNAMIC",
+ "EFLAGS",
+ "MUL",
+ "ADDB",
+ "ADDW",
+ "ADDL",
+ "ADCB",
+ "ADCW",
+ "ADCL",
+ "SUBB",
+ "SUBW",
+ "SUBL",
+ "SBBB",
+ "SBBW",
+ "SBBL",
+ "LOGICB",
+ "LOGICW",
+ "LOGICL",
+ "INCB",
+ "INCW",
+ "INCL",
+ "DECB",
+ "DECW",
+ "DECL",
+ "SHLB",
+ "SHLW",
+ "SHLL",
+ "SARB",
+ "SARW",
+ "SARL",
+};
+
+void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags)
+{
+ int eflags;
+ char cc_op_name[32];
+
+ eflags = env->eflags;
+ fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
+ "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
+ "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n",
+ env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
+ env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
+ env->eip, eflags,
+ eflags & DF_MASK ? 'D' : '-',
+ eflags & CC_O ? 'O' : '-',
+ eflags & CC_S ? 'S' : '-',
+ eflags & CC_Z ? 'Z' : '-',
+ eflags & CC_A ? 'A' : '-',
+ eflags & CC_P ? 'P' : '-',
+ eflags & CC_C ? 'C' : '-');
+ fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
+ env->segs[R_CS].selector,
+ env->segs[R_SS].selector,
+ env->segs[R_DS].selector,
+ env->segs[R_ES].selector,
+ env->segs[R_FS].selector,
+ env->segs[R_GS].selector);
+ if (flags & X86_DUMP_CCOP) {
+ if ((unsigned)env->cc_op < CC_OP_NB)
+ strcpy(cc_op_name, cc_op_str[env->cc_op]);
+ else
+ snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
+ fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
+ env->cc_src, env->cc_dst, cc_op_name);
+ }
+ if (flags & X86_DUMP_FPU) {
+ fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
+ (double)env->fpregs[0],
+ (double)env->fpregs[1],
+ (double)env->fpregs[2],
+ (double)env->fpregs[3]);
+ fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n",
+ (double)env->fpregs[4],
+ (double)env->fpregs[5],
+ (double)env->fpregs[7],
+ (double)env->fpregs[8]);
+ }
+}
+
+/***********************************************************/
+/* x86 mmu */
+/* XXX: add PGE support */
+
+/* called when cr3 or PG bit are modified */
+static int last_pg_state = -1;
+static int last_pe_state = 0;
+int phys_ram_size;
+int phys_ram_fd;
+uint8_t *phys_ram_base;
+
+void cpu_x86_update_cr0(CPUX86State *env)
+{
+ int pg_state, pe_state;
+
+#ifdef DEBUG_MMU
+ printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
+#endif
+ pg_state = env->cr[0] & CR0_PG_MASK;
+ if (pg_state != last_pg_state) {
+ page_unmap();
+ tlb_flush(env);
+ last_pg_state = pg_state;
+ }
+ pe_state = env->cr[0] & CR0_PE_MASK;
+ if (last_pe_state != pe_state) {
+ tb_flush();
+ last_pe_state = pe_state;
+ }
+}
+
+void cpu_x86_update_cr3(CPUX86State *env)
+{
+ if (env->cr[0] & CR0_PG_MASK) {
+#if defined(DEBUG_MMU)
+ printf("CR3 update: CR3=%08x\n", env->cr[3]);
+#endif
+ page_unmap();
+ tlb_flush(env);
+ }
+}
+
+void cpu_x86_init_mmu(CPUX86State *env)
+{
+ last_pg_state = -1;
+ cpu_x86_update_cr0(env);
+}
+
+/* XXX: also flush 4MB pages */
+void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
+{
+ int flags;
+ unsigned long virt_addr;
+
+ tlb_flush_page(env, addr);
+
+ flags = page_get_flags(addr);
+ if (flags & PAGE_VALID) {
+ virt_addr = addr & ~0xfff;
+ munmap((void *)virt_addr, 4096);
+ page_set_flags(virt_addr, virt_addr + 4096, 0);
+ }
+}
+
+/* return value:
+ -1 = cannot handle fault
+ 0 = nothing more to do
+ 1 = generate PF fault
+ 2 = soft MMU activation required for this block
+*/
+int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
+{
+ uint8_t *pde_ptr, *pte_ptr;
+ uint32_t pde, pte, virt_addr;
+ int cpl, error_code, is_dirty, is_user, prot, page_size, ret;
+ unsigned long pd;
+
+ cpl = env->hflags & HF_CPL_MASK;
+ is_user = (cpl == 3);
+
+#ifdef DEBUG_MMU
+ printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
+ addr, is_write, is_user, env->eip);
+#endif
+
+ if (env->user_mode_only) {
+ /* user mode only emulation */
+ error_code = 0;
+ goto do_fault;
+ }
+
+ if (!(env->cr[0] & CR0_PG_MASK)) {
+ pte = addr;
+ virt_addr = addr & ~0xfff;
+ prot = PROT_READ | PROT_WRITE;
+ page_size = 4096;
+ goto do_mapping;
+ }
+
+ /* page directory entry */
+ pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3));
+ pde = ldl(pde_ptr);
+ if (!(pde & PG_PRESENT_MASK)) {
+ error_code = 0;
+ goto do_fault;
+ }
+ if (is_user) {
+ if (!(pde & PG_USER_MASK))
+ goto do_fault_protect;
+ if (is_write && !(pde & PG_RW_MASK))
+ goto do_fault_protect;
+ } else {
+ if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
+ is_write && !(pde & PG_RW_MASK))
+ goto do_fault_protect;
+ }
+ /* if PSE bit is set, then we use a 4MB page */
+ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
+ is_dirty = is_write && !(pde & PG_DIRTY_MASK);
+ if (!(pde & PG_ACCESSED_MASK)) {
+ pde |= PG_ACCESSED_MASK;
+ if (is_dirty)
+ pde |= PG_DIRTY_MASK;
+ stl(pde_ptr, pde);
+ }
+
+ pte = pde & ~0x003ff000; /* align to 4MB */
+ page_size = 4096 * 1024;
+ virt_addr = addr & ~0x003fffff;
+ } else {
+ if (!(pde & PG_ACCESSED_MASK)) {
+ pde |= PG_ACCESSED_MASK;
+ stl(pde_ptr, pde);
+ }
+
+ /* page directory entry */
+ pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc));
+ pte = ldl(pte_ptr);
+ if (!(pte & PG_PRESENT_MASK)) {
+ error_code = 0;
+ goto do_fault;
+ }
+ if (is_user) {
+ if (!(pte & PG_USER_MASK))
+ goto do_fault_protect;
+ if (is_write && !(pte & PG_RW_MASK))
+ goto do_fault_protect;
+ } else {
+ if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) &&
+ is_write && !(pte & PG_RW_MASK))
+ goto do_fault_protect;
+ }
+ is_dirty = is_write && !(pte & PG_DIRTY_MASK);
+ if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
+ pte |= PG_ACCESSED_MASK;
+ if (is_dirty)
+ pte |= PG_DIRTY_MASK;
+ stl(pte_ptr, pte);
+ }
+ page_size = 4096;
+ virt_addr = addr & ~0xfff;
+ }
+ /* the page can be put in the TLB */
+ prot = PROT_READ;
+ if (is_user) {
+ if (pte & PG_RW_MASK)
+ prot |= PROT_WRITE;
+ } else {
+ if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) ||
+ (pte & PG_RW_MASK))
+ prot |= PROT_WRITE;
+ }
+
+ do_mapping:
+ if (env->hflags & HF_SOFTMMU_MASK) {
+ unsigned long paddr, vaddr, address, addend, page_offset;
+ int index;
+
+ /* software MMU case. Even if 4MB pages, we map only one 4KB
+ page in the cache to avoid filling it too fast */
+ page_offset = (addr & ~0xfff) & (page_size - 1);
+ paddr = (pte & ~0xfff) + page_offset;
+ vaddr = virt_addr + page_offset;
+ index = (addr >> 12) & (CPU_TLB_SIZE - 1);
+ pd = physpage_find(paddr);
+ if (pd & 0xfff) {
+ /* IO memory case */
+ address = vaddr | pd;
+ addend = paddr;
+ } else {
+ /* standard memory */
+ address = vaddr;
+ addend = (unsigned long)phys_ram_base + pd;
+ }
+ addend -= vaddr;
+ env->tlb_read[is_user][index].address = address;
+ env->tlb_read[is_user][index].addend = addend;
+ if (prot & PROT_WRITE) {
+ env->tlb_write[is_user][index].address = address;
+ env->tlb_write[is_user][index].addend = addend;
+ }
+ }
+ ret = 0;
+ /* XXX: incorrect for 4MB pages */
+ pd = physpage_find(pte & ~0xfff);
+ if ((pd & 0xfff) != 0) {
+ /* IO access: no mapping is done as it will be handled by the
+ soft MMU */
+ if (!(env->hflags & HF_SOFTMMU_MASK))
+ ret = 2;
+ } else {
+ void *map_addr;
+ map_addr = mmap((void *)virt_addr, page_size, prot,
+ MAP_SHARED | MAP_FIXED, phys_ram_fd, pd);
+ if (map_addr == MAP_FAILED) {
+ fprintf(stderr,
+ "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
+ pte & ~0xfff, virt_addr);
+ exit(1);
+ }
+#ifdef DEBUG_MMU
+ printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
+ pte & ~0xfff, virt_addr, (page_size != 4096));
+#endif
+ page_set_flags(virt_addr, virt_addr + page_size,
+ PAGE_VALID | PAGE_EXEC | prot);
+ }
+ return ret;
+ do_fault_protect:
+ error_code = PG_ERROR_P_MASK;
+ do_fault:
+ env->cr[2] = addr;
+ env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
+ if (is_user)
+ env->error_code |= PG_ERROR_U_MASK;
+ return 1;
+}
diff --git a/target-i386/op.c b/target-i386/op.c
new file mode 100644
index 0000000000..68191f9bc4
--- /dev/null
+++ b/target-i386/op.c
@@ -0,0 +1,2054 @@
+/*
+ * i386 micro operations
+ *
+ * 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 "exec.h"
+
+/* n must be a constant to be efficient */
+static inline int lshift(int x, int n)
+{
+ if (n >= 0)
+ return x << n;
+ else
+ return x >> (-n);
+}
+
+/* we define the various pieces of code used by the JIT */
+
+#define REG EAX
+#define REGNAME _EAX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG ECX
+#define REGNAME _ECX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG EDX
+#define REGNAME _EDX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG EBX
+#define REGNAME _EBX
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG ESP
+#define REGNAME _ESP
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG EBP
+#define REGNAME _EBP
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG ESI
+#define REGNAME _ESI
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+#define REG EDI
+#define REGNAME _EDI
+#include "opreg_template.h"
+#undef REG
+#undef REGNAME
+
+/* operations with flags */
+
+/* update flags with T0 and T1 (add/sub case) */
+void OPPROTO op_update2_cc(void)
+{
+ CC_SRC = T1;
+ CC_DST = T0;
+}
+
+/* update flags with T0 (logic operation case) */
+void OPPROTO op_update1_cc(void)
+{
+ CC_DST = T0;
+}
+
+void OPPROTO op_update_neg_cc(void)
+{
+ CC_SRC = -T0;
+ CC_DST = T0;
+}
+
+void OPPROTO op_cmpl_T0_T1_cc(void)
+{
+ CC_SRC = T1;
+ CC_DST = T0 - T1;
+}
+
+void OPPROTO op_update_inc_cc(void)
+{
+ CC_SRC = cc_table[CC_OP].compute_c();
+ CC_DST = T0;
+}
+
+void OPPROTO op_testl_T0_T1_cc(void)
+{
+ CC_DST = T0 & T1;
+}
+
+/* operations without flags */
+
+void OPPROTO op_addl_T0_T1(void)
+{
+ T0 += T1;
+}
+
+void OPPROTO op_orl_T0_T1(void)
+{
+ T0 |= T1;
+}
+
+void OPPROTO op_andl_T0_T1(void)
+{
+ T0 &= T1;
+}
+
+void OPPROTO op_subl_T0_T1(void)
+{
+ T0 -= T1;
+}
+
+void OPPROTO op_xorl_T0_T1(void)
+{
+ T0 ^= T1;
+}
+
+void OPPROTO op_negl_T0(void)
+{
+ T0 = -T0;
+}
+
+void OPPROTO op_incl_T0(void)
+{
+ T0++;
+}
+
+void OPPROTO op_decl_T0(void)
+{
+ T0--;
+}
+
+void OPPROTO op_notl_T0(void)
+{
+ T0 = ~T0;
+}
+
+void OPPROTO op_bswapl_T0(void)
+{
+ T0 = bswap32(T0);
+}
+
+/* multiply/divide */
+void OPPROTO op_mulb_AL_T0(void)
+{
+ unsigned int res;
+ res = (uint8_t)EAX * (uint8_t)T0;
+ EAX = (EAX & 0xffff0000) | res;
+ CC_SRC = (res & 0xff00);
+}
+
+void OPPROTO op_imulb_AL_T0(void)
+{
+ int res;
+ res = (int8_t)EAX * (int8_t)T0;
+ EAX = (EAX & 0xffff0000) | (res & 0xffff);
+ CC_SRC = (res != (int8_t)res);
+}
+
+void OPPROTO op_mulw_AX_T0(void)
+{
+ unsigned int res;
+ res = (uint16_t)EAX * (uint16_t)T0;
+ EAX = (EAX & 0xffff0000) | (res & 0xffff);
+ EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
+ CC_SRC = res >> 16;
+}
+
+void OPPROTO op_imulw_AX_T0(void)
+{
+ int res;
+ res = (int16_t)EAX * (int16_t)T0;
+ EAX = (EAX & 0xffff0000) | (res & 0xffff);
+ EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff);
+ CC_SRC = (res != (int16_t)res);
+}
+
+void OPPROTO op_mull_EAX_T0(void)
+{
+ uint64_t res;
+ res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0);
+ EAX = res;
+ EDX = res >> 32;
+ CC_SRC = res >> 32;
+}
+
+void OPPROTO op_imull_EAX_T0(void)
+{
+ int64_t res;
+ res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
+ EAX = res;
+ EDX = res >> 32;
+ CC_SRC = (res != (int32_t)res);
+}
+
+void OPPROTO op_imulw_T0_T1(void)
+{
+ int res;
+ res = (int16_t)T0 * (int16_t)T1;
+ T0 = res;
+ CC_SRC = (res != (int16_t)res);
+}
+
+void OPPROTO op_imull_T0_T1(void)
+{
+ int64_t res;
+ res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
+ T0 = res;
+ CC_SRC = (res != (int32_t)res);
+}
+
+/* division, flags are undefined */
+/* XXX: add exceptions for overflow */
+
+void OPPROTO op_divb_AL_T0(void)
+{
+ unsigned int num, den, q, r;
+
+ num = (EAX & 0xffff);
+ den = (T0 & 0xff);
+ if (den == 0) {
+ EIP = PARAM1;
+ raise_exception(EXCP00_DIVZ);
+ }
+ q = (num / den) & 0xff;
+ r = (num % den) & 0xff;
+ EAX = (EAX & 0xffff0000) | (r << 8) | q;
+}
+
+void OPPROTO op_idivb_AL_T0(void)
+{
+ int num, den, q, r;
+
+ num = (int16_t)EAX;
+ den = (int8_t)T0;
+ if (den == 0) {
+ EIP = PARAM1;
+ raise_exception(EXCP00_DIVZ);
+ }
+ q = (num / den) & 0xff;
+ r = (num % den) & 0xff;
+ EAX = (EAX & 0xffff0000) | (r << 8) | q;
+}
+
+void OPPROTO op_divw_AX_T0(void)
+{
+ unsigned int num, den, q, r;
+
+ num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+ den = (T0 & 0xffff);
+ if (den == 0) {
+ EIP = PARAM1;
+ raise_exception(EXCP00_DIVZ);
+ }
+ q = (num / den) & 0xffff;
+ r = (num % den) & 0xffff;
+ EAX = (EAX & 0xffff0000) | q;
+ EDX = (EDX & 0xffff0000) | r;
+}
+
+void OPPROTO op_idivw_AX_T0(void)
+{
+ int num, den, q, r;
+
+ num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
+ den = (int16_t)T0;
+ if (den == 0) {
+ EIP = PARAM1;
+ raise_exception(EXCP00_DIVZ);
+ }
+ q = (num / den) & 0xffff;
+ r = (num % den) & 0xffff;
+ EAX = (EAX & 0xffff0000) | q;
+ EDX = (EDX & 0xffff0000) | r;
+}
+
+void OPPROTO op_divl_EAX_T0(void)
+{
+ helper_divl_EAX_T0(PARAM1);
+}
+
+void OPPROTO op_idivl_EAX_T0(void)
+{
+ helper_idivl_EAX_T0(PARAM1);
+}
+
+/* constant load & misc op */
+
+void OPPROTO op_movl_T0_im(void)
+{
+ T0 = PARAM1;
+}
+
+void OPPROTO op_addl_T0_im(void)
+{
+ T0 += PARAM1;
+}
+
+void OPPROTO op_andl_T0_ffff(void)
+{
+ T0 = T0 & 0xffff;
+}
+
+void OPPROTO op_andl_T0_im(void)
+{
+ T0 = T0 & PARAM1;
+}
+
+void OPPROTO op_movl_T0_T1(void)
+{
+ T0 = T1;
+}
+
+void OPPROTO op_movl_T1_im(void)
+{
+ T1 = PARAM1;
+}
+
+void OPPROTO op_addl_T1_im(void)
+{
+ T1 += PARAM1;
+}
+
+void OPPROTO op_movl_T1_A0(void)
+{
+ T1 = A0;
+}
+
+void OPPROTO op_movl_A0_im(void)
+{
+ A0 = PARAM1;
+}
+
+void OPPROTO op_addl_A0_im(void)
+{
+ A0 += PARAM1;
+}
+
+void OPPROTO op_addl_A0_AL(void)
+{
+ A0 += (EAX & 0xff);
+}
+
+void OPPROTO op_andl_A0_ffff(void)
+{
+ A0 = A0 & 0xffff;
+}
+
+/* memory access */
+
+#define MEMSUFFIX
+#include "ops_mem.h"
+
+#define MEMSUFFIX _user
+#include "ops_mem.h"
+
+#define MEMSUFFIX _kernel
+#include "ops_mem.h"
+
+/* used for bit operations */
+
+void OPPROTO op_add_bitw_A0_T1(void)
+{
+ A0 += ((int32_t)T1 >> 4) << 1;
+}
+
+void OPPROTO op_add_bitl_A0_T1(void)
+{
+ A0 += ((int32_t)T1 >> 5) << 2;
+}
+
+/* indirect jump */
+
+void OPPROTO op_jmp_T0(void)
+{
+ EIP = T0;
+}
+
+void OPPROTO op_jmp_im(void)
+{
+ EIP = PARAM1;
+}
+
+void OPPROTO op_hlt(void)
+{
+ env->exception_index = EXCP_HLT;
+ cpu_loop_exit();
+}
+
+void OPPROTO op_debug(void)
+{
+ env->exception_index = EXCP_DEBUG;
+ cpu_loop_exit();
+}
+
+void OPPROTO op_raise_interrupt(void)
+{
+ int intno;
+ unsigned int next_eip;
+ intno = PARAM1;
+ next_eip = PARAM2;
+ raise_interrupt(intno, 1, 0, next_eip);
+}
+
+void OPPROTO op_raise_exception(void)
+{
+ int exception_index;
+ exception_index = PARAM1;
+ raise_exception(exception_index);
+}
+
+void OPPROTO op_into(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ if (eflags & CC_O) {
+ raise_interrupt(EXCP04_INTO, 1, 0, PARAM1);
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_cli(void)
+{
+ env->eflags &= ~IF_MASK;
+}
+
+void OPPROTO op_sti(void)
+{
+ env->eflags |= IF_MASK;
+}
+
+void OPPROTO op_set_inhibit_irq(void)
+{
+ env->hflags |= HF_INHIBIT_IRQ_MASK;
+}
+
+void OPPROTO op_reset_inhibit_irq(void)
+{
+ env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+}
+
+#if 0
+/* vm86plus instructions */
+void OPPROTO op_cli_vm(void)
+{
+ env->eflags &= ~VIF_MASK;
+}
+
+void OPPROTO op_sti_vm(void)
+{
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ FORCE_RET();
+}
+#endif
+
+void OPPROTO op_boundw(void)
+{
+ int low, high, v;
+ low = ldsw((uint8_t *)A0);
+ high = ldsw((uint8_t *)A0 + 2);
+ v = (int16_t)T0;
+ if (v < low || v > high) {
+ EIP = PARAM1;
+ raise_exception(EXCP05_BOUND);
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_boundl(void)
+{
+ int low, high, v;
+ low = ldl((uint8_t *)A0);
+ high = ldl((uint8_t *)A0 + 4);
+ v = T0;
+ if (v < low || v > high) {
+ EIP = PARAM1;
+ raise_exception(EXCP05_BOUND);
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_cmpxchg8b(void)
+{
+ helper_cmpxchg8b();
+}
+
+void OPPROTO op_jmp(void)
+{
+ JUMP_TB(op_jmp, PARAM1, 0, PARAM2);
+}
+
+void OPPROTO op_movl_T0_0(void)
+{
+ T0 = 0;
+}
+
+void OPPROTO op_exit_tb(void)
+{
+ EXIT_TB();
+}
+
+/* multiple size ops */
+
+#define ldul ldl
+
+#define SHIFT 0
+#include "ops_template.h"
+#undef SHIFT
+
+#define SHIFT 1
+#include "ops_template.h"
+#undef SHIFT
+
+#define SHIFT 2
+#include "ops_template.h"
+#undef SHIFT
+
+/* sign extend */
+
+void OPPROTO op_movsbl_T0_T0(void)
+{
+ T0 = (int8_t)T0;
+}
+
+void OPPROTO op_movzbl_T0_T0(void)
+{
+ T0 = (uint8_t)T0;
+}
+
+void OPPROTO op_movswl_T0_T0(void)
+{
+ T0 = (int16_t)T0;
+}
+
+void OPPROTO op_movzwl_T0_T0(void)
+{
+ T0 = (uint16_t)T0;
+}
+
+void OPPROTO op_movswl_EAX_AX(void)
+{
+ EAX = (int16_t)EAX;
+}
+
+void OPPROTO op_movsbw_AX_AL(void)
+{
+ EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff);
+}
+
+void OPPROTO op_movslq_EDX_EAX(void)
+{
+ EDX = (int32_t)EAX >> 31;
+}
+
+void OPPROTO op_movswl_DX_AX(void)
+{
+ EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff);
+}
+
+/* string ops helpers */
+
+void OPPROTO op_addl_ESI_T0(void)
+{
+ ESI += T0;
+}
+
+void OPPROTO op_addw_ESI_T0(void)
+{
+ ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff);
+}
+
+void OPPROTO op_addl_EDI_T0(void)
+{
+ EDI += T0;
+}
+
+void OPPROTO op_addw_EDI_T0(void)
+{
+ EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff);
+}
+
+void OPPROTO op_decl_ECX(void)
+{
+ ECX--;
+}
+
+void OPPROTO op_decw_ECX(void)
+{
+ ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff);
+}
+
+/* push/pop */
+
+void op_pushl_T0(void)
+{
+ uint32_t offset;
+ offset = ESP - 4;
+ stl((void *)offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = offset;
+}
+
+void op_pushw_T0(void)
+{
+ uint32_t offset;
+ offset = ESP - 2;
+ stw((void *)offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = offset;
+}
+
+void op_pushl_ss32_T0(void)
+{
+ uint32_t offset;
+ offset = ESP - 4;
+ stl(env->segs[R_SS].base + offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = offset;
+}
+
+void op_pushw_ss32_T0(void)
+{
+ uint32_t offset;
+ offset = ESP - 2;
+ stw(env->segs[R_SS].base + offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = offset;
+}
+
+void op_pushl_ss16_T0(void)
+{
+ uint32_t offset;
+ offset = (ESP - 4) & 0xffff;
+ stl(env->segs[R_SS].base + offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = (ESP & ~0xffff) | offset;
+}
+
+void op_pushw_ss16_T0(void)
+{
+ uint32_t offset;
+ offset = (ESP - 2) & 0xffff;
+ stw(env->segs[R_SS].base + offset, T0);
+ /* modify ESP after to handle exceptions correctly */
+ ESP = (ESP & ~0xffff) | offset;
+}
+
+/* NOTE: ESP update is done after */
+void op_popl_T0(void)
+{
+ T0 = ldl((void *)ESP);
+}
+
+void op_popw_T0(void)
+{
+ T0 = lduw((void *)ESP);
+}
+
+void op_popl_ss32_T0(void)
+{
+ T0 = ldl(env->segs[R_SS].base + ESP);
+}
+
+void op_popw_ss32_T0(void)
+{
+ T0 = lduw(env->segs[R_SS].base + ESP);
+}
+
+void op_popl_ss16_T0(void)
+{
+ T0 = ldl(env->segs[R_SS].base + (ESP & 0xffff));
+}
+
+void op_popw_ss16_T0(void)
+{
+ T0 = lduw(env->segs[R_SS].base + (ESP & 0xffff));
+}
+
+void op_addl_ESP_4(void)
+{
+ ESP += 4;
+}
+
+void op_addl_ESP_2(void)
+{
+ ESP += 2;
+}
+
+void op_addw_ESP_4(void)
+{
+ ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff);
+}
+
+void op_addw_ESP_2(void)
+{
+ ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff);
+}
+
+void op_addl_ESP_im(void)
+{
+ ESP += PARAM1;
+}
+
+void op_addw_ESP_im(void)
+{
+ ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
+}
+
+void OPPROTO op_rdtsc(void)
+{
+ helper_rdtsc();
+}
+
+void OPPROTO op_cpuid(void)
+{
+ helper_cpuid();
+}
+
+void OPPROTO op_rdmsr(void)
+{
+ helper_rdmsr();
+}
+
+void OPPROTO op_wrmsr(void)
+{
+ helper_wrmsr();
+}
+
+/* bcd */
+
+/* XXX: exception */
+void OPPROTO op_aam(void)
+{
+ int base = PARAM1;
+ int al, ah;
+ al = EAX & 0xff;
+ ah = al / base;
+ al = al % base;
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_DST = al;
+}
+
+void OPPROTO op_aad(void)
+{
+ int base = PARAM1;
+ int al, ah;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+ al = ((ah * base) + al) & 0xff;
+ EAX = (EAX & ~0xffff) | al;
+ CC_DST = al;
+}
+
+void OPPROTO op_aaa(void)
+{
+ int icarry;
+ int al, ah, af;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+
+ icarry = (al > 0xf9);
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al + 6) & 0x0f;
+ ah = (ah + 1 + icarry) & 0xff;
+ eflags |= CC_C | CC_A;
+ } else {
+ eflags &= ~(CC_C | CC_A);
+ al &= 0x0f;
+ }
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_aas(void)
+{
+ int icarry;
+ int al, ah, af;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+
+ icarry = (al < 6);
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al - 6) & 0x0f;
+ ah = (ah - 1 - icarry) & 0xff;
+ eflags |= CC_C | CC_A;
+ } else {
+ eflags &= ~(CC_C | CC_A);
+ al &= 0x0f;
+ }
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_daa(void)
+{
+ int al, af, cf;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ cf = eflags & CC_C;
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+
+ eflags = 0;
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al + 6) & 0xff;
+ eflags |= CC_A;
+ }
+ if ((al > 0x9f) || cf) {
+ al = (al + 0x60) & 0xff;
+ eflags |= CC_C;
+ }
+ EAX = (EAX & ~0xff) | al;
+ /* well, speed is not an issue here, so we compute the flags by hand */
+ eflags |= (al == 0) << 6; /* zf */
+ eflags |= parity_table[al]; /* pf */
+ eflags |= (al & 0x80); /* sf */
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_das(void)
+{
+ int al, al1, af, cf;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ cf = eflags & CC_C;
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+
+ eflags = 0;
+ al1 = al;
+ if (((al & 0x0f) > 9 ) || af) {
+ eflags |= CC_A;
+ if (al < 6 || cf)
+ eflags |= CC_C;
+ al = (al - 6) & 0xff;
+ }
+ if ((al1 > 0x99) || cf) {
+ al = (al - 0x60) & 0xff;
+ eflags |= CC_C;
+ }
+ EAX = (EAX & ~0xff) | al;
+ /* well, speed is not an issue here, so we compute the flags by hand */
+ eflags |= (al == 0) << 6; /* zf */
+ eflags |= parity_table[al]; /* pf */
+ eflags |= (al & 0x80); /* sf */
+ CC_SRC = eflags;
+}
+
+/* segment handling */
+
+/* never use it with R_CS */
+void OPPROTO op_movl_seg_T0(void)
+{
+ load_seg(PARAM1, T0 & 0xffff, PARAM2);
+}
+
+/* faster VM86 version */
+void OPPROTO op_movl_seg_T0_vm(void)
+{
+ int selector;
+ SegmentCache *sc;
+
+ selector = T0 & 0xffff;
+ /* env->segs[] access */
+ sc = (SegmentCache *)((char *)env + PARAM1);
+ sc->selector = selector;
+ sc->base = (void *)(selector << 4);
+}
+
+void OPPROTO op_movl_T0_seg(void)
+{
+ T0 = env->segs[PARAM1].selector;
+}
+
+void OPPROTO op_movl_A0_seg(void)
+{
+ A0 = *(unsigned long *)((char *)env + PARAM1);
+}
+
+void OPPROTO op_addl_A0_seg(void)
+{
+ A0 += *(unsigned long *)((char *)env + PARAM1);
+}
+
+void OPPROTO op_lsl(void)
+{
+ helper_lsl();
+}
+
+void OPPROTO op_lar(void)
+{
+ helper_lar();
+}
+
+/* T0: segment, T1:eip */
+void OPPROTO op_ljmp_protected_T0_T1(void)
+{
+ helper_ljmp_protected_T0_T1();
+}
+
+void OPPROTO op_lcall_real_T0_T1(void)
+{
+ helper_lcall_real_T0_T1(PARAM1, PARAM2);
+}
+
+void OPPROTO op_lcall_protected_T0_T1(void)
+{
+ helper_lcall_protected_T0_T1(PARAM1, PARAM2);
+}
+
+void OPPROTO op_iret_real(void)
+{
+ helper_iret_real(PARAM1);
+}
+
+void OPPROTO op_iret_protected(void)
+{
+ helper_iret_protected(PARAM1);
+}
+
+void OPPROTO op_lret_protected(void)
+{
+ helper_lret_protected(PARAM1, PARAM2);
+}
+
+void OPPROTO op_lldt_T0(void)
+{
+ helper_lldt_T0();
+}
+
+void OPPROTO op_ltr_T0(void)
+{
+ helper_ltr_T0();
+}
+
+/* CR registers access */
+void OPPROTO op_movl_crN_T0(void)
+{
+ helper_movl_crN_T0(PARAM1);
+}
+
+/* DR registers access */
+void OPPROTO op_movl_drN_T0(void)
+{
+ helper_movl_drN_T0(PARAM1);
+}
+
+void OPPROTO op_lmsw_T0(void)
+{
+ /* only 4 lower bits of CR0 are modified */
+ T0 = (env->cr[0] & ~0xf) | (T0 & 0xf);
+ helper_movl_crN_T0(0);
+}
+
+void OPPROTO op_invlpg_A0(void)
+{
+ helper_invlpg(A0);
+}
+
+void OPPROTO op_movl_T0_env(void)
+{
+ T0 = *(uint32_t *)((char *)env + PARAM1);
+}
+
+void OPPROTO op_movl_env_T0(void)
+{
+ *(uint32_t *)((char *)env + PARAM1) = T0;
+}
+
+void OPPROTO op_movl_env_T1(void)
+{
+ *(uint32_t *)((char *)env + PARAM1) = T1;
+}
+
+void OPPROTO op_clts(void)
+{
+ env->cr[0] &= ~CR0_TS_MASK;
+}
+
+/* flags handling */
+
+/* slow jumps cases : in order to avoid calling a function with a
+ pointer (which can generate a stack frame on PowerPC), we use
+ op_setcc to set T0 and then call op_jcc. */
+void OPPROTO op_jcc(void)
+{
+ if (T0)
+ JUMP_TB(op_jcc, PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(op_jcc, PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO op_jcc_im(void)
+{
+ if (T0)
+ EIP = PARAM1;
+ else
+ EIP = PARAM2;
+ FORCE_RET();
+}
+
+/* slow set cases (compute x86 flags) */
+void OPPROTO op_seto_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (eflags >> 11) & 1;
+}
+
+void OPPROTO op_setb_T0_cc(void)
+{
+ T0 = cc_table[CC_OP].compute_c();
+}
+
+void OPPROTO op_setz_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (eflags >> 6) & 1;
+}
+
+void OPPROTO op_setbe_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (eflags & (CC_Z | CC_C)) != 0;
+}
+
+void OPPROTO op_sets_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (eflags >> 7) & 1;
+}
+
+void OPPROTO op_setp_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (eflags >> 2) & 1;
+}
+
+void OPPROTO op_setl_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1;
+}
+
+void OPPROTO op_setle_T0_cc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0;
+}
+
+void OPPROTO op_xor_T0_1(void)
+{
+ T0 ^= 1;
+}
+
+void OPPROTO op_set_cc_op(void)
+{
+ CC_OP = PARAM1;
+}
+
+#define FL_UPDATE_MASK16 (FL_UPDATE_MASK32 & 0xffff)
+
+void OPPROTO op_movl_eflags_T0(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~FL_UPDATE_MASK32) |
+ (eflags & FL_UPDATE_MASK32);
+}
+
+void OPPROTO op_movw_eflags_T0(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~FL_UPDATE_MASK16) |
+ (eflags & FL_UPDATE_MASK16);
+}
+
+void OPPROTO op_movl_eflags_T0_cpl0(void)
+{
+ load_eflags(T0, FL_UPDATE_CPL0_MASK);
+}
+
+void OPPROTO op_movw_eflags_T0_cpl0(void)
+{
+ load_eflags(T0, FL_UPDATE_CPL0_MASK & 0xffff);
+}
+
+#if 0
+/* vm86plus version */
+void OPPROTO op_movw_eflags_T0_vm(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) |
+ (eflags & FL_UPDATE_MASK16);
+ if (eflags & IF_MASK) {
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_movl_eflags_T0_vm(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) |
+ (eflags & FL_UPDATE_MASK32);
+ if (eflags & IF_MASK) {
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ }
+ FORCE_RET();
+}
+#endif
+
+/* XXX: compute only O flag */
+void OPPROTO op_movb_eflags_T0(void)
+{
+ int of;
+ of = cc_table[CC_OP].compute_all() & CC_O;
+ CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of;
+}
+
+void OPPROTO op_movl_T0_eflags(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= (DF & DF_MASK);
+ eflags |= env->eflags & ~(VM_MASK | RF_MASK);
+ T0 = eflags;
+}
+
+/* vm86plus version */
+#if 0
+void OPPROTO op_movl_T0_eflags_vm(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= (DF & DF_MASK);
+ eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
+ if (env->eflags & VIF_MASK)
+ eflags |= IF_MASK;
+ T0 = eflags;
+}
+#endif
+
+void OPPROTO op_cld(void)
+{
+ DF = 1;
+}
+
+void OPPROTO op_std(void)
+{
+ DF = -1;
+}
+
+void OPPROTO op_clc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags &= ~CC_C;
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_stc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= CC_C;
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_cmc(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags ^= CC_C;
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_salc(void)
+{
+ int cf;
+ cf = cc_table[CC_OP].compute_c();
+ EAX = (EAX & ~0xff) | ((-cf) & 0xff);
+}
+
+static int compute_all_eflags(void)
+{
+ return CC_SRC;
+}
+
+static int compute_c_eflags(void)
+{
+ return CC_SRC & CC_C;
+}
+
+static int compute_c_mul(void)
+{
+ int cf;
+ cf = (CC_SRC != 0);
+ return cf;
+}
+
+static int compute_all_mul(void)
+{
+ int cf, pf, af, zf, sf, of;
+ cf = (CC_SRC != 0);
+ pf = 0; /* undefined */
+ af = 0; /* undefined */
+ zf = 0; /* undefined */
+ sf = 0; /* undefined */
+ of = cf << 11;
+ return cf | pf | af | zf | sf | of;
+}
+
+CCTable cc_table[CC_OP_NB] = {
+ [CC_OP_DYNAMIC] = { /* should never happen */ },
+
+ [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
+
+ [CC_OP_MUL] = { compute_all_mul, compute_c_mul },
+
+ [CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
+ [CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
+ [CC_OP_ADDL] = { compute_all_addl, compute_c_addl },
+
+ [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb },
+ [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw },
+ [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl },
+
+ [CC_OP_SUBB] = { compute_all_subb, compute_c_subb },
+ [CC_OP_SUBW] = { compute_all_subw, compute_c_subw },
+ [CC_OP_SUBL] = { compute_all_subl, compute_c_subl },
+
+ [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb },
+ [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw },
+ [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl },
+
+ [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
+ [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
+ [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
+
+ [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
+ [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
+ [CC_OP_INCL] = { compute_all_incl, compute_c_incl },
+
+ [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
+ [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
+ [CC_OP_DECL] = { compute_all_decl, compute_c_incl },
+
+ [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
+ [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
+ [CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
+
+ [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
+ [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
+ [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
+};
+
+/* floating point support. Some of the code for complicated x87
+ functions comes from the LGPL'ed x86 emulator found in the Willows
+ TWIN windows emulator. */
+
+#if defined(__powerpc__)
+extern CPU86_LDouble copysign(CPU86_LDouble, CPU86_LDouble);
+
+/* correct (but slow) PowerPC rint() (glibc version is incorrect) */
+double qemu_rint(double x)
+{
+ double y = 4503599627370496.0;
+ if (fabs(x) >= y)
+ return x;
+ if (x < 0)
+ y = -y;
+ y = (x + y) - y;
+ if (y == 0.0)
+ y = copysign(y, x);
+ return y;
+}
+
+#define rint qemu_rint
+#endif
+
+/* fp load FT0 */
+
+void OPPROTO op_flds_FT0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = ldl((void *)A0);
+ FT0 = FP_CONVERT.f;
+#else
+ FT0 = ldfl((void *)A0);
+#endif
+}
+
+void OPPROTO op_fldl_FT0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i64 = ldq((void *)A0);
+ FT0 = FP_CONVERT.d;
+#else
+ FT0 = ldfq((void *)A0);
+#endif
+}
+
+/* helpers are needed to avoid static constant reference. XXX: find a better way */
+#ifdef USE_INT_TO_FLOAT_HELPERS
+
+void helper_fild_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)ldsw((void *)A0);
+}
+
+void helper_fildl_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+}
+
+void helper_fildll_FT0_A0(void)
+{
+ FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+}
+
+void OPPROTO op_fild_FT0_A0(void)
+{
+ helper_fild_FT0_A0();
+}
+
+void OPPROTO op_fildl_FT0_A0(void)
+{
+ helper_fildl_FT0_A0();
+}
+
+void OPPROTO op_fildll_FT0_A0(void)
+{
+ helper_fildll_FT0_A0();
+}
+
+#else
+
+void OPPROTO op_fild_FT0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = ldsw((void *)A0);
+ FT0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
+ FT0 = (CPU86_LDouble)ldsw((void *)A0);
+#endif
+}
+
+void OPPROTO op_fildl_FT0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
+ FT0 = (CPU86_LDouble)FP_CONVERT.i32;
+#else
+ FT0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+#endif
+}
+
+void OPPROTO op_fildll_FT0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
+ FT0 = (CPU86_LDouble)FP_CONVERT.i64;
+#else
+ FT0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+#endif
+}
+#endif
+
+/* fp load ST0 */
+
+void OPPROTO op_flds_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = ldl((void *)A0);
+ env->fpregs[new_fpstt] = FP_CONVERT.f;
+#else
+ env->fpregs[new_fpstt] = ldfl((void *)A0);
+#endif
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void OPPROTO op_fldl_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i64 = ldq((void *)A0);
+ env->fpregs[new_fpstt] = FP_CONVERT.d;
+#else
+ env->fpregs[new_fpstt] = ldfq((void *)A0);
+#endif
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+#ifdef USE_X86LDOUBLE
+void OPPROTO op_fldt_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+ env->fpregs[new_fpstt] = *(long double *)A0;
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+#else
+void OPPROTO op_fldt_ST0_A0(void)
+{
+ helper_fldt_ST0_A0();
+}
+#endif
+
+/* helpers are needed to avoid static constant reference. XXX: find a better way */
+#ifdef USE_INT_TO_FLOAT_HELPERS
+
+void helper_fild_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+ env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildl_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+ env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void helper_fildll_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+ env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void OPPROTO op_fild_ST0_A0(void)
+{
+ helper_fild_ST0_A0();
+}
+
+void OPPROTO op_fildl_ST0_A0(void)
+{
+ helper_fildl_ST0_A0();
+}
+
+void OPPROTO op_fildll_ST0_A0(void)
+{
+ helper_fildll_ST0_A0();
+}
+
+#else
+
+void OPPROTO op_fild_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = ldsw((void *)A0);
+ env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
+#else
+ env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
+#endif
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void OPPROTO op_fildl_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
+ env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
+#else
+ env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
+#endif
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+void OPPROTO op_fildll_ST0_A0(void)
+{
+ int new_fpstt;
+ new_fpstt = (env->fpstt - 1) & 7;
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
+ env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
+#else
+ env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
+#endif
+ env->fpstt = new_fpstt;
+ env->fptags[new_fpstt] = 0; /* validate stack entry */
+}
+
+#endif
+
+/* fp store */
+
+void OPPROTO op_fsts_ST0_A0(void)
+{
+#ifdef USE_FP_CONVERT
+ FP_CONVERT.f = (float)ST0;
+ stfl((void *)A0, FP_CONVERT.f);
+#else
+ stfl((void *)A0, (float)ST0);
+#endif
+}
+
+void OPPROTO op_fstl_ST0_A0(void)
+{
+ stfq((void *)A0, (double)ST0);
+}
+
+#ifdef USE_X86LDOUBLE
+void OPPROTO op_fstt_ST0_A0(void)
+{
+ *(long double *)A0 = ST0;
+}
+#else
+void OPPROTO op_fstt_ST0_A0(void)
+{
+ helper_fstt_ST0_A0();
+}
+#endif
+
+void OPPROTO op_fist_ST0_A0(void)
+{
+#if defined(__sparc__) && !defined(__sparc_v9__)
+ register CPU86_LDouble d asm("o0");
+#else
+ CPU86_LDouble d;
+#endif
+ int val;
+
+ d = ST0;
+ val = lrint(d);
+ if (val != (int16_t)val)
+ val = -32768;
+ stw((void *)A0, val);
+}
+
+void OPPROTO op_fistl_ST0_A0(void)
+{
+#if defined(__sparc__) && !defined(__sparc_v9__)
+ register CPU86_LDouble d asm("o0");
+#else
+ CPU86_LDouble d;
+#endif
+ int val;
+
+ d = ST0;
+ val = lrint(d);
+ stl((void *)A0, val);
+}
+
+void OPPROTO op_fistll_ST0_A0(void)
+{
+#if defined(__sparc__) && !defined(__sparc_v9__)
+ register CPU86_LDouble d asm("o0");
+#else
+ CPU86_LDouble d;
+#endif
+ int64_t val;
+
+ d = ST0;
+ val = llrint(d);
+ stq((void *)A0, val);
+}
+
+void OPPROTO op_fbld_ST0_A0(void)
+{
+ helper_fbld_ST0_A0();
+}
+
+void OPPROTO op_fbst_ST0_A0(void)
+{
+ helper_fbst_ST0_A0();
+}
+
+/* FPU move */
+
+void OPPROTO op_fpush(void)
+{
+ fpush();
+}
+
+void OPPROTO op_fpop(void)
+{
+ fpop();
+}
+
+void OPPROTO op_fdecstp(void)
+{
+ env->fpstt = (env->fpstt - 1) & 7;
+ env->fpus &= (~0x4700);
+}
+
+void OPPROTO op_fincstp(void)
+{
+ env->fpstt = (env->fpstt + 1) & 7;
+ env->fpus &= (~0x4700);
+}
+
+void OPPROTO op_fmov_ST0_FT0(void)
+{
+ ST0 = FT0;
+}
+
+void OPPROTO op_fmov_FT0_STN(void)
+{
+ FT0 = ST(PARAM1);
+}
+
+void OPPROTO op_fmov_ST0_STN(void)
+{
+ ST0 = ST(PARAM1);
+}
+
+void OPPROTO op_fmov_STN_ST0(void)
+{
+ ST(PARAM1) = ST0;
+}
+
+void OPPROTO op_fxchg_ST0_STN(void)
+{
+ CPU86_LDouble tmp;
+ tmp = ST(PARAM1);
+ ST(PARAM1) = ST0;
+ ST0 = tmp;
+}
+
+/* FPU operations */
+
+/* XXX: handle nans */
+void OPPROTO op_fcom_ST0_FT0(void)
+{
+ env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */
+ if (ST0 < FT0)
+ env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */
+ else if (ST0 == FT0)
+ env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
+ FORCE_RET();
+}
+
+/* XXX: handle nans */
+void OPPROTO op_fucom_ST0_FT0(void)
+{
+ env->fpus &= (~0x4500); /* (C3,C2,C0) <-- 000 */
+ if (ST0 < FT0)
+ env->fpus |= 0x100; /* (C3,C2,C0) <-- 001 */
+ else if (ST0 == FT0)
+ env->fpus |= 0x4000; /* (C3,C2,C0) <-- 100 */
+ FORCE_RET();
+}
+
+/* XXX: handle nans */
+void OPPROTO op_fcomi_ST0_FT0(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags &= ~(CC_Z | CC_P | CC_C);
+ if (ST0 < FT0)
+ eflags |= CC_C;
+ else if (ST0 == FT0)
+ eflags |= CC_Z;
+ CC_SRC = eflags;
+ FORCE_RET();
+}
+
+/* XXX: handle nans */
+void OPPROTO op_fucomi_ST0_FT0(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags &= ~(CC_Z | CC_P | CC_C);
+ if (ST0 < FT0)
+ eflags |= CC_C;
+ else if (ST0 == FT0)
+ eflags |= CC_Z;
+ CC_SRC = eflags;
+ FORCE_RET();
+}
+
+void OPPROTO op_fadd_ST0_FT0(void)
+{
+ ST0 += FT0;
+}
+
+void OPPROTO op_fmul_ST0_FT0(void)
+{
+ ST0 *= FT0;
+}
+
+void OPPROTO op_fsub_ST0_FT0(void)
+{
+ ST0 -= FT0;
+}
+
+void OPPROTO op_fsubr_ST0_FT0(void)
+{
+ ST0 = FT0 - ST0;
+}
+
+void OPPROTO op_fdiv_ST0_FT0(void)
+{
+ ST0 /= FT0;
+}
+
+void OPPROTO op_fdivr_ST0_FT0(void)
+{
+ ST0 = FT0 / ST0;
+}
+
+/* fp operations between STN and ST0 */
+
+void OPPROTO op_fadd_STN_ST0(void)
+{
+ ST(PARAM1) += ST0;
+}
+
+void OPPROTO op_fmul_STN_ST0(void)
+{
+ ST(PARAM1) *= ST0;
+}
+
+void OPPROTO op_fsub_STN_ST0(void)
+{
+ ST(PARAM1) -= ST0;
+}
+
+void OPPROTO op_fsubr_STN_ST0(void)
+{
+ CPU86_LDouble *p;
+ p = &ST(PARAM1);
+ *p = ST0 - *p;
+}
+
+void OPPROTO op_fdiv_STN_ST0(void)
+{
+ ST(PARAM1) /= ST0;
+}
+
+void OPPROTO op_fdivr_STN_ST0(void)
+{
+ CPU86_LDouble *p;
+ p = &ST(PARAM1);
+ *p = ST0 / *p;
+}
+
+/* misc FPU operations */
+void OPPROTO op_fchs_ST0(void)
+{
+ ST0 = -ST0;
+}
+
+void OPPROTO op_fabs_ST0(void)
+{
+ ST0 = fabs(ST0);
+}
+
+void OPPROTO op_fxam_ST0(void)
+{
+ helper_fxam_ST0();
+}
+
+void OPPROTO op_fld1_ST0(void)
+{
+ ST0 = f15rk[1];
+}
+
+void OPPROTO op_fldl2t_ST0(void)
+{
+ ST0 = f15rk[6];
+}
+
+void OPPROTO op_fldl2e_ST0(void)
+{
+ ST0 = f15rk[5];
+}
+
+void OPPROTO op_fldpi_ST0(void)
+{
+ ST0 = f15rk[2];
+}
+
+void OPPROTO op_fldlg2_ST0(void)
+{
+ ST0 = f15rk[3];
+}
+
+void OPPROTO op_fldln2_ST0(void)
+{
+ ST0 = f15rk[4];
+}
+
+void OPPROTO op_fldz_ST0(void)
+{
+ ST0 = f15rk[0];
+}
+
+void OPPROTO op_fldz_FT0(void)
+{
+ ST0 = f15rk[0];
+}
+
+/* associated heplers to reduce generated code length and to simplify
+ relocation (FP constants are usually stored in .rodata section) */
+
+void OPPROTO op_f2xm1(void)
+{
+ helper_f2xm1();
+}
+
+void OPPROTO op_fyl2x(void)
+{
+ helper_fyl2x();
+}
+
+void OPPROTO op_fptan(void)
+{
+ helper_fptan();
+}
+
+void OPPROTO op_fpatan(void)
+{
+ helper_fpatan();
+}
+
+void OPPROTO op_fxtract(void)
+{
+ helper_fxtract();
+}
+
+void OPPROTO op_fprem1(void)
+{
+ helper_fprem1();
+}
+
+
+void OPPROTO op_fprem(void)
+{
+ helper_fprem();
+}
+
+void OPPROTO op_fyl2xp1(void)
+{
+ helper_fyl2xp1();
+}
+
+void OPPROTO op_fsqrt(void)
+{
+ helper_fsqrt();
+}
+
+void OPPROTO op_fsincos(void)
+{
+ helper_fsincos();
+}
+
+void OPPROTO op_frndint(void)
+{
+ helper_frndint();
+}
+
+void OPPROTO op_fscale(void)
+{
+ helper_fscale();
+}
+
+void OPPROTO op_fsin(void)
+{
+ helper_fsin();
+}
+
+void OPPROTO op_fcos(void)
+{
+ helper_fcos();
+}
+
+void OPPROTO op_fnstsw_A0(void)
+{
+ int fpus;
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ stw((void *)A0, fpus);
+}
+
+void OPPROTO op_fnstsw_EAX(void)
+{
+ int fpus;
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ EAX = (EAX & 0xffff0000) | fpus;
+}
+
+void OPPROTO op_fnstcw_A0(void)
+{
+ stw((void *)A0, env->fpuc);
+}
+
+void OPPROTO op_fldcw_A0(void)
+{
+ int rnd_type;
+ env->fpuc = lduw((void *)A0);
+ /* set rounding mode */
+ switch(env->fpuc & RC_MASK) {
+ default:
+ case RC_NEAR:
+ rnd_type = FE_TONEAREST;
+ break;
+ case RC_DOWN:
+ rnd_type = FE_DOWNWARD;
+ break;
+ case RC_UP:
+ rnd_type = FE_UPWARD;
+ break;
+ case RC_CHOP:
+ rnd_type = FE_TOWARDZERO;
+ break;
+ }
+ fesetround(rnd_type);
+}
+
+void OPPROTO op_fclex(void)
+{
+ env->fpus &= 0x7f00;
+}
+
+void OPPROTO op_fninit(void)
+{
+ env->fpus = 0;
+ env->fpstt = 0;
+ env->fpuc = 0x37f;
+ env->fptags[0] = 1;
+ env->fptags[1] = 1;
+ env->fptags[2] = 1;
+ env->fptags[3] = 1;
+ env->fptags[4] = 1;
+ env->fptags[5] = 1;
+ env->fptags[6] = 1;
+ env->fptags[7] = 1;
+}
+
+void OPPROTO op_fnstenv_A0(void)
+{
+ helper_fstenv((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_fldenv_A0(void)
+{
+ helper_fldenv((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_fnsave_A0(void)
+{
+ helper_fsave((uint8_t *)A0, PARAM1);
+}
+
+void OPPROTO op_frstor_A0(void)
+{
+ helper_frstor((uint8_t *)A0, PARAM1);
+}
+
+/* threading support */
+void OPPROTO op_lock(void)
+{
+ cpu_lock();
+}
+
+void OPPROTO op_unlock(void)
+{
+ cpu_unlock();
+}
+
diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h
new file mode 100644
index 0000000000..f35a1bbc95
--- /dev/null
+++ b/target-i386/opreg_template.h
@@ -0,0 +1,134 @@
+/*
+ * i386 micro operations (templates for various register related
+ * operations)
+ *
+ * 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
+ */
+void OPPROTO glue(op_movl_A0,REGNAME)(void)
+{
+ A0 = REG;
+}
+
+void OPPROTO glue(op_addl_A0,REGNAME)(void)
+{
+ A0 += REG;
+}
+
+void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void)
+{
+ A0 += REG << 1;
+}
+
+void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void)
+{
+ A0 += REG << 2;
+}
+
+void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void)
+{
+ A0 += REG << 3;
+}
+
+void OPPROTO glue(op_movl_T0,REGNAME)(void)
+{
+ T0 = REG;
+}
+
+void OPPROTO glue(op_movl_T1,REGNAME)(void)
+{
+ T1 = REG;
+}
+
+void OPPROTO glue(op_movh_T0,REGNAME)(void)
+{
+ T0 = REG >> 8;
+}
+
+void OPPROTO glue(op_movh_T1,REGNAME)(void)
+{
+ T1 = REG >> 8;
+}
+
+void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void)
+{
+ REG = T0;
+}
+
+void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void)
+{
+ REG = T1;
+}
+
+void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void)
+{
+ REG = A0;
+}
+
+/* mov T1 to REG if T0 is true */
+void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
+{
+ if (T0)
+ REG = (REG & 0xffff0000) | (T1 & 0xffff);
+}
+
+void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
+{
+ if (T0)
+ REG = T1;
+}
+
+/* NOTE: T0 high order bits are ignored */
+void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
+{
+ REG = (REG & 0xffff0000) | (T0 & 0xffff);
+}
+
+/* NOTE: T0 high order bits are ignored */
+void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
+{
+ REG = (REG & 0xffff0000) | (T1 & 0xffff);
+}
+
+/* NOTE: A0 high order bits are ignored */
+void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void)
+{
+ REG = (REG & 0xffff0000) | (A0 & 0xffff);
+}
+
+/* NOTE: T0 high order bits are ignored */
+void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void)
+{
+ REG = (REG & 0xffffff00) | (T0 & 0xff);
+}
+
+/* NOTE: T0 high order bits are ignored */
+void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void)
+{
+ REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8);
+}
+
+/* NOTE: T1 high order bits are ignored */
+void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void)
+{
+ REG = (REG & 0xffffff00) | (T1 & 0xff);
+}
+
+/* NOTE: T1 high order bits are ignored */
+void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void)
+{
+ REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8);
+}
diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h
new file mode 100644
index 0000000000..e1c8277bbc
--- /dev/null
+++ b/target-i386/ops_mem.h
@@ -0,0 +1,66 @@
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void)
+{
+ T0 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldub, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldsb, MEMSUFFIX)((int8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(lduw, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldsw, MEMSUFFIX)((int8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
+{
+ T1 = glue(ldl, MEMSUFFIX)((uint8_t *)A0);
+}
+
+void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
+{
+ glue(stb, MEMSUFFIX)((uint8_t *)A0, T0);
+}
+
+void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
+{
+ glue(stw, MEMSUFFIX)((uint8_t *)A0, T0);
+}
+
+void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void)
+{
+ glue(stl, MEMSUFFIX)((uint8_t *)A0, T0);
+}
+
+#undef MEMSUFFIX
diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h
new file mode 100644
index 0000000000..182296743b
--- /dev/null
+++ b/target-i386/ops_template.h
@@ -0,0 +1,617 @@
+/*
+ * i386 micro operations (included several times to generate
+ * different operand sizes)
+ *
+ * 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
+ */
+#define DATA_BITS (1 << (3 + SHIFT))
+#define SHIFT_MASK (DATA_BITS - 1)
+#define SIGN_MASK (1 << (DATA_BITS - 1))
+
+#if DATA_BITS == 8
+#define SUFFIX b
+#define DATA_TYPE uint8_t
+#define DATA_STYPE int8_t
+#define DATA_MASK 0xff
+#elif DATA_BITS == 16
+#define SUFFIX w
+#define DATA_TYPE uint16_t
+#define DATA_STYPE int16_t
+#define DATA_MASK 0xffff
+#elif DATA_BITS == 32
+#define SUFFIX l
+#define DATA_TYPE uint32_t
+#define DATA_STYPE int32_t
+#define DATA_MASK 0xffffffff
+#else
+#error unhandled operand size
+#endif
+
+/* dynamic flags computation */
+
+static int glue(compute_all_add, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_SRC;
+ src2 = CC_DST - CC_SRC;
+ cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_add, SUFFIX)(void)
+{
+ int src1, cf;
+ src1 = CC_SRC;
+ cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
+ return cf;
+}
+
+static int glue(compute_all_adc, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_SRC;
+ src2 = CC_DST - CC_SRC - 1;
+ cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_adc, SUFFIX)(void)
+{
+ int src1, cf;
+ src1 = CC_SRC;
+ cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+ return cf;
+}
+
+static int glue(compute_all_sub, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+ cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_sub, SUFFIX)(void)
+{
+ int src1, src2, cf;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+ cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
+ return cf;
+}
+
+static int glue(compute_all_sbb, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_DST + CC_SRC + 1;
+ src2 = CC_SRC;
+ cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_sbb, SUFFIX)(void)
+{
+ int src1, src2, cf;
+ src1 = CC_DST + CC_SRC + 1;
+ src2 = CC_SRC;
+ cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
+ return cf;
+}
+
+static int glue(compute_all_logic, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ cf = 0;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = 0;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = 0;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_logic, SUFFIX)(void)
+{
+ return 0;
+}
+
+static int glue(compute_all_inc, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_DST - 1;
+ src2 = 1;
+ cf = CC_SRC;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
+ return cf | pf | af | zf | sf | of;
+}
+
+#if DATA_BITS == 32
+static int glue(compute_c_inc, SUFFIX)(void)
+{
+ return CC_SRC;
+}
+#endif
+
+static int glue(compute_all_dec, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ int src1, src2;
+ src1 = CC_DST + 1;
+ src2 = 1;
+ cf = CC_SRC;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = (CC_DST ^ src1 ^ src2) & 0x10;
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_all_shl, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = 0; /* undefined */
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ /* of is defined if shift count == 1 */
+ of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_shl, SUFFIX)(void)
+{
+ return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
+}
+
+#if DATA_BITS == 32
+static int glue(compute_c_sar, SUFFIX)(void)
+{
+ return CC_SRC & 1;
+}
+#endif
+
+static int glue(compute_all_sar, SUFFIX)(void)
+{
+ int cf, pf, af, zf, sf, of;
+ cf = CC_SRC & 1;
+ pf = parity_table[(uint8_t)CC_DST];
+ af = 0; /* undefined */
+ zf = ((DATA_TYPE)CC_DST == 0) << 6;
+ sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+ /* of is defined if shift count == 1 */
+ of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
+ return cf | pf | af | zf | sf | of;
+}
+
+/* various optimized jumps cases */
+
+void OPPROTO glue(op_jb_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
+ JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_jb_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_jz_sub, SUFFIX)(void)
+{
+ if ((DATA_TYPE)CC_DST == 0)
+ JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_jz_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
+ JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_jbe_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_js_sub, SUFFIX)(void)
+{
+ if (CC_DST & SIGN_MASK)
+ JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_js_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_jl_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
+ JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_jl_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_jle_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
+ JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 0, PARAM2);
+ else
+ JUMP_TB(glue(op_jle_sub, SUFFIX), PARAM1, 1, PARAM3);
+ FORCE_RET();
+}
+
+/* oldies */
+
+#if DATA_BITS >= 16
+
+void OPPROTO glue(op_loopnz, SUFFIX)(void)
+{
+ unsigned int tmp;
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ tmp = (ECX - 1) & DATA_MASK;
+ ECX = (ECX & ~DATA_MASK) | tmp;
+ if (tmp != 0 && !(eflags & CC_Z))
+ EIP = PARAM1;
+ else
+ EIP = PARAM2;
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_loopz, SUFFIX)(void)
+{
+ unsigned int tmp;
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ tmp = (ECX - 1) & DATA_MASK;
+ ECX = (ECX & ~DATA_MASK) | tmp;
+ if (tmp != 0 && (eflags & CC_Z))
+ EIP = PARAM1;
+ else
+ EIP = PARAM2;
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_loop, SUFFIX)(void)
+{
+ unsigned int tmp;
+ tmp = (ECX - 1) & DATA_MASK;
+ ECX = (ECX & ~DATA_MASK) | tmp;
+ if (tmp != 0)
+ EIP = PARAM1;
+ else
+ EIP = PARAM2;
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_jecxz, SUFFIX)(void)
+{
+ if ((DATA_TYPE)ECX == 0)
+ EIP = PARAM1;
+ else
+ EIP = PARAM2;
+ FORCE_RET();
+}
+
+#endif
+
+/* various optimized set cases */
+
+void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
+}
+
+void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
+{
+ T0 = ((DATA_TYPE)CC_DST == 0);
+}
+
+void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
+}
+
+void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
+{
+ T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1;
+}
+
+void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
+}
+
+void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
+{
+ int src1, src2;
+ src1 = CC_DST + CC_SRC;
+ src2 = CC_SRC;
+
+ T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
+}
+
+/* shifts */
+
+void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
+{
+ int count;
+ count = T1 & 0x1f;
+ T0 = T0 << count;
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
+{
+ int count;
+ count = T1 & 0x1f;
+ T0 &= DATA_MASK;
+ T0 = T0 >> count;
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
+{
+ int count, src;
+ count = T1 & 0x1f;
+ src = (DATA_STYPE)T0;
+ T0 = src >> count;
+ FORCE_RET();
+}
+
+#undef MEM_WRITE
+#include "ops_template_mem.h"
+
+#define MEM_WRITE
+#include "ops_template_mem.h"
+
+/* bit operations */
+#if DATA_BITS >= 16
+
+void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ CC_SRC = T0 >> count;
+}
+
+void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ T1 = T0 >> count;
+ T0 |= (1 << count);
+}
+
+void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ T1 = T0 >> count;
+ T0 &= ~(1 << count);
+}
+
+void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ T1 = T0 >> count;
+ T0 ^= (1 << count);
+}
+
+void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void)
+{
+ int res, count;
+ res = T0 & DATA_MASK;
+ if (res != 0) {
+ count = 0;
+ while ((res & 1) == 0) {
+ count++;
+ res >>= 1;
+ }
+ T0 = count;
+ CC_DST = 1; /* ZF = 1 */
+ } else {
+ CC_DST = 0; /* ZF = 1 */
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
+{
+ int res, count;
+ res = T0 & DATA_MASK;
+ if (res != 0) {
+ count = DATA_BITS - 1;
+ while ((res & SIGN_MASK) == 0) {
+ count--;
+ res <<= 1;
+ }
+ T0 = count;
+ CC_DST = 1; /* ZF = 1 */
+ } else {
+ CC_DST = 0; /* ZF = 1 */
+ }
+ FORCE_RET();
+}
+
+#endif
+
+#if DATA_BITS == 32
+void OPPROTO op_update_bt_cc(void)
+{
+ CC_SRC = T1;
+}
+#endif
+
+/* string operations */
+
+void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void)
+{
+ T0 = DF << SHIFT;
+}
+
+void OPPROTO glue(op_string_jz_sub, SUFFIX)(void)
+{
+ if ((DATA_TYPE)CC_DST == 0)
+ JUMP_TB2(glue(op_string_jz_sub, SUFFIX), PARAM1, 1);
+ FORCE_RET();
+}
+
+void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void)
+{
+ if ((DATA_TYPE)CC_DST != 0)
+ JUMP_TB2(glue(op_string_jnz_sub, SUFFIX), PARAM1, 1);
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_string_jz_sub, SUFFIX), _im)(void)
+{
+ if ((DATA_TYPE)CC_DST == 0) {
+ EIP = PARAM1;
+ if (env->eflags & TF_MASK) {
+ raise_exception(EXCP01_SSTP);
+ }
+ T0 = 0;
+ EXIT_TB();
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_string_jnz_sub, SUFFIX), _im)(void)
+{
+ if ((DATA_TYPE)CC_DST != 0) {
+ EIP = PARAM1;
+ if (env->eflags & TF_MASK) {
+ raise_exception(EXCP01_SSTP);
+ }
+ T0 = 0;
+ EXIT_TB();
+ }
+ FORCE_RET();
+}
+
+#if DATA_BITS >= 16
+void OPPROTO glue(op_jz_ecx, SUFFIX)(void)
+{
+ if ((DATA_TYPE)ECX == 0)
+ JUMP_TB(glue(op_jz_ecx, SUFFIX), PARAM1, 1, PARAM2);
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_jz_ecx, SUFFIX), _im)(void)
+{
+ if ((DATA_TYPE)ECX == 0) {
+ EIP = PARAM1;
+ if (env->eflags & TF_MASK) {
+ raise_exception(EXCP01_SSTP);
+ }
+ T0 = 0;
+ EXIT_TB();
+ }
+ FORCE_RET();
+}
+#endif
+
+/* port I/O */
+
+void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
+{
+ glue(cpu_x86_out, SUFFIX)(env, T0 & 0xffff, T1 & DATA_MASK);
+}
+
+void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
+{
+ T1 = glue(cpu_x86_in, SUFFIX)(env, T0 & 0xffff);
+}
+
+void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void)
+{
+ T0 = glue(cpu_x86_in, SUFFIX)(env, EDX & 0xffff);
+}
+
+void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void)
+{
+ glue(cpu_x86_out, SUFFIX)(env, EDX & 0xffff, T0);
+}
+
+#undef DATA_BITS
+#undef SHIFT_MASK
+#undef SIGN_MASK
+#undef DATA_TYPE
+#undef DATA_STYPE
+#undef DATA_MASK
+#undef SUFFIX
diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h
new file mode 100644
index 0000000000..eacaabba5c
--- /dev/null
+++ b/target-i386/ops_template_mem.h
@@ -0,0 +1,429 @@
+/*
+ * i386 micro operations (included several times to generate
+ * different operand sizes)
+ *
+ * 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
+ */
+#ifdef MEM_WRITE
+
+#if DATA_BITS == 8
+#define MEM_SUFFIX b_mem
+#elif DATA_BITS == 16
+#define MEM_SUFFIX w_mem
+#elif DATA_BITS == 32
+#define MEM_SUFFIX l_mem
+#endif
+
+#else
+
+#define MEM_SUFFIX SUFFIX
+
+#endif
+
+void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, src;
+ count = T1 & SHIFT_MASK;
+ if (count) {
+ src = T0;
+ T0 &= DATA_MASK;
+ T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#else
+ /* gcc 3.2 workaround. This is really a bug in gcc. */
+ asm volatile("" : : "r" (T0));
+#endif
+ CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
+ (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
+ (T0 & CC_C);
+ CC_OP = CC_OP_EFLAGS;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, src;
+ count = T1 & SHIFT_MASK;
+ if (count) {
+ src = T0;
+ T0 &= DATA_MASK;
+ T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#else
+ /* gcc 3.2 workaround. This is really a bug in gcc. */
+ asm volatile("" : : "r" (T0));
+#endif
+ CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
+ (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
+ ((T0 >> (DATA_BITS - 1)) & CC_C);
+ CC_OP = CC_OP_EFLAGS;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ if (count) {
+ T0 &= DATA_MASK;
+ T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
+{
+ int count;
+ count = T1 & SHIFT_MASK;
+ if (count) {
+ T0 &= DATA_MASK;
+ T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, res, eflags;
+ unsigned int src;
+
+ count = T1 & 0x1f;
+#if DATA_BITS == 16
+ count = rclw_table[count];
+#elif DATA_BITS == 8
+ count = rclb_table[count];
+#endif
+ if (count) {
+ eflags = cc_table[CC_OP].compute_all();
+ T0 &= DATA_MASK;
+ src = T0;
+ res = (T0 << count) | ((eflags & CC_C) << (count - 1));
+ if (count > 1)
+ res |= T0 >> (DATA_BITS + 1 - count);
+ T0 = res;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = (eflags & ~(CC_C | CC_O)) |
+ (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
+ ((src >> (DATA_BITS - count)) & CC_C);
+ CC_OP = CC_OP_EFLAGS;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, res, eflags;
+ unsigned int src;
+
+ count = T1 & 0x1f;
+#if DATA_BITS == 16
+ count = rclw_table[count];
+#elif DATA_BITS == 8
+ count = rclb_table[count];
+#endif
+ if (count) {
+ eflags = cc_table[CC_OP].compute_all();
+ T0 &= DATA_MASK;
+ src = T0;
+ res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
+ if (count > 1)
+ res |= T0 << (DATA_BITS + 1 - count);
+ T0 = res;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = (eflags & ~(CC_C | CC_O)) |
+ (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
+ ((src >> (count - 1)) & CC_C);
+ CC_OP = CC_OP_EFLAGS;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, src;
+ count = T1 & 0x1f;
+ if (count) {
+ src = (DATA_TYPE)T0 << (count - 1);
+ T0 = T0 << count;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = src;
+ CC_DST = T0;
+ CC_OP = CC_OP_SHLB + SHIFT;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, src;
+ count = T1 & 0x1f;
+ if (count) {
+ T0 &= DATA_MASK;
+ src = T0 >> (count - 1);
+ T0 = T0 >> count;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = src;
+ CC_DST = T0;
+ CC_OP = CC_OP_SARB + SHIFT;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int count, src;
+ count = T1 & 0x1f;
+ if (count) {
+ src = (DATA_STYPE)T0;
+ T0 = src >> count;
+ src = src >> (count - 1);
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = src;
+ CC_DST = T0;
+ CC_OP = CC_OP_SARB + SHIFT;
+ }
+ FORCE_RET();
+}
+
+#if DATA_BITS == 16
+/* XXX: overflow flag might be incorrect in some cases in shldw */
+void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
+{
+ int count;
+ unsigned int res, tmp;
+ count = PARAM1;
+ T1 &= 0xffff;
+ res = T1 | (T0 << 16);
+ tmp = res >> (32 - count);
+ res <<= count;
+ if (count > 16)
+ res |= T1 << (count - 16);
+ T0 = res >> 16;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+}
+
+void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
+{
+ int count;
+ unsigned int res, tmp;
+ count = ECX & 0x1f;
+ if (count) {
+ T1 &= 0xffff;
+ res = T1 | (T0 << 16);
+ tmp = res >> (32 - count);
+ res <<= count;
+ if (count > 16)
+ res |= T1 << (count - 16);
+ T0 = res >> 16;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+ CC_OP = CC_OP_SARB + SHIFT;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
+{
+ int count;
+ unsigned int res, tmp;
+
+ count = PARAM1;
+ res = (T0 & 0xffff) | (T1 << 16);
+ tmp = res >> (count - 1);
+ res >>= count;
+ if (count > 16)
+ res |= T1 << (32 - count);
+ T0 = res;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+}
+
+
+void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
+{
+ int count;
+ unsigned int res, tmp;
+
+ count = ECX & 0x1f;
+ if (count) {
+ res = (T0 & 0xffff) | (T1 << 16);
+ tmp = res >> (count - 1);
+ res >>= count;
+ if (count > 16)
+ res |= T1 << (32 - count);
+ T0 = res;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+ CC_OP = CC_OP_SARB + SHIFT;
+ }
+ FORCE_RET();
+}
+#endif
+
+#if DATA_BITS == 32
+void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
+{
+ int count, tmp;
+ count = PARAM1;
+ T0 &= DATA_MASK;
+ T1 &= DATA_MASK;
+ tmp = T0 << (count - 1);
+ T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+}
+
+void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
+{
+ int count, tmp;
+ count = ECX & 0x1f;
+ if (count) {
+ T0 &= DATA_MASK;
+ T1 &= DATA_MASK;
+ tmp = T0 << (count - 1);
+ T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+ CC_OP = CC_OP_SHLB + SHIFT;
+ }
+ FORCE_RET();
+}
+
+void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
+{
+ int count, tmp;
+ count = PARAM1;
+ T0 &= DATA_MASK;
+ T1 &= DATA_MASK;
+ tmp = T0 >> (count - 1);
+ T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+}
+
+
+void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
+{
+ int count, tmp;
+ count = ECX & 0x1f;
+ if (count) {
+ T0 &= DATA_MASK;
+ T1 &= DATA_MASK;
+ tmp = T0 >> (count - 1);
+ T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = tmp;
+ CC_DST = T0;
+ CC_OP = CC_OP_SARB + SHIFT;
+ }
+ FORCE_RET();
+}
+#endif
+
+/* carry add/sub (we only need to set CC_OP differently) */
+
+void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int cf;
+ cf = cc_table[CC_OP].compute_c();
+ T0 = T0 + T1 + cf;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = T1;
+ CC_DST = T0;
+ CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
+}
+
+void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
+{
+ int cf;
+ cf = cc_table[CC_OP].compute_c();
+ T0 = T0 - T1 - cf;
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = T1;
+ CC_DST = T0;
+ CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
+}
+
+void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
+{
+ unsigned int src, dst;
+
+ src = T0;
+ dst = EAX - T0;
+ if ((DATA_TYPE)dst == 0) {
+ T0 = T1;
+ } else {
+ EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
+ }
+#ifdef MEM_WRITE
+ glue(st, SUFFIX)((uint8_t *)A0, T0);
+#endif
+ CC_SRC = src;
+ CC_DST = dst;
+ FORCE_RET();
+}
+
+#undef MEM_SUFFIX
+#undef MEM_WRITE
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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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);
+}
+