diff options
-rw-r--r-- | cpu-all.h | 12 | ||||
-rw-r--r-- | cpu-arm.h | 4 | ||||
-rw-r--r-- | cpu-i386.h | 20 | ||||
-rw-r--r-- | exec-i386.h | 50 | ||||
-rw-r--r-- | exec.c | 138 | ||||
-rw-r--r-- | exec.h | 43 | ||||
-rw-r--r-- | helper-i386.c | 33 | ||||
-rw-r--r-- | op-i386.c | 100 | ||||
-rw-r--r-- | op_string.h | 150 | ||||
-rw-r--r-- | ops_template.h | 35 |
10 files changed, 351 insertions, 234 deletions
@@ -140,6 +140,7 @@ static inline void stfl(void *ptr, float v) stl(ptr, u.i); } + #if defined(__arm__) && !defined(WORDS_BIGENDIAN) /* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ @@ -317,6 +318,17 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); void cpu_single_step(CPUState *env, int enabled); +/* memory API */ + +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value); +typedef uint32_t CPUReadMemoryFunc(uint32_t addr); + +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, + long phys_offset); +int cpu_register_io_memory(int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write); + /* gdb stub API */ extern int gdbstub_fd; CPUState *cpu_gdbstub_get_env(void *opaque); @@ -20,12 +20,10 @@ #ifndef CPU_ARM_H #define CPU_ARM_H -#include "config.h" -#include <setjmp.h> +#include "cpu-defs.h" #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ -#define EXCP_INTERRUPT 256 /* async interruption */ typedef struct CPUARMState { uint32_t regs[16]; diff --git a/cpu-i386.h b/cpu-i386.h index 879ab1eb8f..a60e959150 100644 --- a/cpu-i386.h +++ b/cpu-i386.h @@ -20,8 +20,7 @@ #ifndef CPU_I386_H #define CPU_I386_H -#include "config.h" -#include <setjmp.h> +#include "cpu-defs.h" #define R_EAX 0 #define R_ECX 1 @@ -153,12 +152,6 @@ #define EXCP11_ALGN 17 #define EXCP12_MCHK 18 -#define EXCP_INTERRUPT 256 /* async interruption */ -#define EXCP_HLT 257 /* hlt instruction reached */ -#define EXCP_DEBUG 258 /* cpu stopped after a breakpoint or singlestep */ - -#define MAX_BREAKPOINTS 32 - enum { CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ @@ -257,7 +250,8 @@ typedef struct CPUX86State { SegmentCache gdt; /* only base and limit are used */ SegmentCache idt; /* only base and limit are used */ int cpl; /* current cpl */ - + int soft_mmu; /* TRUE if soft mmu is being used */ + /* sysenter registers */ uint32_t sysenter_cs; uint32_t sysenter_esp; @@ -275,10 +269,16 @@ typedef struct CPUX86State { 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; diff --git a/exec-i386.h b/exec-i386.h index 964abddfa2..03a547fb18 100644 --- a/exec-i386.h +++ b/exec-i386.h @@ -138,6 +138,7 @@ 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, @@ -364,3 +365,52 @@ static inline void load_eflags(int eflags, int update_mask) 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 + @@ -68,6 +68,7 @@ typedef struct PageDesc { #define L2_SIZE (1 << L2_BITS) static void tb_invalidate_page(unsigned long address); +static void io_mem_init(void); unsigned long real_host_page_size; unsigned long host_page_bits; @@ -76,6 +77,12 @@ unsigned long host_page_mask; static PageDesc *l1_map[L1_SIZE]; +/* io memory support */ +static unsigned long *l1_physmap[L1_SIZE]; +CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; +static int io_mem_nb; + static void page_init(void) { /* NOTE: we can always suppose that host_page_size >= @@ -201,6 +208,7 @@ void cpu_exec_init(void) if (!code_gen_ptr) { code_gen_ptr = code_gen_buffer; page_init(); + io_mem_init(); } } @@ -744,3 +752,133 @@ void page_unmap(void) tb_flush(); } #endif + +void tlb_flush(CPUState *env) +{ +#if defined(TARGET_I386) + int i; + for(i = 0; i < CPU_TLB_SIZE; i++) { + env->tlb_read[0][i].address = -1; + env->tlb_write[0][i].address = -1; + env->tlb_read[1][i].address = -1; + env->tlb_write[1][i].address = -1; + } +#endif +} + +void tlb_flush_page(CPUState *env, uint32_t addr) +{ +#if defined(TARGET_I386) + int i; + + i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + env->tlb_read[0][i].address = -1; + env->tlb_write[0][i].address = -1; + env->tlb_read[1][i].address = -1; + env->tlb_write[1][i].address = -1; +#endif +} + +static inline unsigned long *physpage_find_alloc(unsigned int page) +{ + unsigned long **lp, *p; + unsigned int index, i; + + index = page >> TARGET_PAGE_BITS; + lp = &l1_physmap[index >> L2_BITS]; + p = *lp; + if (!p) { + /* allocate if not found */ + p = malloc(sizeof(unsigned long) * L2_SIZE); + for(i = 0; i < L2_SIZE; i++) + p[i] = IO_MEM_UNASSIGNED; + *lp = p; + } + return p + (index & (L2_SIZE - 1)); +} + +/* return NULL if no page defined (unused memory) */ +unsigned long physpage_find(unsigned long page) +{ + unsigned long *p; + unsigned int index; + index = page >> TARGET_PAGE_BITS; + p = l1_physmap[index >> L2_BITS]; + if (!p) + return IO_MEM_UNASSIGNED; + return p[index & (L2_SIZE - 1)]; +} + +/* register physical memory. 'size' must be a multiple of the target + page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an + io memory page */ +void cpu_register_physical_memory(unsigned long start_addr, unsigned long size, + long phys_offset) +{ + unsigned long addr, end_addr; + unsigned long *p; + + end_addr = start_addr + size; + for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) { + p = physpage_find_alloc(addr); + *p = phys_offset; + if ((phys_offset & ~TARGET_PAGE_MASK) == 0) + phys_offset += TARGET_PAGE_SIZE; + } +} + +static uint32_t unassigned_mem_readb(uint32_t addr) +{ + return 0; +} + +static void unassigned_mem_writeb(uint32_t addr, uint32_t val) +{ +} + +static CPUReadMemoryFunc *unassigned_mem_read[3] = { + unassigned_mem_readb, + unassigned_mem_readb, + unassigned_mem_readb, +}; + +static CPUWriteMemoryFunc *unassigned_mem_write[3] = { + unassigned_mem_writeb, + unassigned_mem_writeb, + unassigned_mem_writeb, +}; + + +static void io_mem_init(void) +{ + io_mem_nb = 1; + cpu_register_io_memory(0, unassigned_mem_read, unassigned_mem_write); +} + +/* mem_read and mem_write are arrays of functions containing the + function to access byte (index 0), word (index 1) and dword (index + 2). All functions must be supplied. If io_index is non zero, the + corresponding io zone is modified. If it is zero, a new io zone is + allocated. The return value can be used with + cpu_register_physical_memory(). (-1) is returned if error. */ +int cpu_register_io_memory(int io_index, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write) +{ + int i; + + if (io_index <= 0) { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + io_index = io_mem_nb++; + } else { + if (io_index >= IO_MEM_NB_ENTRIES) + return -1; + } + + for(i = 0;i < 3; i++) { + io_mem_read[io_index][i] = mem_read[i]; + io_mem_write[io_index][i] = mem_write[i]; + } + return io_index << IO_MEM_SHIFT; +} @@ -21,6 +21,17 @@ /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS +#ifndef glue +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) +#define stringify(s) tostring(s) +#define tostring(s) #s +#endif + +#if GCC_MAJOR < 3 +#define __builtin_expect(x, n) (x) +#endif + /* is_jmp field values */ #define DISAS_NEXT 0 /* next instruction can be analyzed */ #define DISAS_JUMP 1 /* only pc was modified dynamically */ @@ -44,14 +55,17 @@ extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; #if defined(TARGET_I386) -#define GEN_FLAG_CODE32_SHIFT 0 -#define GEN_FLAG_ADDSEG_SHIFT 1 -#define GEN_FLAG_SS32_SHIFT 2 -#define GEN_FLAG_VM_SHIFT 3 -#define GEN_FLAG_ST_SHIFT 4 -#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ -#define GEN_FLAG_CPL_SHIFT 9 -#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ +#define GEN_FLAG_CODE32_SHIFT 0 +#define GEN_FLAG_ADDSEG_SHIFT 1 +#define GEN_FLAG_SS32_SHIFT 2 +#define GEN_FLAG_VM_SHIFT 3 +#define GEN_FLAG_ST_SHIFT 4 +#define GEN_FLAG_TF_SHIFT 8 /* same position as eflags */ +#define GEN_FLAG_CPL_SHIFT 9 +#define GEN_FLAG_SOFT_MMU_SHIFT 11 +#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ + +void optimize_flags_init(void); #endif @@ -68,6 +82,8 @@ int cpu_restore_state(struct TranslationBlock *tb, void cpu_exec_init(void); int page_unprotect(unsigned long address); void page_unmap(void); +void tlb_flush_page(CPUState *env, uint32_t addr); +void tlb_flush(CPUState *env); #define CODE_GEN_MAX_SIZE 65536 #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -230,6 +246,17 @@ dummy_label ## n:\ #endif +/* physical memory access */ +#define IO_MEM_NB_ENTRIES 256 +#define TLB_INVALID_MASK (1 << 3) +#define IO_MEM_SHIFT 4 +#define IO_MEM_UNASSIGNED (1 << IO_MEM_SHIFT) + +unsigned long physpage_find(unsigned long page); + +extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; +extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; + #ifdef __powerpc__ static inline int testandset (int *p) { diff --git a/helper-i386.c b/helper-i386.c index 0003fb46a1..01046ea091 100644 --- a/helper-i386.c +++ b/helper-i386.c @@ -781,7 +781,7 @@ 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 = env->regs[R_ESP]; @@ -1741,3 +1741,34 @@ void helper_frstor(uint8_t *ptr, int data32) } } +#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); + } +} @@ -376,70 +376,14 @@ void OPPROTO op_andl_A0_ffff(void) /* memory access */ -void OPPROTO op_ldub_T0_A0(void) -{ - T0 = ldub((uint8_t *)A0); -} - -void OPPROTO op_ldsb_T0_A0(void) -{ - T0 = ldsb((int8_t *)A0); -} - -void OPPROTO op_lduw_T0_A0(void) -{ - T0 = lduw((uint8_t *)A0); -} - -void OPPROTO op_ldsw_T0_A0(void) -{ - T0 = ldsw((int8_t *)A0); -} - -void OPPROTO op_ldl_T0_A0(void) -{ - T0 = ldl((uint8_t *)A0); -} +#define MEMSUFFIX +#include "ops_mem.h" -void OPPROTO op_ldub_T1_A0(void) -{ - T1 = ldub((uint8_t *)A0); -} - -void OPPROTO op_ldsb_T1_A0(void) -{ - T1 = ldsb((int8_t *)A0); -} - -void OPPROTO op_lduw_T1_A0(void) -{ - T1 = lduw((uint8_t *)A0); -} +#define MEMSUFFIX _user +#include "ops_mem.h" -void OPPROTO op_ldsw_T1_A0(void) -{ - T1 = ldsw((int8_t *)A0); -} - -void OPPROTO op_ldl_T1_A0(void) -{ - T1 = ldl((uint8_t *)A0); -} - -void OPPROTO op_stb_T0_A0(void) -{ - stb((uint8_t *)A0, T0); -} - -void OPPROTO op_stw_T0_A0(void) -{ - stw((uint8_t *)A0, T0); -} - -void OPPROTO op_stl_T0_A0(void) -{ - stl((uint8_t *)A0, T0); -} +#define MEMSUFFIX _kernel +#include "ops_mem.h" /* used for bit operations */ @@ -635,6 +579,38 @@ 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) diff --git a/op_string.h b/op_string.h index 79bc11e1a7..66b598b23a 100644 --- a/op_string.h +++ b/op_string.h @@ -1,94 +1,4 @@ -void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(st, SUFFIX)(DI_ADDR, v); - inc = (DF << SHIFT); - INC_SI(); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_movs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(st, SUFFIX)(DI_ADDR, v); - INC_SI(); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_stos, SUFFIX), STRING_SUFFIX)(void) -{ - int inc; - glue(st, SUFFIX)(DI_ADDR, EAX); - inc = (DF << SHIFT); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_stos, SUFFIX), STRING_SUFFIX)(void) -{ - int inc; - inc = (DF << SHIFT); - while (CX != 0) { - glue(st, SUFFIX)(DI_ADDR, EAX); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_lods, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - v = glue(ldu, SUFFIX)(SI_ADDR); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - inc = (DF << SHIFT); - INC_SI(); -} - -/* don't know if it is used */ -void OPPROTO glue(glue(op_rep_lods, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - inc = (DF << SHIFT); - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); -#if SHIFT == 0 - EAX = (EAX & ~0xff) | v; -#elif SHIFT == 1 - EAX = (EAX & ~0xffff) | v; -#else - EAX = v; -#endif - INC_SI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void) -{ - int v, inc; - - v = glue(ldu, SUFFIX)(DI_ADDR); - inc = (DF << SHIFT); - INC_DI(); - CC_SRC = v; - CC_DST = EAX - v; -} - void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void) { int v1, v2, inc; @@ -133,18 +43,6 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void) -{ - int v1, v2, inc; - v1 = glue(ldu, SUFFIX)(SI_ADDR); - v2 = glue(ldu, SUFFIX)(DI_ADDR); - inc = (DF << SHIFT); - INC_SI(); - INC_DI(); - CC_SRC = v2; - CC_DST = v1 - v2; -} - void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void) { int v1, v2, inc; @@ -187,54 +85,6 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void) FORCE_RET(); } -void OPPROTO glue(glue(op_outs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - dx = EDX & 0xffff; - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(env, dx, v); - inc = (DF << SHIFT); - INC_SI(); -} - -void OPPROTO glue(glue(op_rep_outs, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (CX != 0) { - v = glue(ldu, SUFFIX)(SI_ADDR); - glue(cpu_x86_out, SUFFIX)(env, dx, v); - INC_SI(); - DEC_CX(); - } - FORCE_RET(); -} - -void OPPROTO glue(glue(op_ins, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - dx = EDX & 0xffff; - v = glue(cpu_x86_in, SUFFIX)(env, dx); - glue(st, SUFFIX)(DI_ADDR, v); - inc = (DF << SHIFT); - INC_DI(); -} - -void OPPROTO glue(glue(op_rep_ins, SUFFIX), STRING_SUFFIX)(void) -{ - int v, dx, inc; - inc = (DF << SHIFT); - dx = EDX & 0xffff; - while (CX != 0) { - v = glue(cpu_x86_in, SUFFIX)(env, dx); - glue(st, SUFFIX)(DI_ADDR, v); - INC_DI(); - DEC_CX(); - } - FORCE_RET(); -} - #undef STRING_SUFFIX #undef SI_ADDR #undef DI_ADDR diff --git a/ops_template.h b/ops_template.h index 4595291e78..89480dddbf 100644 --- a/ops_template.h +++ b/ops_template.h @@ -547,6 +547,31 @@ void OPPROTO op_update_bt_cc(void) #define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff) #include "op_string.h" +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_TB(PARAM1, 1, PARAM2); +} + +void OPPROTO glue(op_string_jnz_sub, SUFFIX)(void) +{ + if ((DATA_TYPE)CC_DST != 0) + JUMP_TB(PARAM1, 1, PARAM2); +} + +#if DATA_BITS >= 16 +void OPPROTO glue(op_jz_ecx, SUFFIX)(void) +{ + if ((DATA_TYPE)ECX == 0) + JUMP_TB(PARAM1, 1, PARAM2); +} +#endif + /* port I/O */ void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) @@ -559,6 +584,16 @@ 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 |