|
|
1.1 root 1: /*
2: * i386 translation
1.1.1.6 root 3: *
1.1 root 4: * Copyright (c) 2003 Fabrice Bellard
5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, write to the Free Software
1.1.1.7 ! root 18: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
1.1 root 19: */
20: #include <stdarg.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <inttypes.h>
25: #include <signal.h>
26: #include <assert.h>
27:
28: #include "cpu.h"
29: #include "exec-all.h"
30: #include "disas.h"
1.1.1.7 ! root 31: #include "tcg-op.h"
1.1 root 32:
1.1.1.7 ! root 33: #include "helper.h"
! 34: #define GEN_HELPER 1
! 35: #include "helper.h"
1.1 root 36:
37: #define PREFIX_REPZ 0x01
38: #define PREFIX_REPNZ 0x02
39: #define PREFIX_LOCK 0x04
40: #define PREFIX_DATA 0x08
41: #define PREFIX_ADR 0x10
42:
43: #ifdef TARGET_X86_64
44: #define X86_64_ONLY(x) x
45: #define X86_64_DEF(x...) x
46: #define CODE64(s) ((s)->code64)
47: #define REX_X(s) ((s)->rex_x)
48: #define REX_B(s) ((s)->rex_b)
49: /* XXX: gcc generates push/pop in some opcodes, so we cannot use them */
50: #if 1
51: #define BUGGY_64(x) NULL
52: #endif
53: #else
54: #define X86_64_ONLY(x) NULL
55: #define X86_64_DEF(x...)
56: #define CODE64(s) 0
57: #define REX_X(s) 0
58: #define REX_B(s) 0
59: #endif
60:
1.1.1.7 ! root 61: //#define MACRO_TEST 1
! 62:
! 63: /* global register indexes */
! 64: static TCGv_ptr cpu_env;
! 65: static TCGv cpu_A0, cpu_cc_src, cpu_cc_dst, cpu_cc_tmp;
! 66: static TCGv_i32 cpu_cc_op;
! 67: /* local temps */
! 68: static TCGv cpu_T[2], cpu_T3;
! 69: /* local register indexes (only used inside old micro ops) */
! 70: static TCGv cpu_tmp0, cpu_tmp4;
! 71: static TCGv_ptr cpu_ptr0, cpu_ptr1;
! 72: static TCGv_i32 cpu_tmp2_i32, cpu_tmp3_i32;
! 73: static TCGv_i64 cpu_tmp1_i64;
! 74: static TCGv cpu_tmp5, cpu_tmp6;
! 75:
! 76: #include "gen-icount.h"
! 77:
1.1 root 78: #ifdef TARGET_X86_64
79: static int x86_64_hregs;
80: #endif
81:
82: typedef struct DisasContext {
83: /* current insn context */
84: int override; /* -1 if no override */
85: int prefix;
86: int aflag, dflag;
87: target_ulong pc; /* pc = eip + cs_base */
88: int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
89: static state change (stop translation) */
90: /* current block context */
91: target_ulong cs_base; /* base of CS segment */
92: int pe; /* protected mode */
93: int code32; /* 32 bit code segment */
94: #ifdef TARGET_X86_64
95: int lma; /* long mode active */
96: int code64; /* 64 bit code segment */
97: int rex_x, rex_b;
98: #endif
99: int ss32; /* 32 bit stack segment */
100: int cc_op; /* current CC operation */
101: int addseg; /* non zero if either DS/ES/SS have a non zero base */
102: int f_st; /* currently unused */
103: int vm86; /* vm86 mode */
104: int cpl;
105: int iopl;
106: int tf; /* TF cpu flag */
107: int singlestep_enabled; /* "hardware" single step enabled */
108: int jmp_opt; /* use direct block chaining for direct jumps */
109: int mem_index; /* select memory access functions */
1.1.1.6 root 110: uint64_t flags; /* all execution flags */
1.1 root 111: struct TranslationBlock *tb;
112: int popl_esp_hack; /* for correct popl with esp base handling */
113: int rip_offset; /* only used in x86_64, but left for simplicity */
114: int cpuid_features;
1.1.1.4 root 115: int cpuid_ext_features;
1.1.1.7 ! root 116: int cpuid_ext2_features;
! 117: int cpuid_ext3_features;
1.1 root 118: } DisasContext;
119:
120: static void gen_eob(DisasContext *s);
121: static void gen_jmp(DisasContext *s, target_ulong eip);
122: static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
123:
124: /* i386 arith/logic operations */
125: enum {
1.1.1.6 root 126: OP_ADDL,
127: OP_ORL,
128: OP_ADCL,
1.1 root 129: OP_SBBL,
1.1.1.6 root 130: OP_ANDL,
131: OP_SUBL,
132: OP_XORL,
1.1 root 133: OP_CMPL,
134: };
135:
136: /* i386 shift ops */
137: enum {
1.1.1.6 root 138: OP_ROL,
139: OP_ROR,
140: OP_RCL,
141: OP_RCR,
142: OP_SHL,
143: OP_SHR,
1.1 root 144: OP_SHL1, /* undocumented */
145: OP_SAR = 7,
146: };
147:
148: enum {
1.1.1.7 ! root 149: JCC_O,
! 150: JCC_B,
! 151: JCC_Z,
! 152: JCC_BE,
! 153: JCC_S,
! 154: JCC_P,
! 155: JCC_L,
! 156: JCC_LE,
1.1 root 157: };
158:
159: /* operand size */
160: enum {
161: OT_BYTE = 0,
162: OT_WORD,
1.1.1.6 root 163: OT_LONG,
1.1 root 164: OT_QUAD,
165: };
166:
167: enum {
168: /* I386 int registers */
169: OR_EAX, /* MUST be even numbered */
170: OR_ECX,
171: OR_EDX,
172: OR_EBX,
173: OR_ESP,
174: OR_EBP,
175: OR_ESI,
176: OR_EDI,
177:
178: OR_TMP0 = 16, /* temporary operand register */
179: OR_TMP1,
180: OR_A0, /* temporary register used when doing address evaluation */
181: };
182:
1.1.1.7 ! root 183: static inline void gen_op_movl_T0_0(void)
! 184: {
! 185: tcg_gen_movi_tl(cpu_T[0], 0);
! 186: }
! 187:
! 188: static inline void gen_op_movl_T0_im(int32_t val)
! 189: {
! 190: tcg_gen_movi_tl(cpu_T[0], val);
! 191: }
! 192:
! 193: static inline void gen_op_movl_T0_imu(uint32_t val)
! 194: {
! 195: tcg_gen_movi_tl(cpu_T[0], val);
! 196: }
! 197:
! 198: static inline void gen_op_movl_T1_im(int32_t val)
! 199: {
! 200: tcg_gen_movi_tl(cpu_T[1], val);
! 201: }
! 202:
! 203: static inline void gen_op_movl_T1_imu(uint32_t val)
! 204: {
! 205: tcg_gen_movi_tl(cpu_T[1], val);
! 206: }
! 207:
! 208: static inline void gen_op_movl_A0_im(uint32_t val)
! 209: {
! 210: tcg_gen_movi_tl(cpu_A0, val);
! 211: }
! 212:
1.1 root 213: #ifdef TARGET_X86_64
1.1.1.7 ! root 214: static inline void gen_op_movq_A0_im(int64_t val)
! 215: {
! 216: tcg_gen_movi_tl(cpu_A0, val);
! 217: }
! 218: #endif
1.1 root 219:
1.1.1.7 ! root 220: static inline void gen_movtl_T0_im(target_ulong val)
! 221: {
! 222: tcg_gen_movi_tl(cpu_T[0], val);
! 223: }
! 224:
! 225: static inline void gen_movtl_T1_im(target_ulong val)
! 226: {
! 227: tcg_gen_movi_tl(cpu_T[1], val);
! 228: }
! 229:
! 230: static inline void gen_op_andl_T0_ffff(void)
! 231: {
! 232: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff);
! 233: }
! 234:
! 235: static inline void gen_op_andl_T0_im(uint32_t val)
! 236: {
! 237: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], val);
! 238: }
1.1 root 239:
1.1.1.7 ! root 240: static inline void gen_op_movl_T0_T1(void)
! 241: {
! 242: tcg_gen_mov_tl(cpu_T[0], cpu_T[1]);
! 243: }
! 244:
! 245: static inline void gen_op_andl_A0_ffff(void)
! 246: {
! 247: tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffff);
! 248: }
! 249:
! 250: #ifdef TARGET_X86_64
! 251:
! 252: #define NB_OP_SIZES 4
1.1 root 253:
254: #else /* !TARGET_X86_64 */
255:
256: #define NB_OP_SIZES 3
257:
258: #endif /* !TARGET_X86_64 */
259:
1.1.1.7 ! root 260: #if defined(WORDS_BIGENDIAN)
! 261: #define REG_B_OFFSET (sizeof(target_ulong) - 1)
! 262: #define REG_H_OFFSET (sizeof(target_ulong) - 2)
! 263: #define REG_W_OFFSET (sizeof(target_ulong) - 2)
! 264: #define REG_L_OFFSET (sizeof(target_ulong) - 4)
! 265: #define REG_LH_OFFSET (sizeof(target_ulong) - 8)
1.1 root 266: #else
1.1.1.7 ! root 267: #define REG_B_OFFSET 0
! 268: #define REG_H_OFFSET 1
! 269: #define REG_W_OFFSET 0
! 270: #define REG_L_OFFSET 0
! 271: #define REG_LH_OFFSET 4
1.1 root 272: #endif
273:
1.1.1.7 ! root 274: static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
! 275: {
! 276: switch(ot) {
! 277: case OT_BYTE:
! 278: if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
! 279: tcg_gen_st8_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_B_OFFSET);
! 280: } else {
! 281: tcg_gen_st8_tl(t0, cpu_env, offsetof(CPUState, regs[reg - 4]) + REG_H_OFFSET);
! 282: }
! 283: break;
! 284: case OT_WORD:
! 285: tcg_gen_st16_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET);
! 286: break;
! 287: #ifdef TARGET_X86_64
! 288: case OT_LONG:
! 289: tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 290: /* high part of register set to zero */
! 291: tcg_gen_movi_tl(cpu_tmp0, 0);
! 292: tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET);
! 293: break;
! 294: default:
! 295: case OT_QUAD:
! 296: tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, regs[reg]));
! 297: break;
1.1 root 298: #else
1.1.1.7 ! root 299: default:
! 300: case OT_LONG:
! 301: tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 302: break;
1.1 root 303: #endif
1.1.1.7 ! root 304: }
! 305: }
1.1 root 306:
1.1.1.7 ! root 307: static inline void gen_op_mov_reg_T0(int ot, int reg)
! 308: {
! 309: gen_op_mov_reg_v(ot, reg, cpu_T[0]);
! 310: }
1.1 root 311:
1.1.1.7 ! root 312: static inline void gen_op_mov_reg_T1(int ot, int reg)
1.1 root 313: {
1.1.1.7 ! root 314: gen_op_mov_reg_v(ot, reg, cpu_T[1]);
! 315: }
! 316:
! 317: static inline void gen_op_mov_reg_A0(int size, int reg)
! 318: {
! 319: switch(size) {
! 320: case 0:
! 321: tcg_gen_st16_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET);
! 322: break;
1.1 root 323: #ifdef TARGET_X86_64
1.1.1.7 ! root 324: case 1:
! 325: tcg_gen_st32_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 326: /* high part of register set to zero */
! 327: tcg_gen_movi_tl(cpu_tmp0, 0);
! 328: tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET);
! 329: break;
! 330: default:
! 331: case 2:
! 332: tcg_gen_st_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]));
! 333: break;
! 334: #else
! 335: default:
! 336: case 1:
! 337: tcg_gen_st32_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 338: break;
1.1 root 339: #endif
1.1.1.7 ! root 340: }
! 341: }
1.1 root 342:
1.1.1.7 ! root 343: static inline void gen_op_mov_v_reg(int ot, TCGv t0, int reg)
! 344: {
! 345: switch(ot) {
! 346: case OT_BYTE:
! 347: if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
! 348: goto std_case;
! 349: } else {
! 350: tcg_gen_ld8u_tl(t0, cpu_env, offsetof(CPUState, regs[reg - 4]) + REG_H_OFFSET);
! 351: }
! 352: break;
! 353: default:
! 354: std_case:
! 355: tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, regs[reg]));
! 356: break;
! 357: }
! 358: }
1.1 root 359:
1.1.1.7 ! root 360: static inline void gen_op_mov_TN_reg(int ot, int t_index, int reg)
! 361: {
! 362: gen_op_mov_v_reg(ot, cpu_T[t_index], reg);
! 363: }
1.1 root 364:
1.1.1.7 ! root 365: static inline void gen_op_movl_A0_reg(int reg)
! 366: {
! 367: tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 368: }
1.1 root 369:
1.1.1.7 ! root 370: static inline void gen_op_addl_A0_im(int32_t val)
! 371: {
! 372: tcg_gen_addi_tl(cpu_A0, cpu_A0, val);
! 373: #ifdef TARGET_X86_64
! 374: tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
1.1 root 375: #endif
1.1.1.7 ! root 376: }
1.1 root 377:
1.1.1.7 ! root 378: #ifdef TARGET_X86_64
! 379: static inline void gen_op_addq_A0_im(int64_t val)
! 380: {
! 381: tcg_gen_addi_tl(cpu_A0, cpu_A0, val);
! 382: }
1.1 root 383: #endif
1.1.1.7 ! root 384:
! 385: static void gen_add_A0_im(DisasContext *s, int val)
! 386: {
! 387: #ifdef TARGET_X86_64
! 388: if (CODE64(s))
! 389: gen_op_addq_A0_im(val);
! 390: else
1.1 root 391: #endif
1.1.1.7 ! root 392: gen_op_addl_A0_im(val);
! 393: }
1.1 root 394:
1.1.1.7 ! root 395: static inline void gen_op_addl_T0_T1(void)
! 396: {
! 397: tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 398: }
1.1 root 399:
1.1.1.7 ! root 400: static inline void gen_op_jmp_T0(void)
! 401: {
! 402: tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUState, eip));
! 403: }
1.1 root 404:
1.1.1.7 ! root 405: static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
! 406: {
! 407: switch(size) {
! 408: case 0:
! 409: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 410: tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val);
! 411: tcg_gen_st16_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET);
! 412: break;
! 413: case 1:
! 414: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 415: tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val);
! 416: #ifdef TARGET_X86_64
! 417: tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffff);
1.1 root 418: #endif
1.1.1.7 ! root 419: tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 420: break;
! 421: #ifdef TARGET_X86_64
! 422: case 2:
! 423: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 424: tcg_gen_addi_tl(cpu_tmp0, cpu_tmp0, val);
! 425: tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 426: break;
! 427: #endif
! 428: }
! 429: }
1.1 root 430:
1.1.1.7 ! root 431: static inline void gen_op_add_reg_T0(int size, int reg)
! 432: {
! 433: switch(size) {
! 434: case 0:
! 435: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 436: tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]);
! 437: tcg_gen_st16_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_W_OFFSET);
! 438: break;
! 439: case 1:
! 440: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 441: tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]);
! 442: #ifdef TARGET_X86_64
! 443: tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, 0xffffffff);
! 444: #endif
! 445: tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 446: break;
! 447: #ifdef TARGET_X86_64
! 448: case 2:
! 449: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 450: tcg_gen_add_tl(cpu_tmp0, cpu_tmp0, cpu_T[0]);
! 451: tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 452: break;
! 453: #endif
! 454: }
! 455: }
1.1 root 456:
1.1.1.7 ! root 457: static inline void gen_op_set_cc_op(int32_t val)
! 458: {
! 459: tcg_gen_movi_i32(cpu_cc_op, val);
! 460: }
1.1 root 461:
1.1.1.7 ! root 462: static inline void gen_op_addl_A0_reg_sN(int shift, int reg)
! 463: {
! 464: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 465: if (shift != 0)
! 466: tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
! 467: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
! 468: #ifdef TARGET_X86_64
! 469: tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
1.1 root 470: #endif
1.1.1.7 ! root 471: }
1.1 root 472:
1.1.1.7 ! root 473: static inline void gen_op_movl_A0_seg(int reg)
! 474: {
! 475: tcg_gen_ld32u_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base) + REG_L_OFFSET);
! 476: }
1.1 root 477:
1.1.1.7 ! root 478: static inline void gen_op_addl_A0_seg(int reg)
! 479: {
! 480: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base));
! 481: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
! 482: #ifdef TARGET_X86_64
! 483: tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
! 484: #endif
! 485: }
1.1 root 486:
1.1.1.7 ! root 487: #ifdef TARGET_X86_64
! 488: static inline void gen_op_movq_A0_seg(int reg)
! 489: {
! 490: tcg_gen_ld_tl(cpu_A0, cpu_env, offsetof(CPUState, segs[reg].base));
! 491: }
1.1 root 492:
1.1.1.7 ! root 493: static inline void gen_op_addq_A0_seg(int reg)
! 494: {
! 495: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, segs[reg].base));
! 496: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
! 497: }
1.1 root 498:
1.1.1.7 ! root 499: static inline void gen_op_movq_A0_reg(int reg)
! 500: {
! 501: tcg_gen_ld_tl(cpu_A0, cpu_env, offsetof(CPUState, regs[reg]));
! 502: }
1.1 root 503:
1.1.1.7 ! root 504: static inline void gen_op_addq_A0_reg_sN(int shift, int reg)
! 505: {
! 506: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]));
! 507: if (shift != 0)
! 508: tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
! 509: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
! 510: }
1.1 root 511: #endif
512:
1.1.1.7 ! root 513: static inline void gen_op_lds_T0_A0(int idx)
! 514: {
! 515: int mem_index = (idx >> 2) - 1;
! 516: switch(idx & 3) {
! 517: case 0:
! 518: tcg_gen_qemu_ld8s(cpu_T[0], cpu_A0, mem_index);
! 519: break;
! 520: case 1:
! 521: tcg_gen_qemu_ld16s(cpu_T[0], cpu_A0, mem_index);
! 522: break;
! 523: default:
! 524: case 2:
! 525: tcg_gen_qemu_ld32s(cpu_T[0], cpu_A0, mem_index);
! 526: break;
! 527: }
! 528: }
1.1 root 529:
1.1.1.7 ! root 530: static inline void gen_op_ld_v(int idx, TCGv t0, TCGv a0)
! 531: {
! 532: int mem_index = (idx >> 2) - 1;
! 533: switch(idx & 3) {
! 534: case 0:
! 535: tcg_gen_qemu_ld8u(t0, a0, mem_index);
! 536: break;
! 537: case 1:
! 538: tcg_gen_qemu_ld16u(t0, a0, mem_index);
! 539: break;
! 540: case 2:
! 541: tcg_gen_qemu_ld32u(t0, a0, mem_index);
! 542: break;
! 543: default:
! 544: case 3:
! 545: /* Should never happen on 32-bit targets. */
! 546: #ifdef TARGET_X86_64
! 547: tcg_gen_qemu_ld64(t0, a0, mem_index);
1.1 root 548: #endif
1.1.1.7 ! root 549: break;
! 550: }
! 551: }
1.1 root 552:
1.1.1.7 ! root 553: /* XXX: always use ldu or lds */
! 554: static inline void gen_op_ld_T0_A0(int idx)
! 555: {
! 556: gen_op_ld_v(idx, cpu_T[0], cpu_A0);
! 557: }
1.1 root 558:
1.1.1.7 ! root 559: static inline void gen_op_ldu_T0_A0(int idx)
! 560: {
! 561: gen_op_ld_v(idx, cpu_T[0], cpu_A0);
! 562: }
1.1 root 563:
1.1.1.7 ! root 564: static inline void gen_op_ld_T1_A0(int idx)
! 565: {
! 566: gen_op_ld_v(idx, cpu_T[1], cpu_A0);
! 567: }
1.1 root 568:
1.1.1.7 ! root 569: static inline void gen_op_st_v(int idx, TCGv t0, TCGv a0)
! 570: {
! 571: int mem_index = (idx >> 2) - 1;
! 572: switch(idx & 3) {
! 573: case 0:
! 574: tcg_gen_qemu_st8(t0, a0, mem_index);
! 575: break;
! 576: case 1:
! 577: tcg_gen_qemu_st16(t0, a0, mem_index);
! 578: break;
! 579: case 2:
! 580: tcg_gen_qemu_st32(t0, a0, mem_index);
! 581: break;
! 582: default:
! 583: case 3:
! 584: /* Should never happen on 32-bit targets. */
! 585: #ifdef TARGET_X86_64
! 586: tcg_gen_qemu_st64(t0, a0, mem_index);
1.1 root 587: #endif
1.1.1.7 ! root 588: break;
! 589: }
! 590: }
1.1 root 591:
1.1.1.7 ! root 592: static inline void gen_op_st_T0_A0(int idx)
! 593: {
! 594: gen_op_st_v(idx, cpu_T[0], cpu_A0);
! 595: }
1.1 root 596:
1.1.1.7 ! root 597: static inline void gen_op_st_T1_A0(int idx)
! 598: {
! 599: gen_op_st_v(idx, cpu_T[1], cpu_A0);
! 600: }
1.1 root 601:
602: static inline void gen_jmp_im(target_ulong pc)
603: {
1.1.1.7 ! root 604: tcg_gen_movi_tl(cpu_tmp0, pc);
! 605: tcg_gen_st_tl(cpu_tmp0, cpu_env, offsetof(CPUState, eip));
1.1 root 606: }
607:
608: static inline void gen_string_movl_A0_ESI(DisasContext *s)
609: {
610: int override;
611:
612: override = s->override;
613: #ifdef TARGET_X86_64
614: if (s->aflag == 2) {
615: if (override >= 0) {
1.1.1.7 ! root 616: gen_op_movq_A0_seg(override);
! 617: gen_op_addq_A0_reg_sN(0, R_ESI);
1.1 root 618: } else {
1.1.1.7 ! root 619: gen_op_movq_A0_reg(R_ESI);
1.1 root 620: }
621: } else
622: #endif
623: if (s->aflag) {
624: /* 32 bit address */
625: if (s->addseg && override < 0)
626: override = R_DS;
627: if (override >= 0) {
1.1.1.7 ! root 628: gen_op_movl_A0_seg(override);
! 629: gen_op_addl_A0_reg_sN(0, R_ESI);
1.1 root 630: } else {
1.1.1.7 ! root 631: gen_op_movl_A0_reg(R_ESI);
1.1 root 632: }
633: } else {
634: /* 16 address, always override */
635: if (override < 0)
636: override = R_DS;
1.1.1.7 ! root 637: gen_op_movl_A0_reg(R_ESI);
1.1 root 638: gen_op_andl_A0_ffff();
1.1.1.7 ! root 639: gen_op_addl_A0_seg(override);
1.1 root 640: }
641: }
642:
643: static inline void gen_string_movl_A0_EDI(DisasContext *s)
644: {
645: #ifdef TARGET_X86_64
646: if (s->aflag == 2) {
1.1.1.7 ! root 647: gen_op_movq_A0_reg(R_EDI);
1.1 root 648: } else
649: #endif
650: if (s->aflag) {
651: if (s->addseg) {
1.1.1.7 ! root 652: gen_op_movl_A0_seg(R_ES);
! 653: gen_op_addl_A0_reg_sN(0, R_EDI);
1.1 root 654: } else {
1.1.1.7 ! root 655: gen_op_movl_A0_reg(R_EDI);
1.1 root 656: }
657: } else {
1.1.1.7 ! root 658: gen_op_movl_A0_reg(R_EDI);
1.1 root 659: gen_op_andl_A0_ffff();
1.1.1.7 ! root 660: gen_op_addl_A0_seg(R_ES);
1.1 root 661: }
662: }
663:
1.1.1.7 ! root 664: static inline void gen_op_movl_T0_Dshift(int ot)
! 665: {
! 666: tcg_gen_ld32s_tl(cpu_T[0], cpu_env, offsetof(CPUState, df));
! 667: tcg_gen_shli_tl(cpu_T[0], cpu_T[0], ot);
1.1 root 668: };
669:
1.1.1.7 ! root 670: static void gen_extu(int ot, TCGv reg)
! 671: {
! 672: switch(ot) {
! 673: case OT_BYTE:
! 674: tcg_gen_ext8u_tl(reg, reg);
! 675: break;
! 676: case OT_WORD:
! 677: tcg_gen_ext16u_tl(reg, reg);
! 678: break;
! 679: case OT_LONG:
! 680: tcg_gen_ext32u_tl(reg, reg);
! 681: break;
! 682: default:
! 683: break;
! 684: }
! 685: }
1.1 root 686:
1.1.1.7 ! root 687: static void gen_exts(int ot, TCGv reg)
! 688: {
! 689: switch(ot) {
! 690: case OT_BYTE:
! 691: tcg_gen_ext8s_tl(reg, reg);
! 692: break;
! 693: case OT_WORD:
! 694: tcg_gen_ext16s_tl(reg, reg);
! 695: break;
! 696: case OT_LONG:
! 697: tcg_gen_ext32s_tl(reg, reg);
! 698: break;
! 699: default:
! 700: break;
! 701: }
! 702: }
1.1 root 703:
1.1.1.7 ! root 704: static inline void gen_op_jnz_ecx(int size, int label1)
! 705: {
! 706: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[R_ECX]));
! 707: gen_extu(size + 1, cpu_tmp0);
! 708: tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, label1);
! 709: }
1.1 root 710:
1.1.1.7 ! root 711: static inline void gen_op_jz_ecx(int size, int label1)
! 712: {
! 713: tcg_gen_ld_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[R_ECX]));
! 714: gen_extu(size + 1, cpu_tmp0);
! 715: tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
! 716: }
1.1 root 717:
1.1.1.7 ! root 718: static void gen_helper_in_func(int ot, TCGv v, TCGv_i32 n)
! 719: {
! 720: switch (ot) {
! 721: case 0: gen_helper_inb(v, n); break;
! 722: case 1: gen_helper_inw(v, n); break;
! 723: case 2: gen_helper_inl(v, n); break;
! 724: }
1.1 root 725:
1.1.1.7 ! root 726: }
1.1 root 727:
1.1.1.7 ! root 728: static void gen_helper_out_func(int ot, TCGv_i32 v, TCGv_i32 n)
! 729: {
! 730: switch (ot) {
! 731: case 0: gen_helper_outb(v, n); break;
! 732: case 1: gen_helper_outw(v, n); break;
! 733: case 2: gen_helper_outl(v, n); break;
! 734: }
1.1 root 735:
1.1.1.7 ! root 736: }
1.1 root 737:
1.1.1.7 ! root 738: static void gen_check_io(DisasContext *s, int ot, target_ulong cur_eip,
! 739: uint32_t svm_flags)
1.1 root 740: {
1.1.1.7 ! root 741: int state_saved;
! 742: target_ulong next_eip;
! 743:
! 744: state_saved = 0;
1.1 root 745: if (s->pe && (s->cpl > s->iopl || s->vm86)) {
746: if (s->cc_op != CC_OP_DYNAMIC)
747: gen_op_set_cc_op(s->cc_op);
748: gen_jmp_im(cur_eip);
1.1.1.7 ! root 749: state_saved = 1;
! 750: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 751: switch (ot) {
! 752: case 0: gen_helper_check_iob(cpu_tmp2_i32); break;
! 753: case 1: gen_helper_check_iow(cpu_tmp2_i32); break;
! 754: case 2: gen_helper_check_iol(cpu_tmp2_i32); break;
! 755: }
! 756: }
! 757: if(s->flags & HF_SVMI_MASK) {
! 758: if (!state_saved) {
! 759: if (s->cc_op != CC_OP_DYNAMIC)
! 760: gen_op_set_cc_op(s->cc_op);
! 761: gen_jmp_im(cur_eip);
! 762: state_saved = 1;
! 763: }
! 764: svm_flags |= (1 << (4 + ot));
! 765: next_eip = s->pc - s->cs_base;
! 766: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 767: gen_helper_svm_check_io(cpu_tmp2_i32, tcg_const_i32(svm_flags),
! 768: tcg_const_i32(next_eip - cur_eip));
1.1 root 769: }
770: }
771:
772: static inline void gen_movs(DisasContext *s, int ot)
773: {
774: gen_string_movl_A0_ESI(s);
1.1.1.7 ! root 775: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 776: gen_string_movl_A0_EDI(s);
1.1.1.7 ! root 777: gen_op_st_T0_A0(ot + s->mem_index);
! 778: gen_op_movl_T0_Dshift(ot);
! 779: gen_op_add_reg_T0(s->aflag, R_ESI);
! 780: gen_op_add_reg_T0(s->aflag, R_EDI);
1.1 root 781: }
782:
783: static inline void gen_update_cc_op(DisasContext *s)
784: {
785: if (s->cc_op != CC_OP_DYNAMIC) {
786: gen_op_set_cc_op(s->cc_op);
787: s->cc_op = CC_OP_DYNAMIC;
788: }
789: }
790:
1.1.1.7 ! root 791: static void gen_op_update1_cc(void)
! 792: {
! 793: tcg_gen_discard_tl(cpu_cc_src);
! 794: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 795: }
! 796:
! 797: static void gen_op_update2_cc(void)
! 798: {
! 799: tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
! 800: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 801: }
! 802:
! 803: static inline void gen_op_cmpl_T0_T1_cc(void)
! 804: {
! 805: tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
! 806: tcg_gen_sub_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
! 807: }
! 808:
! 809: static inline void gen_op_testl_T0_T1_cc(void)
! 810: {
! 811: tcg_gen_discard_tl(cpu_cc_src);
! 812: tcg_gen_and_tl(cpu_cc_dst, cpu_T[0], cpu_T[1]);
! 813: }
! 814:
! 815: static void gen_op_update_neg_cc(void)
! 816: {
! 817: tcg_gen_neg_tl(cpu_cc_src, cpu_T[0]);
! 818: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 819: }
! 820:
! 821: /* compute eflags.C to reg */
! 822: static void gen_compute_eflags_c(TCGv reg)
! 823: {
! 824: gen_helper_cc_compute_c(cpu_tmp2_i32, cpu_cc_op);
! 825: tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
! 826: }
! 827:
! 828: /* compute all eflags to cc_src */
! 829: static void gen_compute_eflags(TCGv reg)
! 830: {
! 831: gen_helper_cc_compute_all(cpu_tmp2_i32, cpu_cc_op);
! 832: tcg_gen_extu_i32_tl(reg, cpu_tmp2_i32);
! 833: }
! 834:
! 835: static inline void gen_setcc_slow_T0(DisasContext *s, int jcc_op)
! 836: {
! 837: if (s->cc_op != CC_OP_DYNAMIC)
! 838: gen_op_set_cc_op(s->cc_op);
! 839: switch(jcc_op) {
! 840: case JCC_O:
! 841: gen_compute_eflags(cpu_T[0]);
! 842: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 11);
! 843: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 844: break;
! 845: case JCC_B:
! 846: gen_compute_eflags_c(cpu_T[0]);
! 847: break;
! 848: case JCC_Z:
! 849: gen_compute_eflags(cpu_T[0]);
! 850: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 6);
! 851: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 852: break;
! 853: case JCC_BE:
! 854: gen_compute_eflags(cpu_tmp0);
! 855: tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 6);
! 856: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 857: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 858: break;
! 859: case JCC_S:
! 860: gen_compute_eflags(cpu_T[0]);
! 861: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 7);
! 862: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 863: break;
! 864: case JCC_P:
! 865: gen_compute_eflags(cpu_T[0]);
! 866: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 2);
! 867: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 868: break;
! 869: case JCC_L:
! 870: gen_compute_eflags(cpu_tmp0);
! 871: tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
! 872: tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 7); /* CC_S */
! 873: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 874: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 875: break;
! 876: default:
! 877: case JCC_LE:
! 878: gen_compute_eflags(cpu_tmp0);
! 879: tcg_gen_shri_tl(cpu_T[0], cpu_tmp0, 11); /* CC_O */
! 880: tcg_gen_shri_tl(cpu_tmp4, cpu_tmp0, 7); /* CC_S */
! 881: tcg_gen_shri_tl(cpu_tmp0, cpu_tmp0, 6); /* CC_Z */
! 882: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
! 883: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 884: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 1);
! 885: break;
! 886: }
! 887: }
! 888:
! 889: /* return true if setcc_slow is not needed (WARNING: must be kept in
! 890: sync with gen_jcc1) */
! 891: static int is_fast_jcc_case(DisasContext *s, int b)
! 892: {
! 893: int jcc_op;
! 894: jcc_op = (b >> 1) & 7;
! 895: switch(s->cc_op) {
! 896: /* we optimize the cmp/jcc case */
! 897: case CC_OP_SUBB:
! 898: case CC_OP_SUBW:
! 899: case CC_OP_SUBL:
! 900: case CC_OP_SUBQ:
! 901: if (jcc_op == JCC_O || jcc_op == JCC_P)
! 902: goto slow_jcc;
! 903: break;
! 904:
! 905: /* some jumps are easy to compute */
! 906: case CC_OP_ADDB:
! 907: case CC_OP_ADDW:
! 908: case CC_OP_ADDL:
! 909: case CC_OP_ADDQ:
! 910:
! 911: case CC_OP_LOGICB:
! 912: case CC_OP_LOGICW:
! 913: case CC_OP_LOGICL:
! 914: case CC_OP_LOGICQ:
! 915:
! 916: case CC_OP_INCB:
! 917: case CC_OP_INCW:
! 918: case CC_OP_INCL:
! 919: case CC_OP_INCQ:
! 920:
! 921: case CC_OP_DECB:
! 922: case CC_OP_DECW:
! 923: case CC_OP_DECL:
! 924: case CC_OP_DECQ:
! 925:
! 926: case CC_OP_SHLB:
! 927: case CC_OP_SHLW:
! 928: case CC_OP_SHLL:
! 929: case CC_OP_SHLQ:
! 930: if (jcc_op != JCC_Z && jcc_op != JCC_S)
! 931: goto slow_jcc;
! 932: break;
! 933: default:
! 934: slow_jcc:
! 935: return 0;
! 936: }
! 937: return 1;
! 938: }
! 939:
! 940: /* generate a conditional jump to label 'l1' according to jump opcode
! 941: value 'b'. In the fast case, T0 is guaranted not to be used. */
! 942: static inline void gen_jcc1(DisasContext *s, int cc_op, int b, int l1)
! 943: {
! 944: int inv, jcc_op, size, cond;
! 945: TCGv t0;
! 946:
! 947: inv = b & 1;
! 948: jcc_op = (b >> 1) & 7;
! 949:
! 950: switch(cc_op) {
! 951: /* we optimize the cmp/jcc case */
! 952: case CC_OP_SUBB:
! 953: case CC_OP_SUBW:
! 954: case CC_OP_SUBL:
! 955: case CC_OP_SUBQ:
! 956:
! 957: size = cc_op - CC_OP_SUBB;
! 958: switch(jcc_op) {
! 959: case JCC_Z:
! 960: fast_jcc_z:
! 961: switch(size) {
! 962: case 0:
! 963: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xff);
! 964: t0 = cpu_tmp0;
! 965: break;
! 966: case 1:
! 967: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffff);
! 968: t0 = cpu_tmp0;
! 969: break;
! 970: #ifdef TARGET_X86_64
! 971: case 2:
! 972: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0xffffffff);
! 973: t0 = cpu_tmp0;
! 974: break;
! 975: #endif
! 976: default:
! 977: t0 = cpu_cc_dst;
! 978: break;
! 979: }
! 980: tcg_gen_brcondi_tl(inv ? TCG_COND_NE : TCG_COND_EQ, t0, 0, l1);
! 981: break;
! 982: case JCC_S:
! 983: fast_jcc_s:
! 984: switch(size) {
! 985: case 0:
! 986: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80);
! 987: tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
! 988: 0, l1);
! 989: break;
! 990: case 1:
! 991: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x8000);
! 992: tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
! 993: 0, l1);
! 994: break;
! 995: #ifdef TARGET_X86_64
! 996: case 2:
! 997: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_dst, 0x80000000);
! 998: tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE, cpu_tmp0,
! 999: 0, l1);
! 1000: break;
! 1001: #endif
! 1002: default:
! 1003: tcg_gen_brcondi_tl(inv ? TCG_COND_GE : TCG_COND_LT, cpu_cc_dst,
! 1004: 0, l1);
! 1005: break;
! 1006: }
! 1007: break;
! 1008:
! 1009: case JCC_B:
! 1010: cond = inv ? TCG_COND_GEU : TCG_COND_LTU;
! 1011: goto fast_jcc_b;
! 1012: case JCC_BE:
! 1013: cond = inv ? TCG_COND_GTU : TCG_COND_LEU;
! 1014: fast_jcc_b:
! 1015: tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
! 1016: switch(size) {
! 1017: case 0:
! 1018: t0 = cpu_tmp0;
! 1019: tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xff);
! 1020: tcg_gen_andi_tl(t0, cpu_cc_src, 0xff);
! 1021: break;
! 1022: case 1:
! 1023: t0 = cpu_tmp0;
! 1024: tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffff);
! 1025: tcg_gen_andi_tl(t0, cpu_cc_src, 0xffff);
! 1026: break;
! 1027: #ifdef TARGET_X86_64
! 1028: case 2:
! 1029: t0 = cpu_tmp0;
! 1030: tcg_gen_andi_tl(cpu_tmp4, cpu_tmp4, 0xffffffff);
! 1031: tcg_gen_andi_tl(t0, cpu_cc_src, 0xffffffff);
! 1032: break;
! 1033: #endif
! 1034: default:
! 1035: t0 = cpu_cc_src;
! 1036: break;
! 1037: }
! 1038: tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
! 1039: break;
! 1040:
! 1041: case JCC_L:
! 1042: cond = inv ? TCG_COND_GE : TCG_COND_LT;
! 1043: goto fast_jcc_l;
! 1044: case JCC_LE:
! 1045: cond = inv ? TCG_COND_GT : TCG_COND_LE;
! 1046: fast_jcc_l:
! 1047: tcg_gen_add_tl(cpu_tmp4, cpu_cc_dst, cpu_cc_src);
! 1048: switch(size) {
! 1049: case 0:
! 1050: t0 = cpu_tmp0;
! 1051: tcg_gen_ext8s_tl(cpu_tmp4, cpu_tmp4);
! 1052: tcg_gen_ext8s_tl(t0, cpu_cc_src);
! 1053: break;
! 1054: case 1:
! 1055: t0 = cpu_tmp0;
! 1056: tcg_gen_ext16s_tl(cpu_tmp4, cpu_tmp4);
! 1057: tcg_gen_ext16s_tl(t0, cpu_cc_src);
! 1058: break;
! 1059: #ifdef TARGET_X86_64
! 1060: case 2:
! 1061: t0 = cpu_tmp0;
! 1062: tcg_gen_ext32s_tl(cpu_tmp4, cpu_tmp4);
! 1063: tcg_gen_ext32s_tl(t0, cpu_cc_src);
! 1064: break;
! 1065: #endif
! 1066: default:
! 1067: t0 = cpu_cc_src;
! 1068: break;
! 1069: }
! 1070: tcg_gen_brcond_tl(cond, cpu_tmp4, t0, l1);
! 1071: break;
! 1072:
! 1073: default:
! 1074: goto slow_jcc;
! 1075: }
! 1076: break;
! 1077:
! 1078: /* some jumps are easy to compute */
! 1079: case CC_OP_ADDB:
! 1080: case CC_OP_ADDW:
! 1081: case CC_OP_ADDL:
! 1082: case CC_OP_ADDQ:
! 1083:
! 1084: case CC_OP_ADCB:
! 1085: case CC_OP_ADCW:
! 1086: case CC_OP_ADCL:
! 1087: case CC_OP_ADCQ:
! 1088:
! 1089: case CC_OP_SBBB:
! 1090: case CC_OP_SBBW:
! 1091: case CC_OP_SBBL:
! 1092: case CC_OP_SBBQ:
! 1093:
! 1094: case CC_OP_LOGICB:
! 1095: case CC_OP_LOGICW:
! 1096: case CC_OP_LOGICL:
! 1097: case CC_OP_LOGICQ:
! 1098:
! 1099: case CC_OP_INCB:
! 1100: case CC_OP_INCW:
! 1101: case CC_OP_INCL:
! 1102: case CC_OP_INCQ:
! 1103:
! 1104: case CC_OP_DECB:
! 1105: case CC_OP_DECW:
! 1106: case CC_OP_DECL:
! 1107: case CC_OP_DECQ:
! 1108:
! 1109: case CC_OP_SHLB:
! 1110: case CC_OP_SHLW:
! 1111: case CC_OP_SHLL:
! 1112: case CC_OP_SHLQ:
! 1113:
! 1114: case CC_OP_SARB:
! 1115: case CC_OP_SARW:
! 1116: case CC_OP_SARL:
! 1117: case CC_OP_SARQ:
! 1118: switch(jcc_op) {
! 1119: case JCC_Z:
! 1120: size = (cc_op - CC_OP_ADDB) & 3;
! 1121: goto fast_jcc_z;
! 1122: case JCC_S:
! 1123: size = (cc_op - CC_OP_ADDB) & 3;
! 1124: goto fast_jcc_s;
! 1125: default:
! 1126: goto slow_jcc;
! 1127: }
! 1128: break;
! 1129: default:
! 1130: slow_jcc:
! 1131: gen_setcc_slow_T0(s, jcc_op);
! 1132: tcg_gen_brcondi_tl(inv ? TCG_COND_EQ : TCG_COND_NE,
! 1133: cpu_T[0], 0, l1);
! 1134: break;
! 1135: }
! 1136: }
! 1137:
1.1 root 1138: /* XXX: does not work with gdbstub "ice" single step - not a
1139: serious problem */
1140: static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
1141: {
1142: int l1, l2;
1143:
1144: l1 = gen_new_label();
1145: l2 = gen_new_label();
1.1.1.7 ! root 1146: gen_op_jnz_ecx(s->aflag, l1);
1.1 root 1147: gen_set_label(l2);
1148: gen_jmp_tb(s, next_eip, 1);
1149: gen_set_label(l1);
1150: return l2;
1151: }
1152:
1153: static inline void gen_stos(DisasContext *s, int ot)
1154: {
1.1.1.7 ! root 1155: gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
1.1 root 1156: gen_string_movl_A0_EDI(s);
1.1.1.7 ! root 1157: gen_op_st_T0_A0(ot + s->mem_index);
! 1158: gen_op_movl_T0_Dshift(ot);
! 1159: gen_op_add_reg_T0(s->aflag, R_EDI);
1.1 root 1160: }
1161:
1162: static inline void gen_lods(DisasContext *s, int ot)
1163: {
1164: gen_string_movl_A0_ESI(s);
1.1.1.7 ! root 1165: gen_op_ld_T0_A0(ot + s->mem_index);
! 1166: gen_op_mov_reg_T0(ot, R_EAX);
! 1167: gen_op_movl_T0_Dshift(ot);
! 1168: gen_op_add_reg_T0(s->aflag, R_ESI);
1.1 root 1169: }
1170:
1171: static inline void gen_scas(DisasContext *s, int ot)
1172: {
1.1.1.7 ! root 1173: gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
1.1 root 1174: gen_string_movl_A0_EDI(s);
1.1.1.7 ! root 1175: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 1176: gen_op_cmpl_T0_T1_cc();
1.1.1.7 ! root 1177: gen_op_movl_T0_Dshift(ot);
! 1178: gen_op_add_reg_T0(s->aflag, R_EDI);
1.1 root 1179: }
1180:
1181: static inline void gen_cmps(DisasContext *s, int ot)
1182: {
1183: gen_string_movl_A0_ESI(s);
1.1.1.7 ! root 1184: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 1185: gen_string_movl_A0_EDI(s);
1.1.1.7 ! root 1186: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 1187: gen_op_cmpl_T0_T1_cc();
1.1.1.7 ! root 1188: gen_op_movl_T0_Dshift(ot);
! 1189: gen_op_add_reg_T0(s->aflag, R_ESI);
! 1190: gen_op_add_reg_T0(s->aflag, R_EDI);
1.1 root 1191: }
1192:
1193: static inline void gen_ins(DisasContext *s, int ot)
1194: {
1.1.1.7 ! root 1195: if (use_icount)
! 1196: gen_io_start();
1.1 root 1197: gen_string_movl_A0_EDI(s);
1.1.1.7 ! root 1198: /* Note: we must do this dummy write first to be restartable in
! 1199: case of page fault. */
1.1 root 1200: gen_op_movl_T0_0();
1.1.1.7 ! root 1201: gen_op_st_T0_A0(ot + s->mem_index);
! 1202: gen_op_mov_TN_reg(OT_WORD, 1, R_EDX);
! 1203: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]);
! 1204: tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
! 1205: gen_helper_in_func(ot, cpu_T[0], cpu_tmp2_i32);
! 1206: gen_op_st_T0_A0(ot + s->mem_index);
! 1207: gen_op_movl_T0_Dshift(ot);
! 1208: gen_op_add_reg_T0(s->aflag, R_EDI);
! 1209: if (use_icount)
! 1210: gen_io_end();
1.1 root 1211: }
1212:
1213: static inline void gen_outs(DisasContext *s, int ot)
1214: {
1.1.1.7 ! root 1215: if (use_icount)
! 1216: gen_io_start();
1.1 root 1217: gen_string_movl_A0_ESI(s);
1.1.1.7 ! root 1218: gen_op_ld_T0_A0(ot + s->mem_index);
! 1219:
! 1220: gen_op_mov_TN_reg(OT_WORD, 1, R_EDX);
! 1221: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[1]);
! 1222: tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
! 1223: tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[0]);
! 1224: gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
! 1225:
! 1226: gen_op_movl_T0_Dshift(ot);
! 1227: gen_op_add_reg_T0(s->aflag, R_ESI);
! 1228: if (use_icount)
! 1229: gen_io_end();
1.1 root 1230: }
1231:
1232: /* same method as Valgrind : we generate jumps to current or next
1233: instruction */
1234: #define GEN_REPZ(op) \
1235: static inline void gen_repz_ ## op(DisasContext *s, int ot, \
1236: target_ulong cur_eip, target_ulong next_eip) \
1237: { \
1238: int l2;\
1239: gen_update_cc_op(s); \
1240: l2 = gen_jz_ecx_string(s, next_eip); \
1241: gen_ ## op(s, ot); \
1.1.1.7 ! root 1242: gen_op_add_reg_im(s->aflag, R_ECX, -1); \
1.1 root 1243: /* a loop would cause two single step exceptions if ECX = 1 \
1244: before rep string_insn */ \
1245: if (!s->jmp_opt) \
1.1.1.7 ! root 1246: gen_op_jz_ecx(s->aflag, l2); \
1.1 root 1247: gen_jmp(s, cur_eip); \
1248: }
1249:
1250: #define GEN_REPZ2(op) \
1251: static inline void gen_repz_ ## op(DisasContext *s, int ot, \
1252: target_ulong cur_eip, \
1253: target_ulong next_eip, \
1254: int nz) \
1255: { \
1256: int l2;\
1257: gen_update_cc_op(s); \
1258: l2 = gen_jz_ecx_string(s, next_eip); \
1259: gen_ ## op(s, ot); \
1.1.1.7 ! root 1260: gen_op_add_reg_im(s->aflag, R_ECX, -1); \
1.1 root 1261: gen_op_set_cc_op(CC_OP_SUBB + ot); \
1.1.1.7 ! root 1262: gen_jcc1(s, CC_OP_SUBB + ot, (JCC_Z << 1) | (nz ^ 1), l2); \
1.1 root 1263: if (!s->jmp_opt) \
1.1.1.7 ! root 1264: gen_op_jz_ecx(s->aflag, l2); \
1.1 root 1265: gen_jmp(s, cur_eip); \
1266: }
1267:
1268: GEN_REPZ(movs)
1269: GEN_REPZ(stos)
1270: GEN_REPZ(lods)
1271: GEN_REPZ(ins)
1272: GEN_REPZ(outs)
1273: GEN_REPZ2(scas)
1274: GEN_REPZ2(cmps)
1275:
1.1.1.7 ! root 1276: static void gen_helper_fp_arith_ST0_FT0(int op)
! 1277: {
! 1278: switch (op) {
! 1279: case 0: gen_helper_fadd_ST0_FT0(); break;
! 1280: case 1: gen_helper_fmul_ST0_FT0(); break;
! 1281: case 2: gen_helper_fcom_ST0_FT0(); break;
! 1282: case 3: gen_helper_fcom_ST0_FT0(); break;
! 1283: case 4: gen_helper_fsub_ST0_FT0(); break;
! 1284: case 5: gen_helper_fsubr_ST0_FT0(); break;
! 1285: case 6: gen_helper_fdiv_ST0_FT0(); break;
! 1286: case 7: gen_helper_fdivr_ST0_FT0(); break;
! 1287: }
! 1288: }
1.1 root 1289:
1290: /* NOTE the exception in "r" op ordering */
1.1.1.7 ! root 1291: static void gen_helper_fp_arith_STN_ST0(int op, int opreg)
! 1292: {
! 1293: TCGv_i32 tmp = tcg_const_i32(opreg);
! 1294: switch (op) {
! 1295: case 0: gen_helper_fadd_STN_ST0(tmp); break;
! 1296: case 1: gen_helper_fmul_STN_ST0(tmp); break;
! 1297: case 4: gen_helper_fsubr_STN_ST0(tmp); break;
! 1298: case 5: gen_helper_fsub_STN_ST0(tmp); break;
! 1299: case 6: gen_helper_fdivr_STN_ST0(tmp); break;
! 1300: case 7: gen_helper_fdiv_STN_ST0(tmp); break;
! 1301: }
! 1302: }
1.1 root 1303:
1304: /* if d == OR_TMP0, it means memory operand (address in A0) */
1305: static void gen_op(DisasContext *s1, int op, int ot, int d)
1306: {
1307: if (d != OR_TMP0) {
1.1.1.7 ! root 1308: gen_op_mov_TN_reg(ot, 0, d);
1.1 root 1309: } else {
1.1.1.7 ! root 1310: gen_op_ld_T0_A0(ot + s1->mem_index);
1.1 root 1311: }
1312: switch(op) {
1313: case OP_ADCL:
1.1.1.7 ! root 1314: if (s1->cc_op != CC_OP_DYNAMIC)
! 1315: gen_op_set_cc_op(s1->cc_op);
! 1316: gen_compute_eflags_c(cpu_tmp4);
! 1317: tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1318: tcg_gen_add_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
! 1319: if (d != OR_TMP0)
! 1320: gen_op_mov_reg_T0(ot, d);
! 1321: else
! 1322: gen_op_st_T0_A0(ot + s1->mem_index);
! 1323: tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
! 1324: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 1325: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
! 1326: tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
! 1327: tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_ADDB + ot);
! 1328: s1->cc_op = CC_OP_DYNAMIC;
! 1329: break;
1.1 root 1330: case OP_SBBL:
1331: if (s1->cc_op != CC_OP_DYNAMIC)
1332: gen_op_set_cc_op(s1->cc_op);
1.1.1.7 ! root 1333: gen_compute_eflags_c(cpu_tmp4);
! 1334: tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1335: tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_tmp4);
! 1336: if (d != OR_TMP0)
! 1337: gen_op_mov_reg_T0(ot, d);
! 1338: else
! 1339: gen_op_st_T0_A0(ot + s1->mem_index);
! 1340: tcg_gen_mov_tl(cpu_cc_src, cpu_T[1]);
! 1341: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 1342: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp4);
! 1343: tcg_gen_shli_i32(cpu_tmp2_i32, cpu_tmp2_i32, 2);
! 1344: tcg_gen_addi_i32(cpu_cc_op, cpu_tmp2_i32, CC_OP_SUBB + ot);
1.1 root 1345: s1->cc_op = CC_OP_DYNAMIC;
1.1.1.7 ! root 1346: break;
1.1 root 1347: case OP_ADDL:
1348: gen_op_addl_T0_T1();
1.1.1.7 ! root 1349: if (d != OR_TMP0)
! 1350: gen_op_mov_reg_T0(ot, d);
! 1351: else
! 1352: gen_op_st_T0_A0(ot + s1->mem_index);
! 1353: gen_op_update2_cc();
1.1 root 1354: s1->cc_op = CC_OP_ADDB + ot;
1355: break;
1356: case OP_SUBL:
1.1.1.7 ! root 1357: tcg_gen_sub_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1358: if (d != OR_TMP0)
! 1359: gen_op_mov_reg_T0(ot, d);
! 1360: else
! 1361: gen_op_st_T0_A0(ot + s1->mem_index);
! 1362: gen_op_update2_cc();
1.1 root 1363: s1->cc_op = CC_OP_SUBB + ot;
1364: break;
1365: default:
1366: case OP_ANDL:
1.1.1.7 ! root 1367: tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1368: if (d != OR_TMP0)
! 1369: gen_op_mov_reg_T0(ot, d);
! 1370: else
! 1371: gen_op_st_T0_A0(ot + s1->mem_index);
! 1372: gen_op_update1_cc();
! 1373: s1->cc_op = CC_OP_LOGICB + ot;
! 1374: break;
1.1 root 1375: case OP_ORL:
1.1.1.7 ! root 1376: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1377: if (d != OR_TMP0)
! 1378: gen_op_mov_reg_T0(ot, d);
! 1379: else
! 1380: gen_op_st_T0_A0(ot + s1->mem_index);
! 1381: gen_op_update1_cc();
! 1382: s1->cc_op = CC_OP_LOGICB + ot;
! 1383: break;
1.1 root 1384: case OP_XORL:
1.1.1.7 ! root 1385: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1386: if (d != OR_TMP0)
! 1387: gen_op_mov_reg_T0(ot, d);
! 1388: else
! 1389: gen_op_st_T0_A0(ot + s1->mem_index);
! 1390: gen_op_update1_cc();
1.1 root 1391: s1->cc_op = CC_OP_LOGICB + ot;
1392: break;
1393: case OP_CMPL:
1394: gen_op_cmpl_T0_T1_cc();
1395: s1->cc_op = CC_OP_SUBB + ot;
1396: break;
1397: }
1.1.1.7 ! root 1398: }
! 1399:
! 1400: /* if d == OR_TMP0, it means memory operand (address in A0) */
! 1401: static void gen_inc(DisasContext *s1, int ot, int d, int c)
! 1402: {
! 1403: if (d != OR_TMP0)
! 1404: gen_op_mov_TN_reg(ot, 0, d);
! 1405: else
! 1406: gen_op_ld_T0_A0(ot + s1->mem_index);
! 1407: if (s1->cc_op != CC_OP_DYNAMIC)
! 1408: gen_op_set_cc_op(s1->cc_op);
! 1409: if (c > 0) {
! 1410: tcg_gen_addi_tl(cpu_T[0], cpu_T[0], 1);
! 1411: s1->cc_op = CC_OP_INCB + ot;
! 1412: } else {
! 1413: tcg_gen_addi_tl(cpu_T[0], cpu_T[0], -1);
! 1414: s1->cc_op = CC_OP_DECB + ot;
! 1415: }
! 1416: if (d != OR_TMP0)
! 1417: gen_op_mov_reg_T0(ot, d);
! 1418: else
! 1419: gen_op_st_T0_A0(ot + s1->mem_index);
! 1420: gen_compute_eflags_c(cpu_cc_src);
! 1421: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 1422: }
! 1423:
! 1424: static void gen_shift_rm_T1(DisasContext *s, int ot, int op1,
! 1425: int is_right, int is_arith)
! 1426: {
! 1427: target_ulong mask;
! 1428: int shift_label;
! 1429: TCGv t0, t1;
! 1430:
! 1431: if (ot == OT_QUAD)
! 1432: mask = 0x3f;
! 1433: else
! 1434: mask = 0x1f;
! 1435:
! 1436: /* load */
! 1437: if (op1 == OR_TMP0)
! 1438: gen_op_ld_T0_A0(ot + s->mem_index);
! 1439: else
! 1440: gen_op_mov_TN_reg(ot, 0, op1);
! 1441:
! 1442: tcg_gen_andi_tl(cpu_T[1], cpu_T[1], mask);
! 1443:
! 1444: tcg_gen_addi_tl(cpu_tmp5, cpu_T[1], -1);
! 1445:
! 1446: if (is_right) {
! 1447: if (is_arith) {
! 1448: gen_exts(ot, cpu_T[0]);
! 1449: tcg_gen_sar_tl(cpu_T3, cpu_T[0], cpu_tmp5);
! 1450: tcg_gen_sar_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1451: } else {
! 1452: gen_extu(ot, cpu_T[0]);
! 1453: tcg_gen_shr_tl(cpu_T3, cpu_T[0], cpu_tmp5);
! 1454: tcg_gen_shr_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1455: }
! 1456: } else {
! 1457: tcg_gen_shl_tl(cpu_T3, cpu_T[0], cpu_tmp5);
! 1458: tcg_gen_shl_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 1459: }
! 1460:
! 1461: /* store */
! 1462: if (op1 == OR_TMP0)
! 1463: gen_op_st_T0_A0(ot + s->mem_index);
! 1464: else
! 1465: gen_op_mov_reg_T0(ot, op1);
! 1466:
! 1467: /* update eflags if non zero shift */
! 1468: if (s->cc_op != CC_OP_DYNAMIC)
! 1469: gen_op_set_cc_op(s->cc_op);
! 1470:
! 1471: /* XXX: inefficient */
! 1472: t0 = tcg_temp_local_new();
! 1473: t1 = tcg_temp_local_new();
! 1474:
! 1475: tcg_gen_mov_tl(t0, cpu_T[0]);
! 1476: tcg_gen_mov_tl(t1, cpu_T3);
! 1477:
! 1478: shift_label = gen_new_label();
! 1479: tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_T[1], 0, shift_label);
! 1480:
! 1481: tcg_gen_mov_tl(cpu_cc_src, t1);
! 1482: tcg_gen_mov_tl(cpu_cc_dst, t0);
! 1483: if (is_right)
! 1484: tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
! 1485: else
! 1486: tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
! 1487:
! 1488: gen_set_label(shift_label);
! 1489: s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
! 1490:
! 1491: tcg_temp_free(t0);
! 1492: tcg_temp_free(t1);
! 1493: }
! 1494:
! 1495: static void gen_shift_rm_im(DisasContext *s, int ot, int op1, int op2,
! 1496: int is_right, int is_arith)
! 1497: {
! 1498: int mask;
! 1499:
! 1500: if (ot == OT_QUAD)
! 1501: mask = 0x3f;
! 1502: else
! 1503: mask = 0x1f;
! 1504:
! 1505: /* load */
! 1506: if (op1 == OR_TMP0)
! 1507: gen_op_ld_T0_A0(ot + s->mem_index);
! 1508: else
! 1509: gen_op_mov_TN_reg(ot, 0, op1);
! 1510:
! 1511: op2 &= mask;
! 1512: if (op2 != 0) {
! 1513: if (is_right) {
! 1514: if (is_arith) {
! 1515: gen_exts(ot, cpu_T[0]);
! 1516: tcg_gen_sari_tl(cpu_tmp4, cpu_T[0], op2 - 1);
! 1517: tcg_gen_sari_tl(cpu_T[0], cpu_T[0], op2);
! 1518: } else {
! 1519: gen_extu(ot, cpu_T[0]);
! 1520: tcg_gen_shri_tl(cpu_tmp4, cpu_T[0], op2 - 1);
! 1521: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], op2);
! 1522: }
! 1523: } else {
! 1524: tcg_gen_shli_tl(cpu_tmp4, cpu_T[0], op2 - 1);
! 1525: tcg_gen_shli_tl(cpu_T[0], cpu_T[0], op2);
! 1526: }
! 1527: }
! 1528:
! 1529: /* store */
! 1530: if (op1 == OR_TMP0)
! 1531: gen_op_st_T0_A0(ot + s->mem_index);
! 1532: else
! 1533: gen_op_mov_reg_T0(ot, op1);
! 1534:
! 1535: /* update eflags if non zero shift */
! 1536: if (op2 != 0) {
! 1537: tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
! 1538: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 1539: if (is_right)
! 1540: s->cc_op = CC_OP_SARB + ot;
! 1541: else
! 1542: s->cc_op = CC_OP_SHLB + ot;
! 1543: }
! 1544: }
! 1545:
! 1546: static inline void tcg_gen_lshift(TCGv ret, TCGv arg1, target_long arg2)
! 1547: {
! 1548: if (arg2 >= 0)
! 1549: tcg_gen_shli_tl(ret, arg1, arg2);
! 1550: else
! 1551: tcg_gen_shri_tl(ret, arg1, -arg2);
! 1552: }
! 1553:
! 1554: /* XXX: add faster immediate case */
! 1555: static void gen_rot_rm_T1(DisasContext *s, int ot, int op1,
! 1556: int is_right)
! 1557: {
! 1558: target_ulong mask;
! 1559: int label1, label2, data_bits;
! 1560: TCGv t0, t1, t2, a0;
! 1561:
! 1562: /* XXX: inefficient, but we must use local temps */
! 1563: t0 = tcg_temp_local_new();
! 1564: t1 = tcg_temp_local_new();
! 1565: t2 = tcg_temp_local_new();
! 1566: a0 = tcg_temp_local_new();
! 1567:
! 1568: if (ot == OT_QUAD)
! 1569: mask = 0x3f;
! 1570: else
! 1571: mask = 0x1f;
! 1572:
! 1573: /* load */
! 1574: if (op1 == OR_TMP0) {
! 1575: tcg_gen_mov_tl(a0, cpu_A0);
! 1576: gen_op_ld_v(ot + s->mem_index, t0, a0);
! 1577: } else {
! 1578: gen_op_mov_v_reg(ot, t0, op1);
! 1579: }
! 1580:
! 1581: tcg_gen_mov_tl(t1, cpu_T[1]);
! 1582:
! 1583: tcg_gen_andi_tl(t1, t1, mask);
! 1584:
! 1585: /* Must test zero case to avoid using undefined behaviour in TCG
! 1586: shifts. */
! 1587: label1 = gen_new_label();
! 1588: tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label1);
! 1589:
! 1590: if (ot <= OT_WORD)
! 1591: tcg_gen_andi_tl(cpu_tmp0, t1, (1 << (3 + ot)) - 1);
! 1592: else
! 1593: tcg_gen_mov_tl(cpu_tmp0, t1);
! 1594:
! 1595: gen_extu(ot, t0);
! 1596: tcg_gen_mov_tl(t2, t0);
! 1597:
! 1598: data_bits = 8 << ot;
! 1599: /* XXX: rely on behaviour of shifts when operand 2 overflows (XXX:
! 1600: fix TCG definition) */
! 1601: if (is_right) {
! 1602: tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp0);
! 1603: tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(data_bits), cpu_tmp0);
! 1604: tcg_gen_shl_tl(t0, t0, cpu_tmp0);
! 1605: } else {
! 1606: tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp0);
! 1607: tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(data_bits), cpu_tmp0);
! 1608: tcg_gen_shr_tl(t0, t0, cpu_tmp0);
! 1609: }
! 1610: tcg_gen_or_tl(t0, t0, cpu_tmp4);
! 1611:
! 1612: gen_set_label(label1);
! 1613: /* store */
! 1614: if (op1 == OR_TMP0) {
! 1615: gen_op_st_v(ot + s->mem_index, t0, a0);
! 1616: } else {
! 1617: gen_op_mov_reg_v(ot, op1, t0);
1.1 root 1618: }
1.1.1.7 ! root 1619:
! 1620: /* update eflags */
! 1621: if (s->cc_op != CC_OP_DYNAMIC)
! 1622: gen_op_set_cc_op(s->cc_op);
1.1 root 1623:
1.1.1.7 ! root 1624: label2 = gen_new_label();
! 1625: tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, label2);
! 1626:
! 1627: gen_compute_eflags(cpu_cc_src);
! 1628: tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~(CC_O | CC_C));
! 1629: tcg_gen_xor_tl(cpu_tmp0, t2, t0);
! 1630: tcg_gen_lshift(cpu_tmp0, cpu_tmp0, 11 - (data_bits - 1));
! 1631: tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_O);
! 1632: tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_tmp0);
! 1633: if (is_right) {
! 1634: tcg_gen_shri_tl(t0, t0, data_bits - 1);
! 1635: }
! 1636: tcg_gen_andi_tl(t0, t0, CC_C);
! 1637: tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t0);
! 1638:
! 1639: tcg_gen_discard_tl(cpu_cc_dst);
! 1640: tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
! 1641:
! 1642: gen_set_label(label2);
! 1643: s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
! 1644:
! 1645: tcg_temp_free(t0);
! 1646: tcg_temp_free(t1);
! 1647: tcg_temp_free(t2);
! 1648: tcg_temp_free(a0);
! 1649: }
! 1650:
! 1651: /* XXX: add faster immediate = 1 case */
! 1652: static void gen_rotc_rm_T1(DisasContext *s, int ot, int op1,
! 1653: int is_right)
1.1 root 1654: {
1.1.1.7 ! root 1655: int label1;
! 1656:
! 1657: if (s->cc_op != CC_OP_DYNAMIC)
! 1658: gen_op_set_cc_op(s->cc_op);
! 1659:
! 1660: /* load */
! 1661: if (op1 == OR_TMP0)
! 1662: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 1663: else
1.1.1.7 ! root 1664: gen_op_mov_TN_reg(ot, 0, op1);
! 1665:
! 1666: if (is_right) {
! 1667: switch (ot) {
! 1668: case 0: gen_helper_rcrb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1669: case 1: gen_helper_rcrw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1670: case 2: gen_helper_rcrl(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1671: #ifdef TARGET_X86_64
! 1672: case 3: gen_helper_rcrq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1673: #endif
! 1674: }
1.1 root 1675: } else {
1.1.1.7 ! root 1676: switch (ot) {
! 1677: case 0: gen_helper_rclb(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1678: case 1: gen_helper_rclw(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1679: case 2: gen_helper_rcll(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1680: #ifdef TARGET_X86_64
! 1681: case 3: gen_helper_rclq(cpu_T[0], cpu_T[0], cpu_T[1]); break;
! 1682: #endif
! 1683: }
1.1 root 1684: }
1.1.1.7 ! root 1685: /* store */
! 1686: if (op1 == OR_TMP0)
! 1687: gen_op_st_T0_A0(ot + s->mem_index);
! 1688: else
! 1689: gen_op_mov_reg_T0(ot, op1);
! 1690:
! 1691: /* update eflags */
! 1692: label1 = gen_new_label();
! 1693: tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_cc_tmp, -1, label1);
! 1694:
! 1695: tcg_gen_mov_tl(cpu_cc_src, cpu_cc_tmp);
! 1696: tcg_gen_discard_tl(cpu_cc_dst);
! 1697: tcg_gen_movi_i32(cpu_cc_op, CC_OP_EFLAGS);
! 1698:
! 1699: gen_set_label(label1);
! 1700: s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
! 1701: }
! 1702:
! 1703: /* XXX: add faster immediate case */
! 1704: static void gen_shiftd_rm_T1_T3(DisasContext *s, int ot, int op1,
! 1705: int is_right)
! 1706: {
! 1707: int label1, label2, data_bits;
! 1708: target_ulong mask;
! 1709: TCGv t0, t1, t2, a0;
! 1710:
! 1711: t0 = tcg_temp_local_new();
! 1712: t1 = tcg_temp_local_new();
! 1713: t2 = tcg_temp_local_new();
! 1714: a0 = tcg_temp_local_new();
! 1715:
! 1716: if (ot == OT_QUAD)
! 1717: mask = 0x3f;
1.1 root 1718: else
1.1.1.7 ! root 1719: mask = 0x1f;
! 1720:
! 1721: /* load */
! 1722: if (op1 == OR_TMP0) {
! 1723: tcg_gen_mov_tl(a0, cpu_A0);
! 1724: gen_op_ld_v(ot + s->mem_index, t0, a0);
! 1725: } else {
! 1726: gen_op_mov_v_reg(ot, t0, op1);
! 1727: }
! 1728:
! 1729: tcg_gen_andi_tl(cpu_T3, cpu_T3, mask);
! 1730:
! 1731: tcg_gen_mov_tl(t1, cpu_T[1]);
! 1732: tcg_gen_mov_tl(t2, cpu_T3);
! 1733:
! 1734: /* Must test zero case to avoid using undefined behaviour in TCG
! 1735: shifts. */
! 1736: label1 = gen_new_label();
! 1737: tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
! 1738:
! 1739: tcg_gen_addi_tl(cpu_tmp5, t2, -1);
! 1740: if (ot == OT_WORD) {
! 1741: /* Note: we implement the Intel behaviour for shift count > 16 */
! 1742: if (is_right) {
! 1743: tcg_gen_andi_tl(t0, t0, 0xffff);
! 1744: tcg_gen_shli_tl(cpu_tmp0, t1, 16);
! 1745: tcg_gen_or_tl(t0, t0, cpu_tmp0);
! 1746: tcg_gen_ext32u_tl(t0, t0);
! 1747:
! 1748: tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
! 1749:
! 1750: /* only needed if count > 16, but a test would complicate */
! 1751: tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(32), t2);
! 1752: tcg_gen_shl_tl(cpu_tmp0, t0, cpu_tmp5);
! 1753:
! 1754: tcg_gen_shr_tl(t0, t0, t2);
! 1755:
! 1756: tcg_gen_or_tl(t0, t0, cpu_tmp0);
! 1757: } else {
! 1758: /* XXX: not optimal */
! 1759: tcg_gen_andi_tl(t0, t0, 0xffff);
! 1760: tcg_gen_shli_tl(t1, t1, 16);
! 1761: tcg_gen_or_tl(t1, t1, t0);
! 1762: tcg_gen_ext32u_tl(t1, t1);
! 1763:
! 1764: tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
! 1765: tcg_gen_sub_tl(cpu_tmp0, tcg_const_tl(32), cpu_tmp5);
! 1766: tcg_gen_shr_tl(cpu_tmp6, t1, cpu_tmp0);
! 1767: tcg_gen_or_tl(cpu_tmp4, cpu_tmp4, cpu_tmp6);
! 1768:
! 1769: tcg_gen_shl_tl(t0, t0, t2);
! 1770: tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(32), t2);
! 1771: tcg_gen_shr_tl(t1, t1, cpu_tmp5);
! 1772: tcg_gen_or_tl(t0, t0, t1);
! 1773: }
! 1774: } else {
! 1775: data_bits = 8 << ot;
! 1776: if (is_right) {
! 1777: if (ot == OT_LONG)
! 1778: tcg_gen_ext32u_tl(t0, t0);
! 1779:
! 1780: tcg_gen_shr_tl(cpu_tmp4, t0, cpu_tmp5);
! 1781:
! 1782: tcg_gen_shr_tl(t0, t0, t2);
! 1783: tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(data_bits), t2);
! 1784: tcg_gen_shl_tl(t1, t1, cpu_tmp5);
! 1785: tcg_gen_or_tl(t0, t0, t1);
! 1786:
! 1787: } else {
! 1788: if (ot == OT_LONG)
! 1789: tcg_gen_ext32u_tl(t1, t1);
! 1790:
! 1791: tcg_gen_shl_tl(cpu_tmp4, t0, cpu_tmp5);
! 1792:
! 1793: tcg_gen_shl_tl(t0, t0, t2);
! 1794: tcg_gen_sub_tl(cpu_tmp5, tcg_const_tl(data_bits), t2);
! 1795: tcg_gen_shr_tl(t1, t1, cpu_tmp5);
! 1796: tcg_gen_or_tl(t0, t0, t1);
! 1797: }
! 1798: }
! 1799: tcg_gen_mov_tl(t1, cpu_tmp4);
! 1800:
! 1801: gen_set_label(label1);
! 1802: /* store */
! 1803: if (op1 == OR_TMP0) {
! 1804: gen_op_st_v(ot + s->mem_index, t0, a0);
! 1805: } else {
! 1806: gen_op_mov_reg_v(ot, op1, t0);
! 1807: }
! 1808:
! 1809: /* update eflags */
! 1810: if (s->cc_op != CC_OP_DYNAMIC)
! 1811: gen_op_set_cc_op(s->cc_op);
! 1812:
! 1813: label2 = gen_new_label();
! 1814: tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label2);
! 1815:
! 1816: tcg_gen_mov_tl(cpu_cc_src, t1);
! 1817: tcg_gen_mov_tl(cpu_cc_dst, t0);
! 1818: if (is_right) {
! 1819: tcg_gen_movi_i32(cpu_cc_op, CC_OP_SARB + ot);
! 1820: } else {
! 1821: tcg_gen_movi_i32(cpu_cc_op, CC_OP_SHLB + ot);
! 1822: }
! 1823: gen_set_label(label2);
! 1824: s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
! 1825:
! 1826: tcg_temp_free(t0);
! 1827: tcg_temp_free(t1);
! 1828: tcg_temp_free(t2);
! 1829: tcg_temp_free(a0);
1.1 root 1830: }
1831:
1832: static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
1833: {
1834: if (s != OR_TMP1)
1.1.1.7 ! root 1835: gen_op_mov_TN_reg(ot, 1, s);
! 1836: switch(op) {
! 1837: case OP_ROL:
! 1838: gen_rot_rm_T1(s1, ot, d, 0);
! 1839: break;
! 1840: case OP_ROR:
! 1841: gen_rot_rm_T1(s1, ot, d, 1);
! 1842: break;
! 1843: case OP_SHL:
! 1844: case OP_SHL1:
! 1845: gen_shift_rm_T1(s1, ot, d, 0, 0);
! 1846: break;
! 1847: case OP_SHR:
! 1848: gen_shift_rm_T1(s1, ot, d, 1, 0);
! 1849: break;
! 1850: case OP_SAR:
! 1851: gen_shift_rm_T1(s1, ot, d, 1, 1);
! 1852: break;
! 1853: case OP_RCL:
! 1854: gen_rotc_rm_T1(s1, ot, d, 0);
! 1855: break;
! 1856: case OP_RCR:
! 1857: gen_rotc_rm_T1(s1, ot, d, 1);
! 1858: break;
! 1859: }
1.1 root 1860: }
1861:
1862: static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
1863: {
1.1.1.7 ! root 1864: switch(op) {
! 1865: case OP_SHL:
! 1866: case OP_SHL1:
! 1867: gen_shift_rm_im(s1, ot, d, c, 0, 0);
! 1868: break;
! 1869: case OP_SHR:
! 1870: gen_shift_rm_im(s1, ot, d, c, 1, 0);
! 1871: break;
! 1872: case OP_SAR:
! 1873: gen_shift_rm_im(s1, ot, d, c, 1, 1);
! 1874: break;
! 1875: default:
! 1876: /* currently not optimized */
! 1877: gen_op_movl_T1_im(c);
! 1878: gen_shift(s1, op, ot, d, OR_TMP1);
! 1879: break;
! 1880: }
1.1 root 1881: }
1882:
1883: static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
1884: {
1885: target_long disp;
1886: int havesib;
1887: int base;
1888: int index;
1889: int scale;
1890: int opreg;
1891: int mod, rm, code, override, must_add_seg;
1892:
1893: override = s->override;
1894: must_add_seg = s->addseg;
1895: if (override >= 0)
1896: must_add_seg = 1;
1897: mod = (modrm >> 6) & 3;
1898: rm = modrm & 7;
1899:
1900: if (s->aflag) {
1901:
1902: havesib = 0;
1903: base = rm;
1904: index = 0;
1905: scale = 0;
1.1.1.6 root 1906:
1.1 root 1907: if (base == 4) {
1908: havesib = 1;
1909: code = ldub_code(s->pc++);
1910: scale = (code >> 6) & 3;
1911: index = ((code >> 3) & 7) | REX_X(s);
1912: base = (code & 7);
1913: }
1914: base |= REX_B(s);
1915:
1916: switch (mod) {
1917: case 0:
1918: if ((base & 7) == 5) {
1919: base = -1;
1920: disp = (int32_t)ldl_code(s->pc);
1921: s->pc += 4;
1922: if (CODE64(s) && !havesib) {
1923: disp += s->pc + s->rip_offset;
1924: }
1925: } else {
1926: disp = 0;
1927: }
1928: break;
1929: case 1:
1930: disp = (int8_t)ldub_code(s->pc++);
1931: break;
1932: default:
1933: case 2:
1934: disp = ldl_code(s->pc);
1935: s->pc += 4;
1936: break;
1937: }
1.1.1.6 root 1938:
1.1 root 1939: if (base >= 0) {
1940: /* for correct popl handling with esp */
1941: if (base == 4 && s->popl_esp_hack)
1942: disp += s->popl_esp_hack;
1943: #ifdef TARGET_X86_64
1944: if (s->aflag == 2) {
1.1.1.7 ! root 1945: gen_op_movq_A0_reg(base);
1.1 root 1946: if (disp != 0) {
1.1.1.7 ! root 1947: gen_op_addq_A0_im(disp);
1.1 root 1948: }
1.1.1.6 root 1949: } else
1.1 root 1950: #endif
1951: {
1.1.1.7 ! root 1952: gen_op_movl_A0_reg(base);
1.1 root 1953: if (disp != 0)
1954: gen_op_addl_A0_im(disp);
1955: }
1956: } else {
1957: #ifdef TARGET_X86_64
1958: if (s->aflag == 2) {
1.1.1.7 ! root 1959: gen_op_movq_A0_im(disp);
1.1.1.6 root 1960: } else
1.1 root 1961: #endif
1962: {
1963: gen_op_movl_A0_im(disp);
1964: }
1965: }
1966: /* XXX: index == 4 is always invalid */
1967: if (havesib && (index != 4 || scale != 0)) {
1968: #ifdef TARGET_X86_64
1969: if (s->aflag == 2) {
1.1.1.7 ! root 1970: gen_op_addq_A0_reg_sN(scale, index);
1.1.1.6 root 1971: } else
1.1 root 1972: #endif
1973: {
1.1.1.7 ! root 1974: gen_op_addl_A0_reg_sN(scale, index);
1.1 root 1975: }
1976: }
1977: if (must_add_seg) {
1978: if (override < 0) {
1979: if (base == R_EBP || base == R_ESP)
1980: override = R_SS;
1981: else
1982: override = R_DS;
1983: }
1984: #ifdef TARGET_X86_64
1985: if (s->aflag == 2) {
1.1.1.7 ! root 1986: gen_op_addq_A0_seg(override);
1.1.1.6 root 1987: } else
1.1 root 1988: #endif
1989: {
1.1.1.7 ! root 1990: gen_op_addl_A0_seg(override);
1.1 root 1991: }
1992: }
1993: } else {
1994: switch (mod) {
1995: case 0:
1996: if (rm == 6) {
1997: disp = lduw_code(s->pc);
1998: s->pc += 2;
1999: gen_op_movl_A0_im(disp);
2000: rm = 0; /* avoid SS override */
2001: goto no_rm;
2002: } else {
2003: disp = 0;
2004: }
2005: break;
2006: case 1:
2007: disp = (int8_t)ldub_code(s->pc++);
2008: break;
2009: default:
2010: case 2:
2011: disp = lduw_code(s->pc);
2012: s->pc += 2;
2013: break;
2014: }
2015: switch(rm) {
2016: case 0:
1.1.1.7 ! root 2017: gen_op_movl_A0_reg(R_EBX);
! 2018: gen_op_addl_A0_reg_sN(0, R_ESI);
1.1 root 2019: break;
2020: case 1:
1.1.1.7 ! root 2021: gen_op_movl_A0_reg(R_EBX);
! 2022: gen_op_addl_A0_reg_sN(0, R_EDI);
1.1 root 2023: break;
2024: case 2:
1.1.1.7 ! root 2025: gen_op_movl_A0_reg(R_EBP);
! 2026: gen_op_addl_A0_reg_sN(0, R_ESI);
1.1 root 2027: break;
2028: case 3:
1.1.1.7 ! root 2029: gen_op_movl_A0_reg(R_EBP);
! 2030: gen_op_addl_A0_reg_sN(0, R_EDI);
1.1 root 2031: break;
2032: case 4:
1.1.1.7 ! root 2033: gen_op_movl_A0_reg(R_ESI);
1.1 root 2034: break;
2035: case 5:
1.1.1.7 ! root 2036: gen_op_movl_A0_reg(R_EDI);
1.1 root 2037: break;
2038: case 6:
1.1.1.7 ! root 2039: gen_op_movl_A0_reg(R_EBP);
1.1 root 2040: break;
2041: default:
2042: case 7:
1.1.1.7 ! root 2043: gen_op_movl_A0_reg(R_EBX);
1.1 root 2044: break;
2045: }
2046: if (disp != 0)
2047: gen_op_addl_A0_im(disp);
2048: gen_op_andl_A0_ffff();
2049: no_rm:
2050: if (must_add_seg) {
2051: if (override < 0) {
2052: if (rm == 2 || rm == 3 || rm == 6)
2053: override = R_SS;
2054: else
2055: override = R_DS;
2056: }
1.1.1.7 ! root 2057: gen_op_addl_A0_seg(override);
1.1 root 2058: }
2059: }
2060:
2061: opreg = OR_A0;
2062: disp = 0;
2063: *reg_ptr = opreg;
2064: *offset_ptr = disp;
2065: }
2066:
1.1.1.5 root 2067: static void gen_nop_modrm(DisasContext *s, int modrm)
2068: {
2069: int mod, rm, base, code;
2070:
2071: mod = (modrm >> 6) & 3;
2072: if (mod == 3)
2073: return;
2074: rm = modrm & 7;
2075:
2076: if (s->aflag) {
2077:
2078: base = rm;
1.1.1.6 root 2079:
1.1.1.5 root 2080: if (base == 4) {
2081: code = ldub_code(s->pc++);
2082: base = (code & 7);
2083: }
1.1.1.6 root 2084:
1.1.1.5 root 2085: switch (mod) {
2086: case 0:
2087: if (base == 5) {
2088: s->pc += 4;
2089: }
2090: break;
2091: case 1:
2092: s->pc++;
2093: break;
2094: default:
2095: case 2:
2096: s->pc += 4;
2097: break;
2098: }
2099: } else {
2100: switch (mod) {
2101: case 0:
2102: if (rm == 6) {
2103: s->pc += 2;
2104: }
2105: break;
2106: case 1:
2107: s->pc++;
2108: break;
2109: default:
2110: case 2:
2111: s->pc += 2;
2112: break;
2113: }
2114: }
2115: }
2116:
1.1 root 2117: /* used for LEA and MOV AX, mem */
2118: static void gen_add_A0_ds_seg(DisasContext *s)
2119: {
2120: int override, must_add_seg;
2121: must_add_seg = s->addseg;
2122: override = R_DS;
2123: if (s->override >= 0) {
2124: override = s->override;
2125: must_add_seg = 1;
2126: } else {
2127: override = R_DS;
2128: }
2129: if (must_add_seg) {
2130: #ifdef TARGET_X86_64
2131: if (CODE64(s)) {
1.1.1.7 ! root 2132: gen_op_addq_A0_seg(override);
1.1.1.6 root 2133: } else
1.1 root 2134: #endif
2135: {
1.1.1.7 ! root 2136: gen_op_addl_A0_seg(override);
1.1 root 2137: }
2138: }
2139: }
2140:
1.1.1.7 ! root 2141: /* generate modrm memory load or store of 'reg'. TMP0 is used if reg ==
1.1 root 2142: OR_TMP0 */
2143: static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
2144: {
2145: int mod, rm, opreg, disp;
2146:
2147: mod = (modrm >> 6) & 3;
2148: rm = (modrm & 7) | REX_B(s);
2149: if (mod == 3) {
2150: if (is_store) {
2151: if (reg != OR_TMP0)
1.1.1.7 ! root 2152: gen_op_mov_TN_reg(ot, 0, reg);
! 2153: gen_op_mov_reg_T0(ot, rm);
1.1 root 2154: } else {
1.1.1.7 ! root 2155: gen_op_mov_TN_reg(ot, 0, rm);
1.1 root 2156: if (reg != OR_TMP0)
1.1.1.7 ! root 2157: gen_op_mov_reg_T0(ot, reg);
1.1 root 2158: }
2159: } else {
2160: gen_lea_modrm(s, modrm, &opreg, &disp);
2161: if (is_store) {
2162: if (reg != OR_TMP0)
1.1.1.7 ! root 2163: gen_op_mov_TN_reg(ot, 0, reg);
! 2164: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 2165: } else {
1.1.1.7 ! root 2166: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 2167: if (reg != OR_TMP0)
1.1.1.7 ! root 2168: gen_op_mov_reg_T0(ot, reg);
1.1 root 2169: }
2170: }
2171: }
2172:
2173: static inline uint32_t insn_get(DisasContext *s, int ot)
2174: {
2175: uint32_t ret;
2176:
2177: switch(ot) {
2178: case OT_BYTE:
2179: ret = ldub_code(s->pc);
2180: s->pc++;
2181: break;
2182: case OT_WORD:
2183: ret = lduw_code(s->pc);
2184: s->pc += 2;
2185: break;
2186: default:
2187: case OT_LONG:
2188: ret = ldl_code(s->pc);
2189: s->pc += 4;
2190: break;
2191: }
2192: return ret;
2193: }
2194:
2195: static inline int insn_const_size(unsigned int ot)
2196: {
2197: if (ot <= OT_LONG)
2198: return 1 << ot;
2199: else
2200: return 4;
2201: }
2202:
1.1.1.2 root 2203: static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
2204: {
2205: TranslationBlock *tb;
2206: target_ulong pc;
2207:
2208: pc = s->cs_base + eip;
2209: tb = s->tb;
2210: /* NOTE: we handle the case where the TB spans two pages here */
2211: if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
2212: (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) {
2213: /* jump to same page: we can use a direct jump */
1.1.1.7 ! root 2214: tcg_gen_goto_tb(tb_num);
1.1.1.2 root 2215: gen_jmp_im(eip);
1.1.1.7 ! root 2216: tcg_gen_exit_tb((long)tb + tb_num);
1.1.1.2 root 2217: } else {
2218: /* jump to another page: currently not optimized */
2219: gen_jmp_im(eip);
2220: gen_eob(s);
2221: }
2222: }
2223:
1.1.1.6 root 2224: static inline void gen_jcc(DisasContext *s, int b,
1.1 root 2225: target_ulong val, target_ulong next_eip)
2226: {
1.1.1.7 ! root 2227: int l1, l2, cc_op;
1.1.1.6 root 2228:
1.1.1.7 ! root 2229: cc_op = s->cc_op;
! 2230: if (s->cc_op != CC_OP_DYNAMIC) {
! 2231: gen_op_set_cc_op(s->cc_op);
! 2232: s->cc_op = CC_OP_DYNAMIC;
! 2233: }
1.1 root 2234: if (s->jmp_opt) {
2235: l1 = gen_new_label();
1.1.1.7 ! root 2236: gen_jcc1(s, cc_op, b, l1);
! 2237:
1.1.1.2 root 2238: gen_goto_tb(s, 0, next_eip);
1.1 root 2239:
2240: gen_set_label(l1);
1.1.1.2 root 2241: gen_goto_tb(s, 1, val);
1.1 root 2242: s->is_jmp = 3;
2243: } else {
2244:
2245: l1 = gen_new_label();
2246: l2 = gen_new_label();
1.1.1.7 ! root 2247: gen_jcc1(s, cc_op, b, l1);
! 2248:
1.1 root 2249: gen_jmp_im(next_eip);
1.1.1.7 ! root 2250: tcg_gen_br(l2);
! 2251:
1.1 root 2252: gen_set_label(l1);
2253: gen_jmp_im(val);
2254: gen_set_label(l2);
2255: gen_eob(s);
2256: }
2257: }
2258:
2259: static void gen_setcc(DisasContext *s, int b)
2260: {
1.1.1.7 ! root 2261: int inv, jcc_op, l1;
! 2262: TCGv t0;
1.1.1.6 root 2263:
1.1.1.7 ! root 2264: if (is_fast_jcc_case(s, b)) {
! 2265: /* nominal case: we use a jump */
! 2266: /* XXX: make it faster by adding new instructions in TCG */
! 2267: t0 = tcg_temp_local_new();
! 2268: tcg_gen_movi_tl(t0, 0);
! 2269: l1 = gen_new_label();
! 2270: gen_jcc1(s, s->cc_op, b ^ 1, l1);
! 2271: tcg_gen_movi_tl(t0, 1);
! 2272: gen_set_label(l1);
! 2273: tcg_gen_mov_tl(cpu_T[0], t0);
! 2274: tcg_temp_free(t0);
! 2275: } else {
! 2276: /* slow case: it is more efficient not to generate a jump,
! 2277: although it is questionnable whether this optimization is
! 2278: worth to */
! 2279: inv = b & 1;
! 2280: jcc_op = (b >> 1) & 7;
! 2281: gen_setcc_slow_T0(s, jcc_op);
! 2282: if (inv) {
! 2283: tcg_gen_xori_tl(cpu_T[0], cpu_T[0], 1);
1.1 root 2284: }
2285: }
2286: }
2287:
1.1.1.7 ! root 2288: static inline void gen_op_movl_T0_seg(int seg_reg)
! 2289: {
! 2290: tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
! 2291: offsetof(CPUX86State,segs[seg_reg].selector));
! 2292: }
! 2293:
! 2294: static inline void gen_op_movl_seg_T0_vm(int seg_reg)
! 2295: {
! 2296: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xffff);
! 2297: tcg_gen_st32_tl(cpu_T[0], cpu_env,
! 2298: offsetof(CPUX86State,segs[seg_reg].selector));
! 2299: tcg_gen_shli_tl(cpu_T[0], cpu_T[0], 4);
! 2300: tcg_gen_st_tl(cpu_T[0], cpu_env,
! 2301: offsetof(CPUX86State,segs[seg_reg].base));
! 2302: }
! 2303:
1.1 root 2304: /* move T0 to seg_reg and compute if the CPU state may change. Never
2305: call this function with seg_reg == R_CS */
2306: static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip)
2307: {
2308: if (s->pe && !s->vm86) {
2309: /* XXX: optimize by finding processor state dynamically */
2310: if (s->cc_op != CC_OP_DYNAMIC)
2311: gen_op_set_cc_op(s->cc_op);
2312: gen_jmp_im(cur_eip);
1.1.1.7 ! root 2313: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 2314: gen_helper_load_seg(tcg_const_i32(seg_reg), cpu_tmp2_i32);
1.1 root 2315: /* abort translation because the addseg value may change or
2316: because ss32 may change. For R_SS, translation must always
2317: stop as a special handling must be done to disable hardware
2318: interrupts for the next instruction */
2319: if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
2320: s->is_jmp = 3;
2321: } else {
1.1.1.7 ! root 2322: gen_op_movl_seg_T0_vm(seg_reg);
1.1 root 2323: if (seg_reg == R_SS)
2324: s->is_jmp = 3;
2325: }
2326: }
2327:
1.1.1.6 root 2328: static inline int svm_is_rep(int prefixes)
2329: {
2330: return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
2331: }
2332:
1.1.1.7 ! root 2333: static inline void
1.1.1.6 root 2334: gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
1.1.1.7 ! root 2335: uint32_t type, uint64_t param)
1.1.1.6 root 2336: {
1.1.1.7 ! root 2337: /* no SVM activated; fast case */
! 2338: if (likely(!(s->flags & HF_SVMI_MASK)))
! 2339: return;
! 2340: if (s->cc_op != CC_OP_DYNAMIC)
! 2341: gen_op_set_cc_op(s->cc_op);
! 2342: gen_jmp_im(pc_start - s->cs_base);
! 2343: gen_helper_svm_check_intercept_param(tcg_const_i32(type),
! 2344: tcg_const_i64(param));
1.1.1.6 root 2345: }
2346:
1.1.1.7 ! root 2347: static inline void
1.1.1.6 root 2348: gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type)
2349: {
1.1.1.7 ! root 2350: gen_svm_check_intercept_param(s, pc_start, type, 0);
1.1.1.6 root 2351: }
2352:
1.1 root 2353: static inline void gen_stack_update(DisasContext *s, int addend)
2354: {
2355: #ifdef TARGET_X86_64
2356: if (CODE64(s)) {
1.1.1.7 ! root 2357: gen_op_add_reg_im(2, R_ESP, addend);
1.1 root 2358: } else
2359: #endif
2360: if (s->ss32) {
1.1.1.7 ! root 2361: gen_op_add_reg_im(1, R_ESP, addend);
1.1 root 2362: } else {
1.1.1.7 ! root 2363: gen_op_add_reg_im(0, R_ESP, addend);
1.1 root 2364: }
2365: }
2366:
2367: /* generate a push. It depends on ss32, addseg and dflag */
2368: static void gen_push_T0(DisasContext *s)
2369: {
2370: #ifdef TARGET_X86_64
2371: if (CODE64(s)) {
1.1.1.7 ! root 2372: gen_op_movq_A0_reg(R_ESP);
1.1 root 2373: if (s->dflag) {
1.1.1.7 ! root 2374: gen_op_addq_A0_im(-8);
! 2375: gen_op_st_T0_A0(OT_QUAD + s->mem_index);
1.1 root 2376: } else {
1.1.1.7 ! root 2377: gen_op_addq_A0_im(-2);
! 2378: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 2379: }
1.1.1.7 ! root 2380: gen_op_mov_reg_A0(2, R_ESP);
1.1.1.6 root 2381: } else
1.1 root 2382: #endif
2383: {
1.1.1.7 ! root 2384: gen_op_movl_A0_reg(R_ESP);
1.1 root 2385: if (!s->dflag)
1.1.1.7 ! root 2386: gen_op_addl_A0_im(-2);
1.1 root 2387: else
1.1.1.7 ! root 2388: gen_op_addl_A0_im(-4);
1.1 root 2389: if (s->ss32) {
2390: if (s->addseg) {
1.1.1.7 ! root 2391: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
! 2392: gen_op_addl_A0_seg(R_SS);
1.1 root 2393: }
2394: } else {
2395: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2396: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
! 2397: gen_op_addl_A0_seg(R_SS);
1.1 root 2398: }
1.1.1.7 ! root 2399: gen_op_st_T0_A0(s->dflag + 1 + s->mem_index);
1.1 root 2400: if (s->ss32 && !s->addseg)
1.1.1.7 ! root 2401: gen_op_mov_reg_A0(1, R_ESP);
1.1 root 2402: else
1.1.1.7 ! root 2403: gen_op_mov_reg_T1(s->ss32 + 1, R_ESP);
1.1 root 2404: }
2405: }
2406:
2407: /* generate a push. It depends on ss32, addseg and dflag */
2408: /* slower version for T1, only used for call Ev */
2409: static void gen_push_T1(DisasContext *s)
2410: {
2411: #ifdef TARGET_X86_64
2412: if (CODE64(s)) {
1.1.1.7 ! root 2413: gen_op_movq_A0_reg(R_ESP);
1.1 root 2414: if (s->dflag) {
1.1.1.7 ! root 2415: gen_op_addq_A0_im(-8);
! 2416: gen_op_st_T1_A0(OT_QUAD + s->mem_index);
1.1 root 2417: } else {
1.1.1.7 ! root 2418: gen_op_addq_A0_im(-2);
! 2419: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 2420: }
1.1.1.7 ! root 2421: gen_op_mov_reg_A0(2, R_ESP);
1.1.1.6 root 2422: } else
1.1 root 2423: #endif
2424: {
1.1.1.7 ! root 2425: gen_op_movl_A0_reg(R_ESP);
1.1 root 2426: if (!s->dflag)
1.1.1.7 ! root 2427: gen_op_addl_A0_im(-2);
1.1 root 2428: else
1.1.1.7 ! root 2429: gen_op_addl_A0_im(-4);
1.1 root 2430: if (s->ss32) {
2431: if (s->addseg) {
1.1.1.7 ! root 2432: gen_op_addl_A0_seg(R_SS);
1.1 root 2433: }
2434: } else {
2435: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2436: gen_op_addl_A0_seg(R_SS);
1.1 root 2437: }
1.1.1.7 ! root 2438: gen_op_st_T1_A0(s->dflag + 1 + s->mem_index);
1.1.1.6 root 2439:
1.1 root 2440: if (s->ss32 && !s->addseg)
1.1.1.7 ! root 2441: gen_op_mov_reg_A0(1, R_ESP);
1.1 root 2442: else
2443: gen_stack_update(s, (-2) << s->dflag);
2444: }
2445: }
2446:
2447: /* two step pop is necessary for precise exceptions */
2448: static void gen_pop_T0(DisasContext *s)
2449: {
2450: #ifdef TARGET_X86_64
2451: if (CODE64(s)) {
1.1.1.7 ! root 2452: gen_op_movq_A0_reg(R_ESP);
! 2453: gen_op_ld_T0_A0((s->dflag ? OT_QUAD : OT_WORD) + s->mem_index);
1.1.1.6 root 2454: } else
1.1 root 2455: #endif
2456: {
1.1.1.7 ! root 2457: gen_op_movl_A0_reg(R_ESP);
1.1 root 2458: if (s->ss32) {
2459: if (s->addseg)
1.1.1.7 ! root 2460: gen_op_addl_A0_seg(R_SS);
1.1 root 2461: } else {
2462: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2463: gen_op_addl_A0_seg(R_SS);
1.1 root 2464: }
1.1.1.7 ! root 2465: gen_op_ld_T0_A0(s->dflag + 1 + s->mem_index);
1.1 root 2466: }
2467: }
2468:
2469: static void gen_pop_update(DisasContext *s)
2470: {
2471: #ifdef TARGET_X86_64
2472: if (CODE64(s) && s->dflag) {
2473: gen_stack_update(s, 8);
2474: } else
2475: #endif
2476: {
2477: gen_stack_update(s, 2 << s->dflag);
2478: }
2479: }
2480:
2481: static void gen_stack_A0(DisasContext *s)
2482: {
1.1.1.7 ! root 2483: gen_op_movl_A0_reg(R_ESP);
1.1 root 2484: if (!s->ss32)
2485: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2486: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
1.1 root 2487: if (s->addseg)
1.1.1.7 ! root 2488: gen_op_addl_A0_seg(R_SS);
1.1 root 2489: }
2490:
2491: /* NOTE: wrap around in 16 bit not fully handled */
2492: static void gen_pusha(DisasContext *s)
2493: {
2494: int i;
1.1.1.7 ! root 2495: gen_op_movl_A0_reg(R_ESP);
1.1 root 2496: gen_op_addl_A0_im(-16 << s->dflag);
2497: if (!s->ss32)
2498: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2499: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
1.1 root 2500: if (s->addseg)
1.1.1.7 ! root 2501: gen_op_addl_A0_seg(R_SS);
1.1 root 2502: for(i = 0;i < 8; i++) {
1.1.1.7 ! root 2503: gen_op_mov_TN_reg(OT_LONG, 0, 7 - i);
! 2504: gen_op_st_T0_A0(OT_WORD + s->dflag + s->mem_index);
1.1 root 2505: gen_op_addl_A0_im(2 << s->dflag);
2506: }
1.1.1.7 ! root 2507: gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
1.1 root 2508: }
2509:
2510: /* NOTE: wrap around in 16 bit not fully handled */
2511: static void gen_popa(DisasContext *s)
2512: {
2513: int i;
1.1.1.7 ! root 2514: gen_op_movl_A0_reg(R_ESP);
1.1 root 2515: if (!s->ss32)
2516: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2517: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
! 2518: tcg_gen_addi_tl(cpu_T[1], cpu_T[1], 16 << s->dflag);
1.1 root 2519: if (s->addseg)
1.1.1.7 ! root 2520: gen_op_addl_A0_seg(R_SS);
1.1 root 2521: for(i = 0;i < 8; i++) {
2522: /* ESP is not reloaded */
2523: if (i != 3) {
1.1.1.7 ! root 2524: gen_op_ld_T0_A0(OT_WORD + s->dflag + s->mem_index);
! 2525: gen_op_mov_reg_T0(OT_WORD + s->dflag, 7 - i);
1.1 root 2526: }
2527: gen_op_addl_A0_im(2 << s->dflag);
2528: }
1.1.1.7 ! root 2529: gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
1.1 root 2530: }
2531:
2532: static void gen_enter(DisasContext *s, int esp_addend, int level)
2533: {
2534: int ot, opsize;
2535:
2536: level &= 0x1f;
2537: #ifdef TARGET_X86_64
2538: if (CODE64(s)) {
2539: ot = s->dflag ? OT_QUAD : OT_WORD;
2540: opsize = 1 << ot;
1.1.1.6 root 2541:
1.1.1.7 ! root 2542: gen_op_movl_A0_reg(R_ESP);
1.1 root 2543: gen_op_addq_A0_im(-opsize);
1.1.1.7 ! root 2544: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
1.1 root 2545:
2546: /* push bp */
1.1.1.7 ! root 2547: gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
! 2548: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 2549: if (level) {
1.1.1.7 ! root 2550: /* XXX: must save state */
! 2551: gen_helper_enter64_level(tcg_const_i32(level),
! 2552: tcg_const_i32((ot == OT_QUAD)),
! 2553: cpu_T[1]);
! 2554: }
! 2555: gen_op_mov_reg_T1(ot, R_EBP);
! 2556: tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level));
! 2557: gen_op_mov_reg_T1(OT_QUAD, R_ESP);
1.1.1.6 root 2558: } else
1.1 root 2559: #endif
2560: {
2561: ot = s->dflag + OT_WORD;
2562: opsize = 2 << s->dflag;
1.1.1.6 root 2563:
1.1.1.7 ! root 2564: gen_op_movl_A0_reg(R_ESP);
1.1 root 2565: gen_op_addl_A0_im(-opsize);
2566: if (!s->ss32)
2567: gen_op_andl_A0_ffff();
1.1.1.7 ! root 2568: tcg_gen_mov_tl(cpu_T[1], cpu_A0);
1.1 root 2569: if (s->addseg)
1.1.1.7 ! root 2570: gen_op_addl_A0_seg(R_SS);
1.1 root 2571: /* push bp */
1.1.1.7 ! root 2572: gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
! 2573: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 2574: if (level) {
1.1.1.7 ! root 2575: /* XXX: must save state */
! 2576: gen_helper_enter_level(tcg_const_i32(level),
! 2577: tcg_const_i32(s->dflag),
! 2578: cpu_T[1]);
! 2579: }
! 2580: gen_op_mov_reg_T1(ot, R_EBP);
! 2581: tcg_gen_addi_tl(cpu_T[1], cpu_T[1], -esp_addend + (-opsize * level));
! 2582: gen_op_mov_reg_T1(OT_WORD + s->ss32, R_ESP);
1.1 root 2583: }
2584: }
2585:
2586: static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
2587: {
2588: if (s->cc_op != CC_OP_DYNAMIC)
2589: gen_op_set_cc_op(s->cc_op);
2590: gen_jmp_im(cur_eip);
1.1.1.7 ! root 2591: gen_helper_raise_exception(tcg_const_i32(trapno));
1.1 root 2592: s->is_jmp = 3;
2593: }
2594:
2595: /* an interrupt is different from an exception because of the
1.1.1.6 root 2596: privilege checks */
2597: static void gen_interrupt(DisasContext *s, int intno,
1.1 root 2598: target_ulong cur_eip, target_ulong next_eip)
2599: {
2600: if (s->cc_op != CC_OP_DYNAMIC)
2601: gen_op_set_cc_op(s->cc_op);
2602: gen_jmp_im(cur_eip);
1.1.1.7 ! root 2603: gen_helper_raise_interrupt(tcg_const_i32(intno),
! 2604: tcg_const_i32(next_eip - cur_eip));
1.1 root 2605: s->is_jmp = 3;
2606: }
2607:
2608: static void gen_debug(DisasContext *s, target_ulong cur_eip)
2609: {
2610: if (s->cc_op != CC_OP_DYNAMIC)
2611: gen_op_set_cc_op(s->cc_op);
2612: gen_jmp_im(cur_eip);
1.1.1.7 ! root 2613: gen_helper_debug();
1.1 root 2614: s->is_jmp = 3;
2615: }
2616:
2617: /* generate a generic end of block. Trace exception is also generated
2618: if needed */
2619: static void gen_eob(DisasContext *s)
2620: {
2621: if (s->cc_op != CC_OP_DYNAMIC)
2622: gen_op_set_cc_op(s->cc_op);
2623: if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
1.1.1.7 ! root 2624: gen_helper_reset_inhibit_irq();
1.1 root 2625: }
2626: if (s->singlestep_enabled) {
1.1.1.7 ! root 2627: gen_helper_debug();
1.1 root 2628: } else if (s->tf) {
1.1.1.7 ! root 2629: gen_helper_single_step();
1.1 root 2630: } else {
1.1.1.7 ! root 2631: tcg_gen_exit_tb(0);
1.1 root 2632: }
2633: s->is_jmp = 3;
2634: }
2635:
2636: /* generate a jump to eip. No segment change must happen before as a
2637: direct call to the next block may occur */
2638: static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
2639: {
2640: if (s->jmp_opt) {
1.1.1.2 root 2641: if (s->cc_op != CC_OP_DYNAMIC) {
1.1 root 2642: gen_op_set_cc_op(s->cc_op);
1.1.1.2 root 2643: s->cc_op = CC_OP_DYNAMIC;
2644: }
2645: gen_goto_tb(s, tb_num, eip);
1.1 root 2646: s->is_jmp = 3;
2647: } else {
2648: gen_jmp_im(eip);
2649: gen_eob(s);
2650: }
2651: }
2652:
2653: static void gen_jmp(DisasContext *s, target_ulong eip)
2654: {
2655: gen_jmp_tb(s, eip, 0);
2656: }
2657:
1.1.1.7 ! root 2658: static inline void gen_ldq_env_A0(int idx, int offset)
1.1 root 2659: {
1.1.1.7 ! root 2660: int mem_index = (idx >> 2) - 1;
! 2661: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index);
! 2662: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset);
1.1 root 2663: }
2664:
1.1.1.7 ! root 2665: static inline void gen_stq_env_A0(int idx, int offset)
1.1 root 2666: {
1.1.1.7 ! root 2667: int mem_index = (idx >> 2) - 1;
! 2668: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset);
! 2669: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index);
1.1 root 2670: }
2671:
1.1.1.7 ! root 2672: static inline void gen_ldo_env_A0(int idx, int offset)
1.1 root 2673: {
1.1.1.7 ! root 2674: int mem_index = (idx >> 2) - 1;
! 2675: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0, mem_index);
! 2676: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0)));
! 2677: tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8);
! 2678: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_tmp0, mem_index);
! 2679: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1)));
1.1 root 2680: }
2681:
1.1.1.7 ! root 2682: static inline void gen_sto_env_A0(int idx, int offset)
! 2683: {
! 2684: int mem_index = (idx >> 2) - 1;
! 2685: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(0)));
! 2686: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0, mem_index);
! 2687: tcg_gen_addi_tl(cpu_tmp0, cpu_A0, 8);
! 2688: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, offset + offsetof(XMMReg, XMM_Q(1)));
! 2689: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_tmp0, mem_index);
! 2690: }
1.1 root 2691:
1.1.1.7 ! root 2692: static inline void gen_op_movo(int d_offset, int s_offset)
! 2693: {
! 2694: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset);
! 2695: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
! 2696: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset + 8);
! 2697: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset + 8);
! 2698: }
1.1 root 2699:
1.1.1.7 ! root 2700: static inline void gen_op_movq(int d_offset, int s_offset)
! 2701: {
! 2702: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env, s_offset);
! 2703: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
! 2704: }
1.1 root 2705:
1.1.1.7 ! root 2706: static inline void gen_op_movl(int d_offset, int s_offset)
! 2707: {
! 2708: tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env, s_offset);
! 2709: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, d_offset);
! 2710: }
! 2711:
! 2712: static inline void gen_op_movq_env_0(int d_offset)
! 2713: {
! 2714: tcg_gen_movi_i64(cpu_tmp1_i64, 0);
! 2715: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env, d_offset);
! 2716: }
1.1 root 2717:
1.1.1.7 ! root 2718: #define SSE_SPECIAL ((void *)1)
! 2719: #define SSE_DUMMY ((void *)2)
1.1 root 2720:
1.1.1.7 ! root 2721: #define MMX_OP2(x) { gen_helper_ ## x ## _mmx, gen_helper_ ## x ## _xmm }
! 2722: #define SSE_FOP(x) { gen_helper_ ## x ## ps, gen_helper_ ## x ## pd, \
! 2723: gen_helper_ ## x ## ss, gen_helper_ ## x ## sd, }
1.1 root 2724:
1.1.1.7 ! root 2725: static void *sse_op_table1[256][4] = {
! 2726: /* 3DNow! extensions */
! 2727: [0x0e] = { SSE_DUMMY }, /* femms */
! 2728: [0x0f] = { SSE_DUMMY }, /* pf... */
1.1 root 2729: /* pure SSE operations */
2730: [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
2731: [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
1.1.1.3 root 2732: [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */
1.1 root 2733: [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */
1.1.1.7 ! root 2734: [0x14] = { gen_helper_punpckldq_xmm, gen_helper_punpcklqdq_xmm },
! 2735: [0x15] = { gen_helper_punpckhdq_xmm, gen_helper_punpckhqdq_xmm },
1.1 root 2736: [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */
2737: [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */
2738:
2739: [0x28] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
2740: [0x29] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
2741: [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */
2742: [0x2b] = { SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd */
2743: [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */
2744: [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */
1.1.1.7 ! root 2745: [0x2e] = { gen_helper_ucomiss, gen_helper_ucomisd },
! 2746: [0x2f] = { gen_helper_comiss, gen_helper_comisd },
1.1 root 2747: [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */
2748: [0x51] = SSE_FOP(sqrt),
1.1.1.7 ! root 2749: [0x52] = { gen_helper_rsqrtps, NULL, gen_helper_rsqrtss, NULL },
! 2750: [0x53] = { gen_helper_rcpps, NULL, gen_helper_rcpss, NULL },
! 2751: [0x54] = { gen_helper_pand_xmm, gen_helper_pand_xmm }, /* andps, andpd */
! 2752: [0x55] = { gen_helper_pandn_xmm, gen_helper_pandn_xmm }, /* andnps, andnpd */
! 2753: [0x56] = { gen_helper_por_xmm, gen_helper_por_xmm }, /* orps, orpd */
! 2754: [0x57] = { gen_helper_pxor_xmm, gen_helper_pxor_xmm }, /* xorps, xorpd */
1.1 root 2755: [0x58] = SSE_FOP(add),
2756: [0x59] = SSE_FOP(mul),
1.1.1.7 ! root 2757: [0x5a] = { gen_helper_cvtps2pd, gen_helper_cvtpd2ps,
! 2758: gen_helper_cvtss2sd, gen_helper_cvtsd2ss },
! 2759: [0x5b] = { gen_helper_cvtdq2ps, gen_helper_cvtps2dq, gen_helper_cvttps2dq },
1.1 root 2760: [0x5c] = SSE_FOP(sub),
2761: [0x5d] = SSE_FOP(min),
2762: [0x5e] = SSE_FOP(div),
2763: [0x5f] = SSE_FOP(max),
2764:
2765: [0xc2] = SSE_FOP(cmpeq),
1.1.1.7 ! root 2766: [0xc6] = { gen_helper_shufps, gen_helper_shufpd },
! 2767:
! 2768: [0x38] = { SSE_SPECIAL, SSE_SPECIAL, NULL, SSE_SPECIAL }, /* SSSE3/SSE4 */
! 2769: [0x3a] = { SSE_SPECIAL, SSE_SPECIAL }, /* SSSE3/SSE4 */
1.1 root 2770:
2771: /* MMX ops and their SSE extensions */
2772: [0x60] = MMX_OP2(punpcklbw),
2773: [0x61] = MMX_OP2(punpcklwd),
2774: [0x62] = MMX_OP2(punpckldq),
2775: [0x63] = MMX_OP2(packsswb),
2776: [0x64] = MMX_OP2(pcmpgtb),
2777: [0x65] = MMX_OP2(pcmpgtw),
2778: [0x66] = MMX_OP2(pcmpgtl),
2779: [0x67] = MMX_OP2(packuswb),
2780: [0x68] = MMX_OP2(punpckhbw),
2781: [0x69] = MMX_OP2(punpckhwd),
2782: [0x6a] = MMX_OP2(punpckhdq),
2783: [0x6b] = MMX_OP2(packssdw),
1.1.1.7 ! root 2784: [0x6c] = { NULL, gen_helper_punpcklqdq_xmm },
! 2785: [0x6d] = { NULL, gen_helper_punpckhqdq_xmm },
1.1 root 2786: [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
2787: [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
1.1.1.7 ! root 2788: [0x70] = { gen_helper_pshufw_mmx,
! 2789: gen_helper_pshufd_xmm,
! 2790: gen_helper_pshufhw_xmm,
! 2791: gen_helper_pshuflw_xmm },
1.1 root 2792: [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
2793: [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
2794: [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
2795: [0x74] = MMX_OP2(pcmpeqb),
2796: [0x75] = MMX_OP2(pcmpeqw),
2797: [0x76] = MMX_OP2(pcmpeql),
1.1.1.7 ! root 2798: [0x77] = { SSE_DUMMY }, /* emms */
! 2799: [0x7c] = { NULL, gen_helper_haddpd, NULL, gen_helper_haddps },
! 2800: [0x7d] = { NULL, gen_helper_hsubpd, NULL, gen_helper_hsubps },
1.1 root 2801: [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */
2802: [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */
2803: [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */
2804: [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */
1.1.1.7 ! root 2805: [0xd0] = { NULL, gen_helper_addsubpd, NULL, gen_helper_addsubps },
1.1 root 2806: [0xd1] = MMX_OP2(psrlw),
2807: [0xd2] = MMX_OP2(psrld),
2808: [0xd3] = MMX_OP2(psrlq),
2809: [0xd4] = MMX_OP2(paddq),
2810: [0xd5] = MMX_OP2(pmullw),
2811: [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
2812: [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */
2813: [0xd8] = MMX_OP2(psubusb),
2814: [0xd9] = MMX_OP2(psubusw),
2815: [0xda] = MMX_OP2(pminub),
2816: [0xdb] = MMX_OP2(pand),
2817: [0xdc] = MMX_OP2(paddusb),
2818: [0xdd] = MMX_OP2(paddusw),
2819: [0xde] = MMX_OP2(pmaxub),
2820: [0xdf] = MMX_OP2(pandn),
2821: [0xe0] = MMX_OP2(pavgb),
2822: [0xe1] = MMX_OP2(psraw),
2823: [0xe2] = MMX_OP2(psrad),
2824: [0xe3] = MMX_OP2(pavgw),
2825: [0xe4] = MMX_OP2(pmulhuw),
2826: [0xe5] = MMX_OP2(pmulhw),
1.1.1.7 ! root 2827: [0xe6] = { NULL, gen_helper_cvttpd2dq, gen_helper_cvtdq2pd, gen_helper_cvtpd2dq },
1.1 root 2828: [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */
2829: [0xe8] = MMX_OP2(psubsb),
2830: [0xe9] = MMX_OP2(psubsw),
2831: [0xea] = MMX_OP2(pminsw),
2832: [0xeb] = MMX_OP2(por),
2833: [0xec] = MMX_OP2(paddsb),
2834: [0xed] = MMX_OP2(paddsw),
2835: [0xee] = MMX_OP2(pmaxsw),
2836: [0xef] = MMX_OP2(pxor),
1.1.1.3 root 2837: [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */
1.1 root 2838: [0xf1] = MMX_OP2(psllw),
2839: [0xf2] = MMX_OP2(pslld),
2840: [0xf3] = MMX_OP2(psllq),
2841: [0xf4] = MMX_OP2(pmuludq),
2842: [0xf5] = MMX_OP2(pmaddwd),
2843: [0xf6] = MMX_OP2(psadbw),
2844: [0xf7] = MMX_OP2(maskmov),
2845: [0xf8] = MMX_OP2(psubb),
2846: [0xf9] = MMX_OP2(psubw),
2847: [0xfa] = MMX_OP2(psubl),
2848: [0xfb] = MMX_OP2(psubq),
2849: [0xfc] = MMX_OP2(paddb),
2850: [0xfd] = MMX_OP2(paddw),
2851: [0xfe] = MMX_OP2(paddl),
2852: };
2853:
1.1.1.7 ! root 2854: static void *sse_op_table2[3 * 8][2] = {
1.1 root 2855: [0 + 2] = MMX_OP2(psrlw),
2856: [0 + 4] = MMX_OP2(psraw),
2857: [0 + 6] = MMX_OP2(psllw),
2858: [8 + 2] = MMX_OP2(psrld),
2859: [8 + 4] = MMX_OP2(psrad),
2860: [8 + 6] = MMX_OP2(pslld),
2861: [16 + 2] = MMX_OP2(psrlq),
1.1.1.7 ! root 2862: [16 + 3] = { NULL, gen_helper_psrldq_xmm },
1.1 root 2863: [16 + 6] = MMX_OP2(psllq),
1.1.1.7 ! root 2864: [16 + 7] = { NULL, gen_helper_pslldq_xmm },
1.1 root 2865: };
2866:
1.1.1.7 ! root 2867: static void *sse_op_table3[4 * 3] = {
! 2868: gen_helper_cvtsi2ss,
! 2869: gen_helper_cvtsi2sd,
! 2870: X86_64_ONLY(gen_helper_cvtsq2ss),
! 2871: X86_64_ONLY(gen_helper_cvtsq2sd),
! 2872:
! 2873: gen_helper_cvttss2si,
! 2874: gen_helper_cvttsd2si,
! 2875: X86_64_ONLY(gen_helper_cvttss2sq),
! 2876: X86_64_ONLY(gen_helper_cvttsd2sq),
! 2877:
! 2878: gen_helper_cvtss2si,
! 2879: gen_helper_cvtsd2si,
! 2880: X86_64_ONLY(gen_helper_cvtss2sq),
! 2881: X86_64_ONLY(gen_helper_cvtsd2sq),
1.1 root 2882: };
1.1.1.6 root 2883:
1.1.1.7 ! root 2884: static void *sse_op_table4[8][4] = {
1.1 root 2885: SSE_FOP(cmpeq),
2886: SSE_FOP(cmplt),
2887: SSE_FOP(cmple),
2888: SSE_FOP(cmpunord),
2889: SSE_FOP(cmpneq),
2890: SSE_FOP(cmpnlt),
2891: SSE_FOP(cmpnle),
2892: SSE_FOP(cmpord),
2893: };
1.1.1.6 root 2894:
1.1.1.7 ! root 2895: static void *sse_op_table5[256] = {
! 2896: [0x0c] = gen_helper_pi2fw,
! 2897: [0x0d] = gen_helper_pi2fd,
! 2898: [0x1c] = gen_helper_pf2iw,
! 2899: [0x1d] = gen_helper_pf2id,
! 2900: [0x8a] = gen_helper_pfnacc,
! 2901: [0x8e] = gen_helper_pfpnacc,
! 2902: [0x90] = gen_helper_pfcmpge,
! 2903: [0x94] = gen_helper_pfmin,
! 2904: [0x96] = gen_helper_pfrcp,
! 2905: [0x97] = gen_helper_pfrsqrt,
! 2906: [0x9a] = gen_helper_pfsub,
! 2907: [0x9e] = gen_helper_pfadd,
! 2908: [0xa0] = gen_helper_pfcmpgt,
! 2909: [0xa4] = gen_helper_pfmax,
! 2910: [0xa6] = gen_helper_movq, /* pfrcpit1; no need to actually increase precision */
! 2911: [0xa7] = gen_helper_movq, /* pfrsqit1 */
! 2912: [0xaa] = gen_helper_pfsubr,
! 2913: [0xae] = gen_helper_pfacc,
! 2914: [0xb0] = gen_helper_pfcmpeq,
! 2915: [0xb4] = gen_helper_pfmul,
! 2916: [0xb6] = gen_helper_movq, /* pfrcpit2 */
! 2917: [0xb7] = gen_helper_pmulhrw_mmx,
! 2918: [0xbb] = gen_helper_pswapd,
! 2919: [0xbf] = gen_helper_pavgb_mmx /* pavgusb */
! 2920: };
! 2921:
! 2922: struct sse_op_helper_s {
! 2923: void *op[2]; uint32_t ext_mask;
! 2924: };
! 2925: #define SSSE3_OP(x) { MMX_OP2(x), CPUID_EXT_SSSE3 }
! 2926: #define SSE41_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE41 }
! 2927: #define SSE42_OP(x) { { NULL, gen_helper_ ## x ## _xmm }, CPUID_EXT_SSE42 }
! 2928: #define SSE41_SPECIAL { { NULL, SSE_SPECIAL }, CPUID_EXT_SSE41 }
! 2929: static struct sse_op_helper_s sse_op_table6[256] = {
! 2930: [0x00] = SSSE3_OP(pshufb),
! 2931: [0x01] = SSSE3_OP(phaddw),
! 2932: [0x02] = SSSE3_OP(phaddd),
! 2933: [0x03] = SSSE3_OP(phaddsw),
! 2934: [0x04] = SSSE3_OP(pmaddubsw),
! 2935: [0x05] = SSSE3_OP(phsubw),
! 2936: [0x06] = SSSE3_OP(phsubd),
! 2937: [0x07] = SSSE3_OP(phsubsw),
! 2938: [0x08] = SSSE3_OP(psignb),
! 2939: [0x09] = SSSE3_OP(psignw),
! 2940: [0x0a] = SSSE3_OP(psignd),
! 2941: [0x0b] = SSSE3_OP(pmulhrsw),
! 2942: [0x10] = SSE41_OP(pblendvb),
! 2943: [0x14] = SSE41_OP(blendvps),
! 2944: [0x15] = SSE41_OP(blendvpd),
! 2945: [0x17] = SSE41_OP(ptest),
! 2946: [0x1c] = SSSE3_OP(pabsb),
! 2947: [0x1d] = SSSE3_OP(pabsw),
! 2948: [0x1e] = SSSE3_OP(pabsd),
! 2949: [0x20] = SSE41_OP(pmovsxbw),
! 2950: [0x21] = SSE41_OP(pmovsxbd),
! 2951: [0x22] = SSE41_OP(pmovsxbq),
! 2952: [0x23] = SSE41_OP(pmovsxwd),
! 2953: [0x24] = SSE41_OP(pmovsxwq),
! 2954: [0x25] = SSE41_OP(pmovsxdq),
! 2955: [0x28] = SSE41_OP(pmuldq),
! 2956: [0x29] = SSE41_OP(pcmpeqq),
! 2957: [0x2a] = SSE41_SPECIAL, /* movntqda */
! 2958: [0x2b] = SSE41_OP(packusdw),
! 2959: [0x30] = SSE41_OP(pmovzxbw),
! 2960: [0x31] = SSE41_OP(pmovzxbd),
! 2961: [0x32] = SSE41_OP(pmovzxbq),
! 2962: [0x33] = SSE41_OP(pmovzxwd),
! 2963: [0x34] = SSE41_OP(pmovzxwq),
! 2964: [0x35] = SSE41_OP(pmovzxdq),
! 2965: [0x37] = SSE42_OP(pcmpgtq),
! 2966: [0x38] = SSE41_OP(pminsb),
! 2967: [0x39] = SSE41_OP(pminsd),
! 2968: [0x3a] = SSE41_OP(pminuw),
! 2969: [0x3b] = SSE41_OP(pminud),
! 2970: [0x3c] = SSE41_OP(pmaxsb),
! 2971: [0x3d] = SSE41_OP(pmaxsd),
! 2972: [0x3e] = SSE41_OP(pmaxuw),
! 2973: [0x3f] = SSE41_OP(pmaxud),
! 2974: [0x40] = SSE41_OP(pmulld),
! 2975: [0x41] = SSE41_OP(phminposuw),
! 2976: };
! 2977:
! 2978: static struct sse_op_helper_s sse_op_table7[256] = {
! 2979: [0x08] = SSE41_OP(roundps),
! 2980: [0x09] = SSE41_OP(roundpd),
! 2981: [0x0a] = SSE41_OP(roundss),
! 2982: [0x0b] = SSE41_OP(roundsd),
! 2983: [0x0c] = SSE41_OP(blendps),
! 2984: [0x0d] = SSE41_OP(blendpd),
! 2985: [0x0e] = SSE41_OP(pblendw),
! 2986: [0x0f] = SSSE3_OP(palignr),
! 2987: [0x14] = SSE41_SPECIAL, /* pextrb */
! 2988: [0x15] = SSE41_SPECIAL, /* pextrw */
! 2989: [0x16] = SSE41_SPECIAL, /* pextrd/pextrq */
! 2990: [0x17] = SSE41_SPECIAL, /* extractps */
! 2991: [0x20] = SSE41_SPECIAL, /* pinsrb */
! 2992: [0x21] = SSE41_SPECIAL, /* insertps */
! 2993: [0x22] = SSE41_SPECIAL, /* pinsrd/pinsrq */
! 2994: [0x40] = SSE41_OP(dpps),
! 2995: [0x41] = SSE41_OP(dppd),
! 2996: [0x42] = SSE41_OP(mpsadbw),
! 2997: [0x60] = SSE42_OP(pcmpestrm),
! 2998: [0x61] = SSE42_OP(pcmpestri),
! 2999: [0x62] = SSE42_OP(pcmpistrm),
! 3000: [0x63] = SSE42_OP(pcmpistri),
! 3001: };
! 3002:
1.1 root 3003: static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
3004: {
3005: int b1, op1_offset, op2_offset, is_xmm, val, ot;
3006: int modrm, mod, rm, reg, reg_addr, offset_addr;
1.1.1.7 ! root 3007: void *sse_op2;
1.1 root 3008:
3009: b &= 0xff;
1.1.1.6 root 3010: if (s->prefix & PREFIX_DATA)
1.1 root 3011: b1 = 1;
1.1.1.6 root 3012: else if (s->prefix & PREFIX_REPZ)
1.1 root 3013: b1 = 2;
1.1.1.6 root 3014: else if (s->prefix & PREFIX_REPNZ)
1.1 root 3015: b1 = 3;
3016: else
3017: b1 = 0;
3018: sse_op2 = sse_op_table1[b][b1];
1.1.1.6 root 3019: if (!sse_op2)
1.1 root 3020: goto illegal_op;
1.1.1.7 ! root 3021: if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
1.1 root 3022: is_xmm = 1;
3023: } else {
3024: if (b1 == 0) {
3025: /* MMX case */
3026: is_xmm = 0;
3027: } else {
3028: is_xmm = 1;
3029: }
3030: }
3031: /* simple MMX/SSE operation */
3032: if (s->flags & HF_TS_MASK) {
3033: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
3034: return;
3035: }
3036: if (s->flags & HF_EM_MASK) {
3037: illegal_op:
3038: gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
3039: return;
3040: }
3041: if (is_xmm && !(s->flags & HF_OSFXSR_MASK))
1.1.1.7 ! root 3042: if ((b != 0x38 && b != 0x3a) || (s->prefix & PREFIX_DATA))
! 3043: goto illegal_op;
! 3044: if (b == 0x0e) {
! 3045: if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
! 3046: goto illegal_op;
! 3047: /* femms */
! 3048: gen_helper_emms();
! 3049: return;
! 3050: }
1.1 root 3051: if (b == 0x77) {
3052: /* emms */
1.1.1.7 ! root 3053: gen_helper_emms();
1.1 root 3054: return;
3055: }
3056: /* prepare MMX state (XXX: optimize by storing fptt and fptags in
3057: the static cpu state) */
3058: if (!is_xmm) {
1.1.1.7 ! root 3059: gen_helper_enter_mmx();
1.1 root 3060: }
3061:
3062: modrm = ldub_code(s->pc++);
3063: reg = ((modrm >> 3) & 7);
3064: if (is_xmm)
3065: reg |= rex_r;
3066: mod = (modrm >> 6) & 3;
3067: if (sse_op2 == SSE_SPECIAL) {
3068: b |= (b1 << 8);
3069: switch(b) {
3070: case 0x0e7: /* movntq */
1.1.1.6 root 3071: if (mod == 3)
1.1 root 3072: goto illegal_op;
3073: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3074: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
1.1 root 3075: break;
3076: case 0x1e7: /* movntdq */
3077: case 0x02b: /* movntps */
3078: case 0x12b: /* movntps */
1.1.1.3 root 3079: case 0x3f0: /* lddqu */
3080: if (mod == 3)
1.1 root 3081: goto illegal_op;
3082: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3083: gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
1.1 root 3084: break;
3085: case 0x6e: /* movd mm, ea */
1.1.1.5 root 3086: #ifdef TARGET_X86_64
3087: if (s->dflag == 2) {
3088: gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
1.1.1.7 ! root 3089: tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,fpregs[reg].mmx));
1.1.1.6 root 3090: } else
1.1.1.5 root 3091: #endif
3092: {
3093: gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
1.1.1.7 ! root 3094: tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
! 3095: offsetof(CPUX86State,fpregs[reg].mmx));
! 3096: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 3097: gen_helper_movl_mm_T0_mmx(cpu_ptr0, cpu_tmp2_i32);
1.1.1.5 root 3098: }
1.1 root 3099: break;
3100: case 0x16e: /* movd xmm, ea */
1.1.1.5 root 3101: #ifdef TARGET_X86_64
3102: if (s->dflag == 2) {
3103: gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
1.1.1.7 ! root 3104: tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
! 3105: offsetof(CPUX86State,xmm_regs[reg]));
! 3106: gen_helper_movq_mm_T0_xmm(cpu_ptr0, cpu_T[0]);
1.1.1.6 root 3107: } else
1.1.1.5 root 3108: #endif
3109: {
3110: gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
1.1.1.7 ! root 3111: tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
! 3112: offsetof(CPUX86State,xmm_regs[reg]));
! 3113: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 3114: gen_helper_movl_mm_T0_xmm(cpu_ptr0, cpu_tmp2_i32);
1.1.1.5 root 3115: }
1.1 root 3116: break;
3117: case 0x6f: /* movq mm, ea */
3118: if (mod != 3) {
3119: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3120: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
1.1 root 3121: } else {
3122: rm = (modrm & 7);
1.1.1.7 ! root 3123: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env,
! 3124: offsetof(CPUX86State,fpregs[rm].mmx));
! 3125: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env,
! 3126: offsetof(CPUX86State,fpregs[reg].mmx));
1.1 root 3127: }
3128: break;
3129: case 0x010: /* movups */
3130: case 0x110: /* movupd */
3131: case 0x028: /* movaps */
3132: case 0x128: /* movapd */
3133: case 0x16f: /* movdqa xmm, ea */
3134: case 0x26f: /* movdqu xmm, ea */
3135: if (mod != 3) {
3136: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3137: gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
1.1 root 3138: } else {
3139: rm = (modrm & 7) | REX_B(s);
3140: gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]),
3141: offsetof(CPUX86State,xmm_regs[rm]));
3142: }
3143: break;
3144: case 0x210: /* movss xmm, ea */
3145: if (mod != 3) {
3146: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3147: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 3148: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
1.1 root 3149: gen_op_movl_T0_0();
1.1.1.7 ! root 3150: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
! 3151: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
! 3152: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
1.1 root 3153: } else {
3154: rm = (modrm & 7) | REX_B(s);
3155: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
3156: offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
3157: }
3158: break;
3159: case 0x310: /* movsd xmm, ea */
3160: if (mod != 3) {
3161: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3162: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3163: gen_op_movl_T0_0();
1.1.1.7 ! root 3164: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
! 3165: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
1.1 root 3166: } else {
3167: rm = (modrm & 7) | REX_B(s);
3168: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
3169: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
3170: }
3171: break;
3172: case 0x012: /* movlps */
3173: case 0x112: /* movlpd */
3174: if (mod != 3) {
3175: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3176: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3177: } else {
3178: /* movhlps */
3179: rm = (modrm & 7) | REX_B(s);
3180: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
3181: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
3182: }
3183: break;
1.1.1.3 root 3184: case 0x212: /* movsldup */
3185: if (mod != 3) {
3186: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3187: gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
1.1.1.3 root 3188: } else {
3189: rm = (modrm & 7) | REX_B(s);
3190: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
3191: offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
3192: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
3193: offsetof(CPUX86State,xmm_regs[rm].XMM_L(2)));
3194: }
3195: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
3196: offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
3197: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
3198: offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
3199: break;
3200: case 0x312: /* movddup */
3201: if (mod != 3) {
3202: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3203: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1.1.3 root 3204: } else {
3205: rm = (modrm & 7) | REX_B(s);
3206: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
3207: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
3208: }
3209: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
3210: offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
3211: break;
1.1 root 3212: case 0x016: /* movhps */
3213: case 0x116: /* movhpd */
3214: if (mod != 3) {
3215: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3216: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
1.1 root 3217: } else {
3218: /* movlhps */
3219: rm = (modrm & 7) | REX_B(s);
3220: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
3221: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
3222: }
3223: break;
3224: case 0x216: /* movshdup */
3225: if (mod != 3) {
3226: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3227: gen_ldo_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
1.1 root 3228: } else {
3229: rm = (modrm & 7) | REX_B(s);
3230: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
3231: offsetof(CPUX86State,xmm_regs[rm].XMM_L(1)));
3232: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
3233: offsetof(CPUX86State,xmm_regs[rm].XMM_L(3)));
3234: }
3235: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
3236: offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
3237: gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
3238: offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
3239: break;
3240: case 0x7e: /* movd ea, mm */
1.1.1.5 root 3241: #ifdef TARGET_X86_64
3242: if (s->dflag == 2) {
1.1.1.7 ! root 3243: tcg_gen_ld_i64(cpu_T[0], cpu_env,
! 3244: offsetof(CPUX86State,fpregs[reg].mmx));
1.1.1.5 root 3245: gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
1.1.1.6 root 3246: } else
1.1.1.5 root 3247: #endif
3248: {
1.1.1.7 ! root 3249: tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
! 3250: offsetof(CPUX86State,fpregs[reg].mmx.MMX_L(0)));
1.1.1.5 root 3251: gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
3252: }
1.1 root 3253: break;
3254: case 0x17e: /* movd ea, xmm */
1.1.1.5 root 3255: #ifdef TARGET_X86_64
3256: if (s->dflag == 2) {
1.1.1.7 ! root 3257: tcg_gen_ld_i64(cpu_T[0], cpu_env,
! 3258: offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1.1.5 root 3259: gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
1.1.1.6 root 3260: } else
1.1.1.5 root 3261: #endif
3262: {
1.1.1.7 ! root 3263: tcg_gen_ld32u_tl(cpu_T[0], cpu_env,
! 3264: offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
1.1.1.5 root 3265: gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
3266: }
1.1 root 3267: break;
3268: case 0x27e: /* movq xmm, ea */
3269: if (mod != 3) {
3270: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3271: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3272: } else {
3273: rm = (modrm & 7) | REX_B(s);
3274: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
3275: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
3276: }
3277: gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
3278: break;
3279: case 0x7f: /* movq ea, mm */
3280: if (mod != 3) {
3281: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3282: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,fpregs[reg].mmx));
1.1 root 3283: } else {
3284: rm = (modrm & 7);
3285: gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx),
3286: offsetof(CPUX86State,fpregs[reg].mmx));
3287: }
3288: break;
3289: case 0x011: /* movups */
3290: case 0x111: /* movupd */
3291: case 0x029: /* movaps */
3292: case 0x129: /* movapd */
3293: case 0x17f: /* movdqa ea, xmm */
3294: case 0x27f: /* movdqu ea, xmm */
3295: if (mod != 3) {
3296: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3297: gen_sto_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg]));
1.1 root 3298: } else {
3299: rm = (modrm & 7) | REX_B(s);
3300: gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]),
3301: offsetof(CPUX86State,xmm_regs[reg]));
3302: }
3303: break;
3304: case 0x211: /* movss ea, xmm */
3305: if (mod != 3) {
3306: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3307: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
! 3308: gen_op_st_T0_A0(OT_LONG + s->mem_index);
1.1 root 3309: } else {
3310: rm = (modrm & 7) | REX_B(s);
3311: gen_op_movl(offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)),
3312: offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
3313: }
3314: break;
3315: case 0x311: /* movsd ea, xmm */
3316: if (mod != 3) {
3317: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3318: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3319: } else {
3320: rm = (modrm & 7) | REX_B(s);
3321: gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
3322: offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
3323: }
3324: break;
3325: case 0x013: /* movlps */
3326: case 0x113: /* movlpd */
3327: if (mod != 3) {
3328: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3329: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3330: } else {
3331: goto illegal_op;
3332: }
3333: break;
3334: case 0x017: /* movhps */
3335: case 0x117: /* movhpd */
3336: if (mod != 3) {
3337: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3338: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
1.1 root 3339: } else {
3340: goto illegal_op;
3341: }
3342: break;
3343: case 0x71: /* shift mm, im */
3344: case 0x72:
3345: case 0x73:
3346: case 0x171: /* shift xmm, im */
3347: case 0x172:
3348: case 0x173:
3349: val = ldub_code(s->pc++);
3350: if (is_xmm) {
3351: gen_op_movl_T0_im(val);
1.1.1.7 ! root 3352: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
1.1 root 3353: gen_op_movl_T0_0();
1.1.1.7 ! root 3354: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(1)));
1.1 root 3355: op1_offset = offsetof(CPUX86State,xmm_t0);
3356: } else {
3357: gen_op_movl_T0_im(val);
1.1.1.7 ! root 3358: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(0)));
1.1 root 3359: gen_op_movl_T0_0();
1.1.1.7 ! root 3360: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,mmx_t0.MMX_L(1)));
1.1 root 3361: op1_offset = offsetof(CPUX86State,mmx_t0);
3362: }
3363: sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
3364: if (!sse_op2)
3365: goto illegal_op;
3366: if (is_xmm) {
3367: rm = (modrm & 7) | REX_B(s);
3368: op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3369: } else {
3370: rm = (modrm & 7);
3371: op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3372: }
1.1.1.7 ! root 3373: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
! 3374: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op1_offset);
! 3375: ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
1.1 root 3376: break;
3377: case 0x050: /* movmskps */
3378: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 3379: tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
! 3380: offsetof(CPUX86State,xmm_regs[rm]));
! 3381: gen_helper_movmskps(cpu_tmp2_i32, cpu_ptr0);
! 3382: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 3383: gen_op_mov_reg_T0(OT_LONG, reg);
1.1 root 3384: break;
3385: case 0x150: /* movmskpd */
3386: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 3387: tcg_gen_addi_ptr(cpu_ptr0, cpu_env,
! 3388: offsetof(CPUX86State,xmm_regs[rm]));
! 3389: gen_helper_movmskpd(cpu_tmp2_i32, cpu_ptr0);
! 3390: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 3391: gen_op_mov_reg_T0(OT_LONG, reg);
1.1 root 3392: break;
3393: case 0x02a: /* cvtpi2ps */
3394: case 0x12a: /* cvtpi2pd */
1.1.1.7 ! root 3395: gen_helper_enter_mmx();
1.1 root 3396: if (mod != 3) {
3397: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
3398: op2_offset = offsetof(CPUX86State,mmx_t0);
1.1.1.7 ! root 3399: gen_ldq_env_A0(s->mem_index, op2_offset);
1.1 root 3400: } else {
3401: rm = (modrm & 7);
3402: op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3403: }
3404: op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
1.1.1.7 ! root 3405: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3406: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
1.1 root 3407: switch(b >> 8) {
3408: case 0x0:
1.1.1.7 ! root 3409: gen_helper_cvtpi2ps(cpu_ptr0, cpu_ptr1);
1.1 root 3410: break;
3411: default:
3412: case 0x1:
1.1.1.7 ! root 3413: gen_helper_cvtpi2pd(cpu_ptr0, cpu_ptr1);
1.1 root 3414: break;
3415: }
3416: break;
3417: case 0x22a: /* cvtsi2ss */
3418: case 0x32a: /* cvtsi2sd */
3419: ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
3420: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
3421: op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
1.1.1.7 ! root 3422: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3423: sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)];
! 3424: if (ot == OT_LONG) {
! 3425: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 3426: ((void (*)(TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_tmp2_i32);
! 3427: } else {
! 3428: ((void (*)(TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_T[0]);
! 3429: }
1.1 root 3430: break;
3431: case 0x02c: /* cvttps2pi */
3432: case 0x12c: /* cvttpd2pi */
3433: case 0x02d: /* cvtps2pi */
3434: case 0x12d: /* cvtpd2pi */
1.1.1.7 ! root 3435: gen_helper_enter_mmx();
1.1 root 3436: if (mod != 3) {
3437: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
3438: op2_offset = offsetof(CPUX86State,xmm_t0);
1.1.1.7 ! root 3439: gen_ldo_env_A0(s->mem_index, op2_offset);
1.1 root 3440: } else {
3441: rm = (modrm & 7) | REX_B(s);
3442: op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3443: }
3444: op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx);
1.1.1.7 ! root 3445: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3446: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
1.1 root 3447: switch(b) {
3448: case 0x02c:
1.1.1.7 ! root 3449: gen_helper_cvttps2pi(cpu_ptr0, cpu_ptr1);
1.1 root 3450: break;
3451: case 0x12c:
1.1.1.7 ! root 3452: gen_helper_cvttpd2pi(cpu_ptr0, cpu_ptr1);
1.1 root 3453: break;
3454: case 0x02d:
1.1.1.7 ! root 3455: gen_helper_cvtps2pi(cpu_ptr0, cpu_ptr1);
1.1 root 3456: break;
3457: case 0x12d:
1.1.1.7 ! root 3458: gen_helper_cvtpd2pi(cpu_ptr0, cpu_ptr1);
1.1 root 3459: break;
3460: }
3461: break;
3462: case 0x22c: /* cvttss2si */
3463: case 0x32c: /* cvttsd2si */
3464: case 0x22d: /* cvtss2si */
3465: case 0x32d: /* cvtsd2si */
3466: ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
3467: if (mod != 3) {
3468: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
3469: if ((b >> 8) & 1) {
1.1.1.7 ! root 3470: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_Q(0)));
1.1 root 3471: } else {
1.1.1.7 ! root 3472: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 3473: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
1.1 root 3474: }
3475: op2_offset = offsetof(CPUX86State,xmm_t0);
3476: } else {
3477: rm = (modrm & 7) | REX_B(s);
3478: op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3479: }
1.1.1.7 ! root 3480: sse_op2 = sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 +
! 3481: (b & 1) * 4];
! 3482: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op2_offset);
! 3483: if (ot == OT_LONG) {
! 3484: ((void (*)(TCGv_i32, TCGv_ptr))sse_op2)(cpu_tmp2_i32, cpu_ptr0);
! 3485: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 3486: } else {
! 3487: ((void (*)(TCGv, TCGv_ptr))sse_op2)(cpu_T[0], cpu_ptr0);
! 3488: }
! 3489: gen_op_mov_reg_T0(ot, reg);
1.1 root 3490: break;
3491: case 0xc4: /* pinsrw */
1.1.1.6 root 3492: case 0x1c4:
1.1.1.4 root 3493: s->rip_offset = 1;
1.1 root 3494: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
3495: val = ldub_code(s->pc++);
3496: if (b1) {
3497: val &= 7;
1.1.1.7 ! root 3498: tcg_gen_st16_tl(cpu_T[0], cpu_env,
! 3499: offsetof(CPUX86State,xmm_regs[reg].XMM_W(val)));
1.1 root 3500: } else {
3501: val &= 3;
1.1.1.7 ! root 3502: tcg_gen_st16_tl(cpu_T[0], cpu_env,
! 3503: offsetof(CPUX86State,fpregs[reg].mmx.MMX_W(val)));
1.1 root 3504: }
3505: break;
3506: case 0xc5: /* pextrw */
1.1.1.6 root 3507: case 0x1c5:
1.1 root 3508: if (mod != 3)
3509: goto illegal_op;
1.1.1.7 ! root 3510: ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
1.1 root 3511: val = ldub_code(s->pc++);
3512: if (b1) {
3513: val &= 7;
3514: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 3515: tcg_gen_ld16u_tl(cpu_T[0], cpu_env,
! 3516: offsetof(CPUX86State,xmm_regs[rm].XMM_W(val)));
1.1 root 3517: } else {
3518: val &= 3;
3519: rm = (modrm & 7);
1.1.1.7 ! root 3520: tcg_gen_ld16u_tl(cpu_T[0], cpu_env,
! 3521: offsetof(CPUX86State,fpregs[rm].mmx.MMX_W(val)));
1.1 root 3522: }
3523: reg = ((modrm >> 3) & 7) | rex_r;
1.1.1.7 ! root 3524: gen_op_mov_reg_T0(ot, reg);
1.1 root 3525: break;
3526: case 0x1d6: /* movq ea, xmm */
3527: if (mod != 3) {
3528: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 3529: gen_stq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
1.1 root 3530: } else {
3531: rm = (modrm & 7) | REX_B(s);
3532: gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
3533: offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
3534: gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
3535: }
3536: break;
3537: case 0x2d6: /* movq2dq */
1.1.1.7 ! root 3538: gen_helper_enter_mmx();
1.1.1.4 root 3539: rm = (modrm & 7);
3540: gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
3541: offsetof(CPUX86State,fpregs[rm].mmx));
3542: gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
1.1 root 3543: break;
3544: case 0x3d6: /* movdq2q */
1.1.1.7 ! root 3545: gen_helper_enter_mmx();
1.1.1.4 root 3546: rm = (modrm & 7) | REX_B(s);
3547: gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx),
3548: offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
1.1 root 3549: break;
3550: case 0xd7: /* pmovmskb */
3551: case 0x1d7:
3552: if (mod != 3)
3553: goto illegal_op;
3554: if (b1) {
3555: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 3556: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,xmm_regs[rm]));
! 3557: gen_helper_pmovmskb_xmm(cpu_tmp2_i32, cpu_ptr0);
1.1 root 3558: } else {
3559: rm = (modrm & 7);
1.1.1.7 ! root 3560: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, offsetof(CPUX86State,fpregs[rm].mmx));
! 3561: gen_helper_pmovmskb_mmx(cpu_tmp2_i32, cpu_ptr0);
! 3562: }
! 3563: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 3564: reg = ((modrm >> 3) & 7) | rex_r;
! 3565: gen_op_mov_reg_T0(OT_LONG, reg);
! 3566: break;
! 3567: case 0x138:
! 3568: if (s->prefix & PREFIX_REPNZ)
! 3569: goto crc32;
! 3570: case 0x038:
! 3571: b = modrm;
! 3572: modrm = ldub_code(s->pc++);
! 3573: rm = modrm & 7;
! 3574: reg = ((modrm >> 3) & 7) | rex_r;
! 3575: mod = (modrm >> 6) & 3;
! 3576:
! 3577: sse_op2 = sse_op_table6[b].op[b1];
! 3578: if (!sse_op2)
! 3579: goto illegal_op;
! 3580: if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
! 3581: goto illegal_op;
! 3582:
! 3583: if (b1) {
! 3584: op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
! 3585: if (mod == 3) {
! 3586: op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
! 3587: } else {
! 3588: op2_offset = offsetof(CPUX86State,xmm_t0);
! 3589: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 3590: switch (b) {
! 3591: case 0x20: case 0x30: /* pmovsxbw, pmovzxbw */
! 3592: case 0x23: case 0x33: /* pmovsxwd, pmovzxwd */
! 3593: case 0x25: case 0x35: /* pmovsxdq, pmovzxdq */
! 3594: gen_ldq_env_A0(s->mem_index, op2_offset +
! 3595: offsetof(XMMReg, XMM_Q(0)));
! 3596: break;
! 3597: case 0x21: case 0x31: /* pmovsxbd, pmovzxbd */
! 3598: case 0x24: case 0x34: /* pmovsxwq, pmovzxwq */
! 3599: tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
! 3600: (s->mem_index >> 2) - 1);
! 3601: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
! 3602: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, op2_offset +
! 3603: offsetof(XMMReg, XMM_L(0)));
! 3604: break;
! 3605: case 0x22: case 0x32: /* pmovsxbq, pmovzxbq */
! 3606: tcg_gen_qemu_ld16u(cpu_tmp0, cpu_A0,
! 3607: (s->mem_index >> 2) - 1);
! 3608: tcg_gen_st16_tl(cpu_tmp0, cpu_env, op2_offset +
! 3609: offsetof(XMMReg, XMM_W(0)));
! 3610: break;
! 3611: case 0x2a: /* movntqda */
! 3612: gen_ldo_env_A0(s->mem_index, op1_offset);
! 3613: return;
! 3614: default:
! 3615: gen_ldo_env_A0(s->mem_index, op2_offset);
! 3616: }
! 3617: }
! 3618: } else {
! 3619: op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
! 3620: if (mod == 3) {
! 3621: op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
! 3622: } else {
! 3623: op2_offset = offsetof(CPUX86State,mmx_t0);
! 3624: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 3625: gen_ldq_env_A0(s->mem_index, op2_offset);
! 3626: }
1.1 root 3627: }
1.1.1.7 ! root 3628: if (sse_op2 == SSE_SPECIAL)
! 3629: goto illegal_op;
! 3630:
! 3631: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3632: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3633: ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
! 3634:
! 3635: if (b == 0x17)
! 3636: s->cc_op = CC_OP_EFLAGS;
! 3637: break;
! 3638: case 0x338: /* crc32 */
! 3639: crc32:
! 3640: b = modrm;
! 3641: modrm = ldub_code(s->pc++);
! 3642: reg = ((modrm >> 3) & 7) | rex_r;
! 3643:
! 3644: if (b != 0xf0 && b != 0xf1)
! 3645: goto illegal_op;
! 3646: if (!(s->cpuid_ext_features & CPUID_EXT_SSE42))
! 3647: goto illegal_op;
! 3648:
! 3649: if (b == 0xf0)
! 3650: ot = OT_BYTE;
! 3651: else if (b == 0xf1 && s->dflag != 2)
! 3652: if (s->prefix & PREFIX_DATA)
! 3653: ot = OT_WORD;
! 3654: else
! 3655: ot = OT_LONG;
! 3656: else
! 3657: ot = OT_QUAD;
! 3658:
! 3659: gen_op_mov_TN_reg(OT_LONG, 0, reg);
! 3660: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 3661: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
! 3662: gen_helper_crc32(cpu_T[0], cpu_tmp2_i32,
! 3663: cpu_T[0], tcg_const_i32(8 << ot));
! 3664:
! 3665: ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
! 3666: gen_op_mov_reg_T0(ot, reg);
! 3667: break;
! 3668: case 0x03a:
! 3669: case 0x13a:
! 3670: b = modrm;
! 3671: modrm = ldub_code(s->pc++);
! 3672: rm = modrm & 7;
1.1 root 3673: reg = ((modrm >> 3) & 7) | rex_r;
1.1.1.7 ! root 3674: mod = (modrm >> 6) & 3;
! 3675:
! 3676: sse_op2 = sse_op_table7[b].op[b1];
! 3677: if (!sse_op2)
! 3678: goto illegal_op;
! 3679: if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
! 3680: goto illegal_op;
! 3681:
! 3682: if (sse_op2 == SSE_SPECIAL) {
! 3683: ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
! 3684: rm = (modrm & 7) | REX_B(s);
! 3685: if (mod != 3)
! 3686: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 3687: reg = ((modrm >> 3) & 7) | rex_r;
! 3688: val = ldub_code(s->pc++);
! 3689: switch (b) {
! 3690: case 0x14: /* pextrb */
! 3691: tcg_gen_ld8u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
! 3692: xmm_regs[reg].XMM_B(val & 15)));
! 3693: if (mod == 3)
! 3694: gen_op_mov_reg_T0(ot, rm);
! 3695: else
! 3696: tcg_gen_qemu_st8(cpu_T[0], cpu_A0,
! 3697: (s->mem_index >> 2) - 1);
! 3698: break;
! 3699: case 0x15: /* pextrw */
! 3700: tcg_gen_ld16u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
! 3701: xmm_regs[reg].XMM_W(val & 7)));
! 3702: if (mod == 3)
! 3703: gen_op_mov_reg_T0(ot, rm);
! 3704: else
! 3705: tcg_gen_qemu_st16(cpu_T[0], cpu_A0,
! 3706: (s->mem_index >> 2) - 1);
! 3707: break;
! 3708: case 0x16:
! 3709: if (ot == OT_LONG) { /* pextrd */
! 3710: tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env,
! 3711: offsetof(CPUX86State,
! 3712: xmm_regs[reg].XMM_L(val & 3)));
! 3713: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 3714: if (mod == 3)
! 3715: gen_op_mov_reg_v(ot, rm, cpu_T[0]);
! 3716: else
! 3717: tcg_gen_qemu_st32(cpu_T[0], cpu_A0,
! 3718: (s->mem_index >> 2) - 1);
! 3719: } else { /* pextrq */
! 3720: #ifdef TARGET_X86_64
! 3721: tcg_gen_ld_i64(cpu_tmp1_i64, cpu_env,
! 3722: offsetof(CPUX86State,
! 3723: xmm_regs[reg].XMM_Q(val & 1)));
! 3724: if (mod == 3)
! 3725: gen_op_mov_reg_v(ot, rm, cpu_tmp1_i64);
! 3726: else
! 3727: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
! 3728: (s->mem_index >> 2) - 1);
! 3729: #else
! 3730: goto illegal_op;
! 3731: #endif
! 3732: }
! 3733: break;
! 3734: case 0x17: /* extractps */
! 3735: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,
! 3736: xmm_regs[reg].XMM_L(val & 3)));
! 3737: if (mod == 3)
! 3738: gen_op_mov_reg_T0(ot, rm);
! 3739: else
! 3740: tcg_gen_qemu_st32(cpu_T[0], cpu_A0,
! 3741: (s->mem_index >> 2) - 1);
! 3742: break;
! 3743: case 0x20: /* pinsrb */
! 3744: if (mod == 3)
! 3745: gen_op_mov_TN_reg(OT_LONG, 0, rm);
! 3746: else
! 3747: tcg_gen_qemu_ld8u(cpu_tmp0, cpu_A0,
! 3748: (s->mem_index >> 2) - 1);
! 3749: tcg_gen_st8_tl(cpu_tmp0, cpu_env, offsetof(CPUX86State,
! 3750: xmm_regs[reg].XMM_B(val & 15)));
! 3751: break;
! 3752: case 0x21: /* insertps */
! 3753: if (mod == 3) {
! 3754: tcg_gen_ld_i32(cpu_tmp2_i32, cpu_env,
! 3755: offsetof(CPUX86State,xmm_regs[rm]
! 3756: .XMM_L((val >> 6) & 3)));
! 3757: } else {
! 3758: tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
! 3759: (s->mem_index >> 2) - 1);
! 3760: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
! 3761: }
! 3762: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env,
! 3763: offsetof(CPUX86State,xmm_regs[reg]
! 3764: .XMM_L((val >> 4) & 3)));
! 3765: if ((val >> 0) & 1)
! 3766: tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
! 3767: cpu_env, offsetof(CPUX86State,
! 3768: xmm_regs[reg].XMM_L(0)));
! 3769: if ((val >> 1) & 1)
! 3770: tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
! 3771: cpu_env, offsetof(CPUX86State,
! 3772: xmm_regs[reg].XMM_L(1)));
! 3773: if ((val >> 2) & 1)
! 3774: tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
! 3775: cpu_env, offsetof(CPUX86State,
! 3776: xmm_regs[reg].XMM_L(2)));
! 3777: if ((val >> 3) & 1)
! 3778: tcg_gen_st_i32(tcg_const_i32(0 /*float32_zero*/),
! 3779: cpu_env, offsetof(CPUX86State,
! 3780: xmm_regs[reg].XMM_L(3)));
! 3781: break;
! 3782: case 0x22:
! 3783: if (ot == OT_LONG) { /* pinsrd */
! 3784: if (mod == 3)
! 3785: gen_op_mov_v_reg(ot, cpu_tmp0, rm);
! 3786: else
! 3787: tcg_gen_qemu_ld32u(cpu_tmp0, cpu_A0,
! 3788: (s->mem_index >> 2) - 1);
! 3789: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_tmp0);
! 3790: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env,
! 3791: offsetof(CPUX86State,
! 3792: xmm_regs[reg].XMM_L(val & 3)));
! 3793: } else { /* pinsrq */
! 3794: #ifdef TARGET_X86_64
! 3795: if (mod == 3)
! 3796: gen_op_mov_v_reg(ot, cpu_tmp1_i64, rm);
! 3797: else
! 3798: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
! 3799: (s->mem_index >> 2) - 1);
! 3800: tcg_gen_st_i64(cpu_tmp1_i64, cpu_env,
! 3801: offsetof(CPUX86State,
! 3802: xmm_regs[reg].XMM_Q(val & 1)));
! 3803: #else
! 3804: goto illegal_op;
! 3805: #endif
! 3806: }
! 3807: break;
! 3808: }
! 3809: return;
! 3810: }
! 3811:
! 3812: if (b1) {
! 3813: op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
! 3814: if (mod == 3) {
! 3815: op2_offset = offsetof(CPUX86State,xmm_regs[rm | REX_B(s)]);
! 3816: } else {
! 3817: op2_offset = offsetof(CPUX86State,xmm_t0);
! 3818: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 3819: gen_ldo_env_A0(s->mem_index, op2_offset);
! 3820: }
! 3821: } else {
! 3822: op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
! 3823: if (mod == 3) {
! 3824: op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
! 3825: } else {
! 3826: op2_offset = offsetof(CPUX86State,mmx_t0);
! 3827: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 3828: gen_ldq_env_A0(s->mem_index, op2_offset);
! 3829: }
! 3830: }
! 3831: val = ldub_code(s->pc++);
! 3832:
! 3833: if ((b & 0xfc) == 0x60) { /* pcmpXstrX */
! 3834: s->cc_op = CC_OP_EFLAGS;
! 3835:
! 3836: if (s->dflag == 2)
! 3837: /* The helper must use entire 64-bit gp registers */
! 3838: val |= 1 << 8;
! 3839: }
! 3840:
! 3841: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3842: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3843: ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
1.1 root 3844: break;
3845: default:
3846: goto illegal_op;
3847: }
3848: } else {
3849: /* generic MMX or SSE operation */
1.1.1.4 root 3850: switch(b) {
3851: case 0x70: /* pshufx insn */
3852: case 0xc6: /* pshufx insn */
3853: case 0xc2: /* compare insns */
3854: s->rip_offset = 1;
3855: break;
3856: default:
3857: break;
1.1 root 3858: }
3859: if (is_xmm) {
3860: op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
3861: if (mod != 3) {
3862: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
3863: op2_offset = offsetof(CPUX86State,xmm_t0);
1.1.1.4 root 3864: if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
1.1 root 3865: b == 0xc2)) {
3866: /* specific case for SSE single instructions */
3867: if (b1 == 2) {
3868: /* 32 bit access */
1.1.1.7 ! root 3869: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 3870: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,xmm_t0.XMM_L(0)));
1.1 root 3871: } else {
3872: /* 64 bit access */
1.1.1.7 ! root 3873: gen_ldq_env_A0(s->mem_index, offsetof(CPUX86State,xmm_t0.XMM_D(0)));
1.1 root 3874: }
3875: } else {
1.1.1.7 ! root 3876: gen_ldo_env_A0(s->mem_index, op2_offset);
1.1 root 3877: }
3878: } else {
3879: rm = (modrm & 7) | REX_B(s);
3880: op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
3881: }
3882: } else {
3883: op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
3884: if (mod != 3) {
3885: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
3886: op2_offset = offsetof(CPUX86State,mmx_t0);
1.1.1.7 ! root 3887: gen_ldq_env_A0(s->mem_index, op2_offset);
1.1 root 3888: } else {
3889: rm = (modrm & 7);
3890: op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
3891: }
3892: }
3893: switch(b) {
1.1.1.7 ! root 3894: case 0x0f: /* 3DNow! data insns */
! 3895: if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
! 3896: goto illegal_op;
! 3897: val = ldub_code(s->pc++);
! 3898: sse_op2 = sse_op_table5[val];
! 3899: if (!sse_op2)
! 3900: goto illegal_op;
! 3901: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3902: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3903: ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
! 3904: break;
1.1 root 3905: case 0x70: /* pshufx insn */
3906: case 0xc6: /* pshufx insn */
3907: val = ldub_code(s->pc++);
1.1.1.7 ! root 3908: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3909: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3910: ((void (*)(TCGv_ptr, TCGv_ptr, TCGv_i32))sse_op2)(cpu_ptr0, cpu_ptr1, tcg_const_i32(val));
1.1 root 3911: break;
3912: case 0xc2:
3913: /* compare insns */
3914: val = ldub_code(s->pc++);
3915: if (val >= 8)
3916: goto illegal_op;
3917: sse_op2 = sse_op_table4[val][b1];
1.1.1.7 ! root 3918: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3919: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3920: ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
! 3921: break;
! 3922: case 0xf7:
! 3923: /* maskmov : we must prepare A0 */
! 3924: if (mod != 3)
! 3925: goto illegal_op;
! 3926: #ifdef TARGET_X86_64
! 3927: if (s->aflag == 2) {
! 3928: gen_op_movq_A0_reg(R_EDI);
! 3929: } else
! 3930: #endif
! 3931: {
! 3932: gen_op_movl_A0_reg(R_EDI);
! 3933: if (s->aflag == 0)
! 3934: gen_op_andl_A0_ffff();
! 3935: }
! 3936: gen_add_A0_ds_seg(s);
! 3937:
! 3938: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3939: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3940: ((void (*)(TCGv_ptr, TCGv_ptr, TCGv))sse_op2)(cpu_ptr0, cpu_ptr1, cpu_A0);
1.1 root 3941: break;
3942: default:
1.1.1.7 ! root 3943: tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
! 3944: tcg_gen_addi_ptr(cpu_ptr1, cpu_env, op2_offset);
! 3945: ((void (*)(TCGv_ptr, TCGv_ptr))sse_op2)(cpu_ptr0, cpu_ptr1);
1.1 root 3946: break;
3947: }
3948: if (b == 0x2e || b == 0x2f) {
3949: s->cc_op = CC_OP_EFLAGS;
3950: }
3951: }
3952: }
3953:
3954: /* convert one instruction. s->is_jmp is set if the translation must
3955: be stopped. Return the next pc value */
3956: static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
3957: {
3958: int b, prefixes, aflag, dflag;
3959: int shift, ot;
3960: int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
3961: target_ulong next_eip, tval;
3962: int rex_w, rex_r;
3963:
1.1.1.7 ! root 3964: if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
! 3965: tcg_gen_debug_insn_start(pc_start);
1.1 root 3966: s->pc = pc_start;
3967: prefixes = 0;
3968: aflag = s->code32;
3969: dflag = s->code32;
3970: s->override = -1;
3971: rex_w = -1;
3972: rex_r = 0;
3973: #ifdef TARGET_X86_64
3974: s->rex_x = 0;
3975: s->rex_b = 0;
1.1.1.6 root 3976: x86_64_hregs = 0;
1.1 root 3977: #endif
3978: s->rip_offset = 0; /* for relative ip address */
3979: next_byte:
3980: b = ldub_code(s->pc);
3981: s->pc++;
3982: /* check prefixes */
3983: #ifdef TARGET_X86_64
3984: if (CODE64(s)) {
3985: switch (b) {
3986: case 0xf3:
3987: prefixes |= PREFIX_REPZ;
3988: goto next_byte;
3989: case 0xf2:
3990: prefixes |= PREFIX_REPNZ;
3991: goto next_byte;
3992: case 0xf0:
3993: prefixes |= PREFIX_LOCK;
3994: goto next_byte;
3995: case 0x2e:
3996: s->override = R_CS;
3997: goto next_byte;
3998: case 0x36:
3999: s->override = R_SS;
4000: goto next_byte;
4001: case 0x3e:
4002: s->override = R_DS;
4003: goto next_byte;
4004: case 0x26:
4005: s->override = R_ES;
4006: goto next_byte;
4007: case 0x64:
4008: s->override = R_FS;
4009: goto next_byte;
4010: case 0x65:
4011: s->override = R_GS;
4012: goto next_byte;
4013: case 0x66:
4014: prefixes |= PREFIX_DATA;
4015: goto next_byte;
4016: case 0x67:
4017: prefixes |= PREFIX_ADR;
4018: goto next_byte;
4019: case 0x40 ... 0x4f:
4020: /* REX prefix */
4021: rex_w = (b >> 3) & 1;
4022: rex_r = (b & 0x4) << 1;
4023: s->rex_x = (b & 0x2) << 2;
4024: REX_B(s) = (b & 0x1) << 3;
4025: x86_64_hregs = 1; /* select uniform byte register addressing */
4026: goto next_byte;
4027: }
4028: if (rex_w == 1) {
4029: /* 0x66 is ignored if rex.w is set */
4030: dflag = 2;
4031: } else {
4032: if (prefixes & PREFIX_DATA)
4033: dflag ^= 1;
4034: }
4035: if (!(prefixes & PREFIX_ADR))
4036: aflag = 2;
1.1.1.6 root 4037: } else
1.1 root 4038: #endif
4039: {
4040: switch (b) {
4041: case 0xf3:
4042: prefixes |= PREFIX_REPZ;
4043: goto next_byte;
4044: case 0xf2:
4045: prefixes |= PREFIX_REPNZ;
4046: goto next_byte;
4047: case 0xf0:
4048: prefixes |= PREFIX_LOCK;
4049: goto next_byte;
4050: case 0x2e:
4051: s->override = R_CS;
4052: goto next_byte;
4053: case 0x36:
4054: s->override = R_SS;
4055: goto next_byte;
4056: case 0x3e:
4057: s->override = R_DS;
4058: goto next_byte;
4059: case 0x26:
4060: s->override = R_ES;
4061: goto next_byte;
4062: case 0x64:
4063: s->override = R_FS;
4064: goto next_byte;
4065: case 0x65:
4066: s->override = R_GS;
4067: goto next_byte;
4068: case 0x66:
4069: prefixes |= PREFIX_DATA;
4070: goto next_byte;
4071: case 0x67:
4072: prefixes |= PREFIX_ADR;
4073: goto next_byte;
4074: }
4075: if (prefixes & PREFIX_DATA)
4076: dflag ^= 1;
4077: if (prefixes & PREFIX_ADR)
4078: aflag ^= 1;
4079: }
4080:
4081: s->prefix = prefixes;
4082: s->aflag = aflag;
4083: s->dflag = dflag;
4084:
4085: /* lock generation */
4086: if (prefixes & PREFIX_LOCK)
1.1.1.7 ! root 4087: gen_helper_lock();
1.1 root 4088:
4089: /* now check op code */
4090: reswitch:
4091: switch(b) {
4092: case 0x0f:
4093: /**************************/
4094: /* extended op code */
4095: b = ldub_code(s->pc++) | 0x100;
4096: goto reswitch;
1.1.1.6 root 4097:
1.1 root 4098: /**************************/
4099: /* arith & logic */
4100: case 0x00 ... 0x05:
4101: case 0x08 ... 0x0d:
4102: case 0x10 ... 0x15:
4103: case 0x18 ... 0x1d:
4104: case 0x20 ... 0x25:
4105: case 0x28 ... 0x2d:
4106: case 0x30 ... 0x35:
4107: case 0x38 ... 0x3d:
4108: {
4109: int op, f, val;
4110: op = (b >> 3) & 7;
4111: f = (b >> 1) & 3;
4112:
4113: if ((b & 1) == 0)
4114: ot = OT_BYTE;
4115: else
4116: ot = dflag + OT_WORD;
1.1.1.6 root 4117:
1.1 root 4118: switch(f) {
4119: case 0: /* OP Ev, Gv */
4120: modrm = ldub_code(s->pc++);
4121: reg = ((modrm >> 3) & 7) | rex_r;
4122: mod = (modrm >> 6) & 3;
4123: rm = (modrm & 7) | REX_B(s);
4124: if (mod != 3) {
4125: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
4126: opreg = OR_TMP0;
4127: } else if (op == OP_XORL && rm == reg) {
4128: xor_zero:
4129: /* xor reg, reg optimisation */
4130: gen_op_movl_T0_0();
4131: s->cc_op = CC_OP_LOGICB + ot;
1.1.1.7 ! root 4132: gen_op_mov_reg_T0(ot, reg);
1.1 root 4133: gen_op_update1_cc();
4134: break;
4135: } else {
4136: opreg = rm;
4137: }
1.1.1.7 ! root 4138: gen_op_mov_TN_reg(ot, 1, reg);
1.1 root 4139: gen_op(s, op, ot, opreg);
4140: break;
4141: case 1: /* OP Gv, Ev */
4142: modrm = ldub_code(s->pc++);
4143: mod = (modrm >> 6) & 3;
4144: reg = ((modrm >> 3) & 7) | rex_r;
4145: rm = (modrm & 7) | REX_B(s);
4146: if (mod != 3) {
4147: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 4148: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 4149: } else if (op == OP_XORL && rm == reg) {
4150: goto xor_zero;
4151: } else {
1.1.1.7 ! root 4152: gen_op_mov_TN_reg(ot, 1, rm);
1.1 root 4153: }
4154: gen_op(s, op, ot, reg);
4155: break;
4156: case 2: /* OP A, Iv */
4157: val = insn_get(s, ot);
4158: gen_op_movl_T1_im(val);
4159: gen_op(s, op, ot, OR_EAX);
4160: break;
4161: }
4162: }
4163: break;
4164:
1.1.1.7 ! root 4165: case 0x82:
! 4166: if (CODE64(s))
! 4167: goto illegal_op;
1.1 root 4168: case 0x80: /* GRP1 */
4169: case 0x81:
4170: case 0x83:
4171: {
4172: int val;
4173:
4174: if ((b & 1) == 0)
4175: ot = OT_BYTE;
4176: else
4177: ot = dflag + OT_WORD;
1.1.1.6 root 4178:
1.1 root 4179: modrm = ldub_code(s->pc++);
4180: mod = (modrm >> 6) & 3;
4181: rm = (modrm & 7) | REX_B(s);
4182: op = (modrm >> 3) & 7;
1.1.1.6 root 4183:
1.1 root 4184: if (mod != 3) {
4185: if (b == 0x83)
4186: s->rip_offset = 1;
4187: else
4188: s->rip_offset = insn_const_size(ot);
4189: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
4190: opreg = OR_TMP0;
4191: } else {
4192: opreg = rm;
4193: }
4194:
4195: switch(b) {
4196: default:
4197: case 0x80:
4198: case 0x81:
4199: case 0x82:
4200: val = insn_get(s, ot);
4201: break;
4202: case 0x83:
4203: val = (int8_t)insn_get(s, OT_BYTE);
4204: break;
4205: }
4206: gen_op_movl_T1_im(val);
4207: gen_op(s, op, ot, opreg);
4208: }
4209: break;
4210:
4211: /**************************/
4212: /* inc, dec, and other misc arith */
4213: case 0x40 ... 0x47: /* inc Gv */
4214: ot = dflag ? OT_LONG : OT_WORD;
4215: gen_inc(s, ot, OR_EAX + (b & 7), 1);
4216: break;
4217: case 0x48 ... 0x4f: /* dec Gv */
4218: ot = dflag ? OT_LONG : OT_WORD;
4219: gen_inc(s, ot, OR_EAX + (b & 7), -1);
4220: break;
4221: case 0xf6: /* GRP3 */
4222: case 0xf7:
4223: if ((b & 1) == 0)
4224: ot = OT_BYTE;
4225: else
4226: ot = dflag + OT_WORD;
4227:
4228: modrm = ldub_code(s->pc++);
4229: mod = (modrm >> 6) & 3;
4230: rm = (modrm & 7) | REX_B(s);
4231: op = (modrm >> 3) & 7;
4232: if (mod != 3) {
4233: if (op == 0)
4234: s->rip_offset = insn_const_size(ot);
4235: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 4236: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 4237: } else {
1.1.1.7 ! root 4238: gen_op_mov_TN_reg(ot, 0, rm);
1.1 root 4239: }
4240:
4241: switch(op) {
4242: case 0: /* test */
4243: val = insn_get(s, ot);
4244: gen_op_movl_T1_im(val);
4245: gen_op_testl_T0_T1_cc();
4246: s->cc_op = CC_OP_LOGICB + ot;
4247: break;
4248: case 2: /* not */
1.1.1.7 ! root 4249: tcg_gen_not_tl(cpu_T[0], cpu_T[0]);
1.1 root 4250: if (mod != 3) {
1.1.1.7 ! root 4251: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 4252: } else {
1.1.1.7 ! root 4253: gen_op_mov_reg_T0(ot, rm);
1.1 root 4254: }
4255: break;
4256: case 3: /* neg */
1.1.1.7 ! root 4257: tcg_gen_neg_tl(cpu_T[0], cpu_T[0]);
1.1 root 4258: if (mod != 3) {
1.1.1.7 ! root 4259: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 4260: } else {
1.1.1.7 ! root 4261: gen_op_mov_reg_T0(ot, rm);
1.1 root 4262: }
4263: gen_op_update_neg_cc();
4264: s->cc_op = CC_OP_SUBB + ot;
4265: break;
4266: case 4: /* mul */
4267: switch(ot) {
4268: case OT_BYTE:
1.1.1.7 ! root 4269: gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX);
! 4270: tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]);
! 4271: tcg_gen_ext8u_tl(cpu_T[1], cpu_T[1]);
! 4272: /* XXX: use 32 bit mul which could be faster */
! 4273: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4274: gen_op_mov_reg_T0(OT_WORD, R_EAX);
! 4275: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4276: tcg_gen_andi_tl(cpu_cc_src, cpu_T[0], 0xff00);
1.1 root 4277: s->cc_op = CC_OP_MULB;
4278: break;
4279: case OT_WORD:
1.1.1.7 ! root 4280: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
! 4281: tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]);
! 4282: tcg_gen_ext16u_tl(cpu_T[1], cpu_T[1]);
! 4283: /* XXX: use 32 bit mul which could be faster */
! 4284: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4285: gen_op_mov_reg_T0(OT_WORD, R_EAX);
! 4286: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4287: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
! 4288: gen_op_mov_reg_T0(OT_WORD, R_EDX);
! 4289: tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
1.1 root 4290: s->cc_op = CC_OP_MULW;
4291: break;
4292: default:
4293: case OT_LONG:
1.1.1.7 ! root 4294: #ifdef TARGET_X86_64
! 4295: gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
! 4296: tcg_gen_ext32u_tl(cpu_T[0], cpu_T[0]);
! 4297: tcg_gen_ext32u_tl(cpu_T[1], cpu_T[1]);
! 4298: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4299: gen_op_mov_reg_T0(OT_LONG, R_EAX);
! 4300: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4301: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
! 4302: gen_op_mov_reg_T0(OT_LONG, R_EDX);
! 4303: tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
! 4304: #else
! 4305: {
! 4306: TCGv_i64 t0, t1;
! 4307: t0 = tcg_temp_new_i64();
! 4308: t1 = tcg_temp_new_i64();
! 4309: gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
! 4310: tcg_gen_extu_i32_i64(t0, cpu_T[0]);
! 4311: tcg_gen_extu_i32_i64(t1, cpu_T[1]);
! 4312: tcg_gen_mul_i64(t0, t0, t1);
! 4313: tcg_gen_trunc_i64_i32(cpu_T[0], t0);
! 4314: gen_op_mov_reg_T0(OT_LONG, R_EAX);
! 4315: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4316: tcg_gen_shri_i64(t0, t0, 32);
! 4317: tcg_gen_trunc_i64_i32(cpu_T[0], t0);
! 4318: gen_op_mov_reg_T0(OT_LONG, R_EDX);
! 4319: tcg_gen_mov_tl(cpu_cc_src, cpu_T[0]);
! 4320: }
! 4321: #endif
1.1 root 4322: s->cc_op = CC_OP_MULL;
4323: break;
4324: #ifdef TARGET_X86_64
4325: case OT_QUAD:
1.1.1.7 ! root 4326: gen_helper_mulq_EAX_T0(cpu_T[0]);
1.1 root 4327: s->cc_op = CC_OP_MULQ;
4328: break;
4329: #endif
4330: }
4331: break;
4332: case 5: /* imul */
4333: switch(ot) {
4334: case OT_BYTE:
1.1.1.7 ! root 4335: gen_op_mov_TN_reg(OT_BYTE, 1, R_EAX);
! 4336: tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
! 4337: tcg_gen_ext8s_tl(cpu_T[1], cpu_T[1]);
! 4338: /* XXX: use 32 bit mul which could be faster */
! 4339: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4340: gen_op_mov_reg_T0(OT_WORD, R_EAX);
! 4341: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4342: tcg_gen_ext8s_tl(cpu_tmp0, cpu_T[0]);
! 4343: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
1.1 root 4344: s->cc_op = CC_OP_MULB;
4345: break;
4346: case OT_WORD:
1.1.1.7 ! root 4347: gen_op_mov_TN_reg(OT_WORD, 1, R_EAX);
! 4348: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
! 4349: tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]);
! 4350: /* XXX: use 32 bit mul which could be faster */
! 4351: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4352: gen_op_mov_reg_T0(OT_WORD, R_EAX);
! 4353: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4354: tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]);
! 4355: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
! 4356: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 16);
! 4357: gen_op_mov_reg_T0(OT_WORD, R_EDX);
1.1 root 4358: s->cc_op = CC_OP_MULW;
4359: break;
4360: default:
4361: case OT_LONG:
1.1.1.7 ! root 4362: #ifdef TARGET_X86_64
! 4363: gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
! 4364: tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
! 4365: tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
! 4366: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4367: gen_op_mov_reg_T0(OT_LONG, R_EAX);
! 4368: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4369: tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
! 4370: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
! 4371: tcg_gen_shri_tl(cpu_T[0], cpu_T[0], 32);
! 4372: gen_op_mov_reg_T0(OT_LONG, R_EDX);
! 4373: #else
! 4374: {
! 4375: TCGv_i64 t0, t1;
! 4376: t0 = tcg_temp_new_i64();
! 4377: t1 = tcg_temp_new_i64();
! 4378: gen_op_mov_TN_reg(OT_LONG, 1, R_EAX);
! 4379: tcg_gen_ext_i32_i64(t0, cpu_T[0]);
! 4380: tcg_gen_ext_i32_i64(t1, cpu_T[1]);
! 4381: tcg_gen_mul_i64(t0, t0, t1);
! 4382: tcg_gen_trunc_i64_i32(cpu_T[0], t0);
! 4383: gen_op_mov_reg_T0(OT_LONG, R_EAX);
! 4384: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4385: tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
! 4386: tcg_gen_shri_i64(t0, t0, 32);
! 4387: tcg_gen_trunc_i64_i32(cpu_T[0], t0);
! 4388: gen_op_mov_reg_T0(OT_LONG, R_EDX);
! 4389: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
! 4390: }
! 4391: #endif
1.1 root 4392: s->cc_op = CC_OP_MULL;
4393: break;
4394: #ifdef TARGET_X86_64
4395: case OT_QUAD:
1.1.1.7 ! root 4396: gen_helper_imulq_EAX_T0(cpu_T[0]);
1.1 root 4397: s->cc_op = CC_OP_MULQ;
4398: break;
4399: #endif
4400: }
4401: break;
4402: case 6: /* div */
4403: switch(ot) {
4404: case OT_BYTE:
4405: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4406: gen_helper_divb_AL(cpu_T[0]);
1.1 root 4407: break;
4408: case OT_WORD:
4409: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4410: gen_helper_divw_AX(cpu_T[0]);
1.1 root 4411: break;
4412: default:
4413: case OT_LONG:
4414: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4415: gen_helper_divl_EAX(cpu_T[0]);
1.1 root 4416: break;
4417: #ifdef TARGET_X86_64
4418: case OT_QUAD:
4419: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4420: gen_helper_divq_EAX(cpu_T[0]);
1.1 root 4421: break;
4422: #endif
4423: }
4424: break;
4425: case 7: /* idiv */
4426: switch(ot) {
4427: case OT_BYTE:
4428: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4429: gen_helper_idivb_AL(cpu_T[0]);
1.1 root 4430: break;
4431: case OT_WORD:
4432: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4433: gen_helper_idivw_AX(cpu_T[0]);
1.1 root 4434: break;
4435: default:
4436: case OT_LONG:
4437: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4438: gen_helper_idivl_EAX(cpu_T[0]);
1.1 root 4439: break;
4440: #ifdef TARGET_X86_64
4441: case OT_QUAD:
4442: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4443: gen_helper_idivq_EAX(cpu_T[0]);
1.1 root 4444: break;
4445: #endif
4446: }
4447: break;
4448: default:
4449: goto illegal_op;
4450: }
4451: break;
4452:
4453: case 0xfe: /* GRP4 */
4454: case 0xff: /* GRP5 */
4455: if ((b & 1) == 0)
4456: ot = OT_BYTE;
4457: else
4458: ot = dflag + OT_WORD;
4459:
4460: modrm = ldub_code(s->pc++);
4461: mod = (modrm >> 6) & 3;
4462: rm = (modrm & 7) | REX_B(s);
4463: op = (modrm >> 3) & 7;
4464: if (op >= 2 && b == 0xfe) {
4465: goto illegal_op;
4466: }
4467: if (CODE64(s)) {
4468: if (op == 2 || op == 4) {
4469: /* operand size for jumps is 64 bit */
4470: ot = OT_QUAD;
4471: } else if (op == 3 || op == 5) {
4472: /* for call calls, the operand is 16 or 32 bit, even
4473: in long mode */
4474: ot = dflag ? OT_LONG : OT_WORD;
4475: } else if (op == 6) {
4476: /* default push size is 64 bit */
4477: ot = dflag ? OT_QUAD : OT_WORD;
4478: }
4479: }
4480: if (mod != 3) {
4481: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
4482: if (op >= 2 && op != 3 && op != 5)
1.1.1.7 ! root 4483: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 4484: } else {
1.1.1.7 ! root 4485: gen_op_mov_TN_reg(ot, 0, rm);
1.1 root 4486: }
4487:
4488: switch(op) {
4489: case 0: /* inc Ev */
4490: if (mod != 3)
4491: opreg = OR_TMP0;
4492: else
4493: opreg = rm;
4494: gen_inc(s, ot, opreg, 1);
4495: break;
4496: case 1: /* dec Ev */
4497: if (mod != 3)
4498: opreg = OR_TMP0;
4499: else
4500: opreg = rm;
4501: gen_inc(s, ot, opreg, -1);
4502: break;
4503: case 2: /* call Ev */
4504: /* XXX: optimize if memory (no 'and' is necessary) */
4505: if (s->dflag == 0)
4506: gen_op_andl_T0_ffff();
4507: next_eip = s->pc - s->cs_base;
4508: gen_movtl_T1_im(next_eip);
4509: gen_push_T1(s);
4510: gen_op_jmp_T0();
4511: gen_eob(s);
4512: break;
4513: case 3: /* lcall Ev */
1.1.1.7 ! root 4514: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 4515: gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
1.1.1.7 ! root 4516: gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
1.1 root 4517: do_lcall:
4518: if (s->pe && !s->vm86) {
4519: if (s->cc_op != CC_OP_DYNAMIC)
4520: gen_op_set_cc_op(s->cc_op);
4521: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4522: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 4523: gen_helper_lcall_protected(cpu_tmp2_i32, cpu_T[1],
! 4524: tcg_const_i32(dflag),
! 4525: tcg_const_i32(s->pc - pc_start));
! 4526: } else {
! 4527: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 4528: gen_helper_lcall_real(cpu_tmp2_i32, cpu_T[1],
! 4529: tcg_const_i32(dflag),
! 4530: tcg_const_i32(s->pc - s->cs_base));
1.1 root 4531: }
4532: gen_eob(s);
4533: break;
4534: case 4: /* jmp Ev */
4535: if (s->dflag == 0)
4536: gen_op_andl_T0_ffff();
4537: gen_op_jmp_T0();
4538: gen_eob(s);
4539: break;
4540: case 5: /* ljmp Ev */
1.1.1.7 ! root 4541: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 4542: gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
1.1.1.7 ! root 4543: gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
1.1 root 4544: do_ljmp:
4545: if (s->pe && !s->vm86) {
4546: if (s->cc_op != CC_OP_DYNAMIC)
4547: gen_op_set_cc_op(s->cc_op);
4548: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 4549: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 4550: gen_helper_ljmp_protected(cpu_tmp2_i32, cpu_T[1],
! 4551: tcg_const_i32(s->pc - pc_start));
1.1 root 4552: } else {
1.1.1.7 ! root 4553: gen_op_movl_seg_T0_vm(R_CS);
1.1 root 4554: gen_op_movl_T0_T1();
4555: gen_op_jmp_T0();
4556: }
4557: gen_eob(s);
4558: break;
4559: case 6: /* push Ev */
4560: gen_push_T0(s);
4561: break;
4562: default:
4563: goto illegal_op;
4564: }
4565: break;
4566:
4567: case 0x84: /* test Ev, Gv */
1.1.1.6 root 4568: case 0x85:
1.1 root 4569: if ((b & 1) == 0)
4570: ot = OT_BYTE;
4571: else
4572: ot = dflag + OT_WORD;
4573:
4574: modrm = ldub_code(s->pc++);
4575: mod = (modrm >> 6) & 3;
4576: rm = (modrm & 7) | REX_B(s);
4577: reg = ((modrm >> 3) & 7) | rex_r;
1.1.1.6 root 4578:
1.1 root 4579: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1.1.1.7 ! root 4580: gen_op_mov_TN_reg(ot, 1, reg);
1.1 root 4581: gen_op_testl_T0_T1_cc();
4582: s->cc_op = CC_OP_LOGICB + ot;
4583: break;
1.1.1.6 root 4584:
1.1 root 4585: case 0xa8: /* test eAX, Iv */
4586: case 0xa9:
4587: if ((b & 1) == 0)
4588: ot = OT_BYTE;
4589: else
4590: ot = dflag + OT_WORD;
4591: val = insn_get(s, ot);
4592:
1.1.1.7 ! root 4593: gen_op_mov_TN_reg(ot, 0, OR_EAX);
1.1 root 4594: gen_op_movl_T1_im(val);
4595: gen_op_testl_T0_T1_cc();
4596: s->cc_op = CC_OP_LOGICB + ot;
4597: break;
1.1.1.6 root 4598:
1.1 root 4599: case 0x98: /* CWDE/CBW */
4600: #ifdef TARGET_X86_64
4601: if (dflag == 2) {
1.1.1.7 ! root 4602: gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
! 4603: tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
! 4604: gen_op_mov_reg_T0(OT_QUAD, R_EAX);
1.1 root 4605: } else
4606: #endif
1.1.1.7 ! root 4607: if (dflag == 1) {
! 4608: gen_op_mov_TN_reg(OT_WORD, 0, R_EAX);
! 4609: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
! 4610: gen_op_mov_reg_T0(OT_LONG, R_EAX);
! 4611: } else {
! 4612: gen_op_mov_TN_reg(OT_BYTE, 0, R_EAX);
! 4613: tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
! 4614: gen_op_mov_reg_T0(OT_WORD, R_EAX);
! 4615: }
1.1 root 4616: break;
4617: case 0x99: /* CDQ/CWD */
4618: #ifdef TARGET_X86_64
4619: if (dflag == 2) {
1.1.1.7 ! root 4620: gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX);
! 4621: tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 63);
! 4622: gen_op_mov_reg_T0(OT_QUAD, R_EDX);
1.1 root 4623: } else
4624: #endif
1.1.1.7 ! root 4625: if (dflag == 1) {
! 4626: gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
! 4627: tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
! 4628: tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 31);
! 4629: gen_op_mov_reg_T0(OT_LONG, R_EDX);
! 4630: } else {
! 4631: gen_op_mov_TN_reg(OT_WORD, 0, R_EAX);
! 4632: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
! 4633: tcg_gen_sari_tl(cpu_T[0], cpu_T[0], 15);
! 4634: gen_op_mov_reg_T0(OT_WORD, R_EDX);
! 4635: }
1.1 root 4636: break;
4637: case 0x1af: /* imul Gv, Ev */
4638: case 0x69: /* imul Gv, Ev, I */
4639: case 0x6b:
4640: ot = dflag + OT_WORD;
4641: modrm = ldub_code(s->pc++);
4642: reg = ((modrm >> 3) & 7) | rex_r;
4643: if (b == 0x69)
4644: s->rip_offset = insn_const_size(ot);
4645: else if (b == 0x6b)
4646: s->rip_offset = 1;
4647: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
4648: if (b == 0x69) {
4649: val = insn_get(s, ot);
4650: gen_op_movl_T1_im(val);
4651: } else if (b == 0x6b) {
4652: val = (int8_t)insn_get(s, OT_BYTE);
4653: gen_op_movl_T1_im(val);
4654: } else {
1.1.1.7 ! root 4655: gen_op_mov_TN_reg(ot, 1, reg);
1.1 root 4656: }
4657:
4658: #ifdef TARGET_X86_64
4659: if (ot == OT_QUAD) {
1.1.1.7 ! root 4660: gen_helper_imulq_T0_T1(cpu_T[0], cpu_T[0], cpu_T[1]);
1.1 root 4661: } else
4662: #endif
4663: if (ot == OT_LONG) {
1.1.1.7 ! root 4664: #ifdef TARGET_X86_64
! 4665: tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
! 4666: tcg_gen_ext32s_tl(cpu_T[1], cpu_T[1]);
! 4667: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4668: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4669: tcg_gen_ext32s_tl(cpu_tmp0, cpu_T[0]);
! 4670: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
! 4671: #else
! 4672: {
! 4673: TCGv_i64 t0, t1;
! 4674: t0 = tcg_temp_new_i64();
! 4675: t1 = tcg_temp_new_i64();
! 4676: tcg_gen_ext_i32_i64(t0, cpu_T[0]);
! 4677: tcg_gen_ext_i32_i64(t1, cpu_T[1]);
! 4678: tcg_gen_mul_i64(t0, t0, t1);
! 4679: tcg_gen_trunc_i64_i32(cpu_T[0], t0);
! 4680: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4681: tcg_gen_sari_tl(cpu_tmp0, cpu_T[0], 31);
! 4682: tcg_gen_shri_i64(t0, t0, 32);
! 4683: tcg_gen_trunc_i64_i32(cpu_T[1], t0);
! 4684: tcg_gen_sub_tl(cpu_cc_src, cpu_T[1], cpu_tmp0);
! 4685: }
! 4686: #endif
1.1 root 4687: } else {
1.1.1.7 ! root 4688: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
! 4689: tcg_gen_ext16s_tl(cpu_T[1], cpu_T[1]);
! 4690: /* XXX: use 32 bit mul which could be faster */
! 4691: tcg_gen_mul_tl(cpu_T[0], cpu_T[0], cpu_T[1]);
! 4692: tcg_gen_mov_tl(cpu_cc_dst, cpu_T[0]);
! 4693: tcg_gen_ext16s_tl(cpu_tmp0, cpu_T[0]);
! 4694: tcg_gen_sub_tl(cpu_cc_src, cpu_T[0], cpu_tmp0);
1.1 root 4695: }
1.1.1.7 ! root 4696: gen_op_mov_reg_T0(ot, reg);
1.1 root 4697: s->cc_op = CC_OP_MULB + ot;
4698: break;
4699: case 0x1c0:
4700: case 0x1c1: /* xadd Ev, Gv */
4701: if ((b & 1) == 0)
4702: ot = OT_BYTE;
4703: else
4704: ot = dflag + OT_WORD;
4705: modrm = ldub_code(s->pc++);
4706: reg = ((modrm >> 3) & 7) | rex_r;
4707: mod = (modrm >> 6) & 3;
4708: if (mod == 3) {
4709: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 4710: gen_op_mov_TN_reg(ot, 0, reg);
! 4711: gen_op_mov_TN_reg(ot, 1, rm);
1.1 root 4712: gen_op_addl_T0_T1();
1.1.1.7 ! root 4713: gen_op_mov_reg_T1(ot, reg);
! 4714: gen_op_mov_reg_T0(ot, rm);
1.1 root 4715: } else {
4716: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 4717: gen_op_mov_TN_reg(ot, 0, reg);
! 4718: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 4719: gen_op_addl_T0_T1();
1.1.1.7 ! root 4720: gen_op_st_T0_A0(ot + s->mem_index);
! 4721: gen_op_mov_reg_T1(ot, reg);
1.1 root 4722: }
4723: gen_op_update2_cc();
4724: s->cc_op = CC_OP_ADDB + ot;
4725: break;
4726: case 0x1b0:
4727: case 0x1b1: /* cmpxchg Ev, Gv */
1.1.1.7 ! root 4728: {
! 4729: int label1, label2;
! 4730: TCGv t0, t1, t2, a0;
! 4731:
! 4732: if ((b & 1) == 0)
! 4733: ot = OT_BYTE;
! 4734: else
! 4735: ot = dflag + OT_WORD;
! 4736: modrm = ldub_code(s->pc++);
! 4737: reg = ((modrm >> 3) & 7) | rex_r;
! 4738: mod = (modrm >> 6) & 3;
! 4739: t0 = tcg_temp_local_new();
! 4740: t1 = tcg_temp_local_new();
! 4741: t2 = tcg_temp_local_new();
! 4742: a0 = tcg_temp_local_new();
! 4743: gen_op_mov_v_reg(ot, t1, reg);
! 4744: if (mod == 3) {
! 4745: rm = (modrm & 7) | REX_B(s);
! 4746: gen_op_mov_v_reg(ot, t0, rm);
! 4747: } else {
! 4748: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 4749: tcg_gen_mov_tl(a0, cpu_A0);
! 4750: gen_op_ld_v(ot + s->mem_index, t0, a0);
! 4751: rm = 0; /* avoid warning */
! 4752: }
! 4753: label1 = gen_new_label();
! 4754: tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUState, regs[R_EAX]));
! 4755: tcg_gen_sub_tl(t2, t2, t0);
! 4756: gen_extu(ot, t2);
! 4757: tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
! 4758: if (mod == 3) {
! 4759: label2 = gen_new_label();
! 4760: gen_op_mov_reg_v(ot, R_EAX, t0);
! 4761: tcg_gen_br(label2);
! 4762: gen_set_label(label1);
! 4763: gen_op_mov_reg_v(ot, rm, t1);
! 4764: gen_set_label(label2);
! 4765: } else {
! 4766: tcg_gen_mov_tl(t1, t0);
! 4767: gen_op_mov_reg_v(ot, R_EAX, t0);
! 4768: gen_set_label(label1);
! 4769: /* always store */
! 4770: gen_op_st_v(ot + s->mem_index, t1, a0);
! 4771: }
! 4772: tcg_gen_mov_tl(cpu_cc_src, t0);
! 4773: tcg_gen_mov_tl(cpu_cc_dst, t2);
! 4774: s->cc_op = CC_OP_SUBB + ot;
! 4775: tcg_temp_free(t0);
! 4776: tcg_temp_free(t1);
! 4777: tcg_temp_free(t2);
! 4778: tcg_temp_free(a0);
1.1 root 4779: }
4780: break;
4781: case 0x1c7: /* cmpxchg8b */
4782: modrm = ldub_code(s->pc++);
4783: mod = (modrm >> 6) & 3;
1.1.1.6 root 4784: if ((mod == 3) || ((modrm & 0x38) != 0x8))
1.1 root 4785: goto illegal_op;
1.1.1.7 ! root 4786: #ifdef TARGET_X86_64
! 4787: if (dflag == 2) {
! 4788: if (!(s->cpuid_ext_features & CPUID_EXT_CX16))
! 4789: goto illegal_op;
! 4790: gen_jmp_im(pc_start - s->cs_base);
! 4791: if (s->cc_op != CC_OP_DYNAMIC)
! 4792: gen_op_set_cc_op(s->cc_op);
! 4793: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 4794: gen_helper_cmpxchg16b(cpu_A0);
! 4795: } else
! 4796: #endif
! 4797: {
! 4798: if (!(s->cpuid_features & CPUID_CX8))
! 4799: goto illegal_op;
! 4800: gen_jmp_im(pc_start - s->cs_base);
! 4801: if (s->cc_op != CC_OP_DYNAMIC)
! 4802: gen_op_set_cc_op(s->cc_op);
! 4803: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 4804: gen_helper_cmpxchg8b(cpu_A0);
! 4805: }
1.1 root 4806: s->cc_op = CC_OP_EFLAGS;
4807: break;
1.1.1.6 root 4808:
1.1 root 4809: /**************************/
4810: /* push/pop */
4811: case 0x50 ... 0x57: /* push */
1.1.1.7 ! root 4812: gen_op_mov_TN_reg(OT_LONG, 0, (b & 7) | REX_B(s));
1.1 root 4813: gen_push_T0(s);
4814: break;
4815: case 0x58 ... 0x5f: /* pop */
4816: if (CODE64(s)) {
4817: ot = dflag ? OT_QUAD : OT_WORD;
4818: } else {
4819: ot = dflag + OT_WORD;
4820: }
4821: gen_pop_T0(s);
4822: /* NOTE: order is important for pop %sp */
4823: gen_pop_update(s);
1.1.1.7 ! root 4824: gen_op_mov_reg_T0(ot, (b & 7) | REX_B(s));
1.1 root 4825: break;
4826: case 0x60: /* pusha */
4827: if (CODE64(s))
4828: goto illegal_op;
4829: gen_pusha(s);
4830: break;
4831: case 0x61: /* popa */
4832: if (CODE64(s))
4833: goto illegal_op;
4834: gen_popa(s);
4835: break;
4836: case 0x68: /* push Iv */
4837: case 0x6a:
4838: if (CODE64(s)) {
4839: ot = dflag ? OT_QUAD : OT_WORD;
4840: } else {
4841: ot = dflag + OT_WORD;
4842: }
4843: if (b == 0x68)
4844: val = insn_get(s, ot);
4845: else
4846: val = (int8_t)insn_get(s, OT_BYTE);
4847: gen_op_movl_T0_im(val);
4848: gen_push_T0(s);
4849: break;
4850: case 0x8f: /* pop Ev */
4851: if (CODE64(s)) {
4852: ot = dflag ? OT_QUAD : OT_WORD;
4853: } else {
4854: ot = dflag + OT_WORD;
4855: }
4856: modrm = ldub_code(s->pc++);
4857: mod = (modrm >> 6) & 3;
4858: gen_pop_T0(s);
4859: if (mod == 3) {
4860: /* NOTE: order is important for pop %sp */
4861: gen_pop_update(s);
4862: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 4863: gen_op_mov_reg_T0(ot, rm);
1.1 root 4864: } else {
4865: /* NOTE: order is important too for MMU exceptions */
4866: s->popl_esp_hack = 1 << ot;
4867: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
4868: s->popl_esp_hack = 0;
4869: gen_pop_update(s);
4870: }
4871: break;
4872: case 0xc8: /* enter */
4873: {
4874: int level;
4875: val = lduw_code(s->pc);
4876: s->pc += 2;
4877: level = ldub_code(s->pc++);
4878: gen_enter(s, val, level);
4879: }
4880: break;
4881: case 0xc9: /* leave */
4882: /* XXX: exception not precise (ESP is updated before potential exception) */
4883: if (CODE64(s)) {
1.1.1.7 ! root 4884: gen_op_mov_TN_reg(OT_QUAD, 0, R_EBP);
! 4885: gen_op_mov_reg_T0(OT_QUAD, R_ESP);
1.1 root 4886: } else if (s->ss32) {
1.1.1.7 ! root 4887: gen_op_mov_TN_reg(OT_LONG, 0, R_EBP);
! 4888: gen_op_mov_reg_T0(OT_LONG, R_ESP);
1.1 root 4889: } else {
1.1.1.7 ! root 4890: gen_op_mov_TN_reg(OT_WORD, 0, R_EBP);
! 4891: gen_op_mov_reg_T0(OT_WORD, R_ESP);
1.1 root 4892: }
4893: gen_pop_T0(s);
4894: if (CODE64(s)) {
4895: ot = dflag ? OT_QUAD : OT_WORD;
4896: } else {
4897: ot = dflag + OT_WORD;
4898: }
1.1.1.7 ! root 4899: gen_op_mov_reg_T0(ot, R_EBP);
1.1 root 4900: gen_pop_update(s);
4901: break;
4902: case 0x06: /* push es */
4903: case 0x0e: /* push cs */
4904: case 0x16: /* push ss */
4905: case 0x1e: /* push ds */
4906: if (CODE64(s))
4907: goto illegal_op;
4908: gen_op_movl_T0_seg(b >> 3);
4909: gen_push_T0(s);
4910: break;
4911: case 0x1a0: /* push fs */
4912: case 0x1a8: /* push gs */
4913: gen_op_movl_T0_seg((b >> 3) & 7);
4914: gen_push_T0(s);
4915: break;
4916: case 0x07: /* pop es */
4917: case 0x17: /* pop ss */
4918: case 0x1f: /* pop ds */
4919: if (CODE64(s))
4920: goto illegal_op;
4921: reg = b >> 3;
4922: gen_pop_T0(s);
4923: gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
4924: gen_pop_update(s);
4925: if (reg == R_SS) {
4926: /* if reg == SS, inhibit interrupts/trace. */
4927: /* If several instructions disable interrupts, only the
4928: _first_ does it */
4929: if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
1.1.1.7 ! root 4930: gen_helper_set_inhibit_irq();
1.1 root 4931: s->tf = 0;
4932: }
4933: if (s->is_jmp) {
4934: gen_jmp_im(s->pc - s->cs_base);
4935: gen_eob(s);
4936: }
4937: break;
4938: case 0x1a1: /* pop fs */
4939: case 0x1a9: /* pop gs */
4940: gen_pop_T0(s);
4941: gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
4942: gen_pop_update(s);
4943: if (s->is_jmp) {
4944: gen_jmp_im(s->pc - s->cs_base);
4945: gen_eob(s);
4946: }
4947: break;
4948:
4949: /**************************/
4950: /* mov */
4951: case 0x88:
4952: case 0x89: /* mov Gv, Ev */
4953: if ((b & 1) == 0)
4954: ot = OT_BYTE;
4955: else
4956: ot = dflag + OT_WORD;
4957: modrm = ldub_code(s->pc++);
4958: reg = ((modrm >> 3) & 7) | rex_r;
1.1.1.6 root 4959:
1.1 root 4960: /* generate a generic store */
4961: gen_ldst_modrm(s, modrm, ot, reg, 1);
4962: break;
4963: case 0xc6:
4964: case 0xc7: /* mov Ev, Iv */
4965: if ((b & 1) == 0)
4966: ot = OT_BYTE;
4967: else
4968: ot = dflag + OT_WORD;
4969: modrm = ldub_code(s->pc++);
4970: mod = (modrm >> 6) & 3;
4971: if (mod != 3) {
4972: s->rip_offset = insn_const_size(ot);
4973: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
4974: }
4975: val = insn_get(s, ot);
4976: gen_op_movl_T0_im(val);
4977: if (mod != 3)
1.1.1.7 ! root 4978: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 4979: else
1.1.1.7 ! root 4980: gen_op_mov_reg_T0(ot, (modrm & 7) | REX_B(s));
1.1 root 4981: break;
4982: case 0x8a:
4983: case 0x8b: /* mov Ev, Gv */
4984: if ((b & 1) == 0)
4985: ot = OT_BYTE;
4986: else
4987: ot = OT_WORD + dflag;
4988: modrm = ldub_code(s->pc++);
4989: reg = ((modrm >> 3) & 7) | rex_r;
1.1.1.6 root 4990:
1.1 root 4991: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
1.1.1.7 ! root 4992: gen_op_mov_reg_T0(ot, reg);
1.1 root 4993: break;
4994: case 0x8e: /* mov seg, Gv */
4995: modrm = ldub_code(s->pc++);
4996: reg = (modrm >> 3) & 7;
4997: if (reg >= 6 || reg == R_CS)
4998: goto illegal_op;
4999: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
5000: gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
5001: if (reg == R_SS) {
5002: /* if reg == SS, inhibit interrupts/trace */
5003: /* If several instructions disable interrupts, only the
5004: _first_ does it */
5005: if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
1.1.1.7 ! root 5006: gen_helper_set_inhibit_irq();
1.1 root 5007: s->tf = 0;
5008: }
5009: if (s->is_jmp) {
5010: gen_jmp_im(s->pc - s->cs_base);
5011: gen_eob(s);
5012: }
5013: break;
5014: case 0x8c: /* mov Gv, seg */
5015: modrm = ldub_code(s->pc++);
5016: reg = (modrm >> 3) & 7;
5017: mod = (modrm >> 6) & 3;
5018: if (reg >= 6)
5019: goto illegal_op;
5020: gen_op_movl_T0_seg(reg);
5021: if (mod == 3)
5022: ot = OT_WORD + dflag;
5023: else
5024: ot = OT_WORD;
5025: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
5026: break;
5027:
5028: case 0x1b6: /* movzbS Gv, Eb */
5029: case 0x1b7: /* movzwS Gv, Eb */
5030: case 0x1be: /* movsbS Gv, Eb */
5031: case 0x1bf: /* movswS Gv, Eb */
5032: {
5033: int d_ot;
5034: /* d_ot is the size of destination */
5035: d_ot = dflag + OT_WORD;
5036: /* ot is the size of source */
5037: ot = (b & 1) + OT_BYTE;
5038: modrm = ldub_code(s->pc++);
5039: reg = ((modrm >> 3) & 7) | rex_r;
5040: mod = (modrm >> 6) & 3;
5041: rm = (modrm & 7) | REX_B(s);
1.1.1.6 root 5042:
1.1 root 5043: if (mod == 3) {
1.1.1.7 ! root 5044: gen_op_mov_TN_reg(ot, 0, rm);
1.1 root 5045: switch(ot | (b & 8)) {
5046: case OT_BYTE:
1.1.1.7 ! root 5047: tcg_gen_ext8u_tl(cpu_T[0], cpu_T[0]);
1.1 root 5048: break;
5049: case OT_BYTE | 8:
1.1.1.7 ! root 5050: tcg_gen_ext8s_tl(cpu_T[0], cpu_T[0]);
1.1 root 5051: break;
5052: case OT_WORD:
1.1.1.7 ! root 5053: tcg_gen_ext16u_tl(cpu_T[0], cpu_T[0]);
1.1 root 5054: break;
5055: default:
5056: case OT_WORD | 8:
1.1.1.7 ! root 5057: tcg_gen_ext16s_tl(cpu_T[0], cpu_T[0]);
1.1 root 5058: break;
5059: }
1.1.1.7 ! root 5060: gen_op_mov_reg_T0(d_ot, reg);
1.1 root 5061: } else {
5062: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
5063: if (b & 8) {
1.1.1.7 ! root 5064: gen_op_lds_T0_A0(ot + s->mem_index);
1.1 root 5065: } else {
1.1.1.7 ! root 5066: gen_op_ldu_T0_A0(ot + s->mem_index);
1.1 root 5067: }
1.1.1.7 ! root 5068: gen_op_mov_reg_T0(d_ot, reg);
1.1 root 5069: }
5070: }
5071: break;
5072:
5073: case 0x8d: /* lea */
5074: ot = dflag + OT_WORD;
5075: modrm = ldub_code(s->pc++);
5076: mod = (modrm >> 6) & 3;
5077: if (mod == 3)
5078: goto illegal_op;
5079: reg = ((modrm >> 3) & 7) | rex_r;
5080: /* we must ensure that no segment is added */
5081: s->override = -1;
5082: val = s->addseg;
5083: s->addseg = 0;
5084: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
5085: s->addseg = val;
1.1.1.7 ! root 5086: gen_op_mov_reg_A0(ot - OT_WORD, reg);
1.1 root 5087: break;
1.1.1.6 root 5088:
1.1 root 5089: case 0xa0: /* mov EAX, Ov */
5090: case 0xa1:
5091: case 0xa2: /* mov Ov, EAX */
5092: case 0xa3:
5093: {
5094: target_ulong offset_addr;
5095:
5096: if ((b & 1) == 0)
5097: ot = OT_BYTE;
5098: else
5099: ot = dflag + OT_WORD;
5100: #ifdef TARGET_X86_64
5101: if (s->aflag == 2) {
5102: offset_addr = ldq_code(s->pc);
5103: s->pc += 8;
1.1.1.7 ! root 5104: gen_op_movq_A0_im(offset_addr);
1.1.1.6 root 5105: } else
1.1 root 5106: #endif
5107: {
5108: if (s->aflag) {
5109: offset_addr = insn_get(s, OT_LONG);
5110: } else {
5111: offset_addr = insn_get(s, OT_WORD);
5112: }
5113: gen_op_movl_A0_im(offset_addr);
5114: }
5115: gen_add_A0_ds_seg(s);
5116: if ((b & 2) == 0) {
1.1.1.7 ! root 5117: gen_op_ld_T0_A0(ot + s->mem_index);
! 5118: gen_op_mov_reg_T0(ot, R_EAX);
1.1 root 5119: } else {
1.1.1.7 ! root 5120: gen_op_mov_TN_reg(ot, 0, R_EAX);
! 5121: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 5122: }
5123: }
5124: break;
5125: case 0xd7: /* xlat */
5126: #ifdef TARGET_X86_64
5127: if (s->aflag == 2) {
1.1.1.7 ! root 5128: gen_op_movq_A0_reg(R_EBX);
! 5129: gen_op_mov_TN_reg(OT_QUAD, 0, R_EAX);
! 5130: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff);
! 5131: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]);
1.1.1.6 root 5132: } else
1.1 root 5133: #endif
5134: {
1.1.1.7 ! root 5135: gen_op_movl_A0_reg(R_EBX);
! 5136: gen_op_mov_TN_reg(OT_LONG, 0, R_EAX);
! 5137: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], 0xff);
! 5138: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_T[0]);
1.1 root 5139: if (s->aflag == 0)
5140: gen_op_andl_A0_ffff();
1.1.1.7 ! root 5141: else
! 5142: tcg_gen_andi_tl(cpu_A0, cpu_A0, 0xffffffff);
1.1 root 5143: }
5144: gen_add_A0_ds_seg(s);
1.1.1.7 ! root 5145: gen_op_ldu_T0_A0(OT_BYTE + s->mem_index);
! 5146: gen_op_mov_reg_T0(OT_BYTE, R_EAX);
1.1 root 5147: break;
5148: case 0xb0 ... 0xb7: /* mov R, Ib */
5149: val = insn_get(s, OT_BYTE);
5150: gen_op_movl_T0_im(val);
1.1.1.7 ! root 5151: gen_op_mov_reg_T0(OT_BYTE, (b & 7) | REX_B(s));
1.1 root 5152: break;
5153: case 0xb8 ... 0xbf: /* mov R, Iv */
5154: #ifdef TARGET_X86_64
5155: if (dflag == 2) {
5156: uint64_t tmp;
5157: /* 64 bit case */
5158: tmp = ldq_code(s->pc);
5159: s->pc += 8;
5160: reg = (b & 7) | REX_B(s);
5161: gen_movtl_T0_im(tmp);
1.1.1.7 ! root 5162: gen_op_mov_reg_T0(OT_QUAD, reg);
1.1.1.6 root 5163: } else
1.1 root 5164: #endif
5165: {
5166: ot = dflag ? OT_LONG : OT_WORD;
5167: val = insn_get(s, ot);
5168: reg = (b & 7) | REX_B(s);
5169: gen_op_movl_T0_im(val);
1.1.1.7 ! root 5170: gen_op_mov_reg_T0(ot, reg);
1.1 root 5171: }
5172: break;
5173:
5174: case 0x91 ... 0x97: /* xchg R, EAX */
5175: ot = dflag + OT_WORD;
5176: reg = (b & 7) | REX_B(s);
5177: rm = R_EAX;
5178: goto do_xchg_reg;
5179: case 0x86:
5180: case 0x87: /* xchg Ev, Gv */
5181: if ((b & 1) == 0)
5182: ot = OT_BYTE;
5183: else
5184: ot = dflag + OT_WORD;
5185: modrm = ldub_code(s->pc++);
5186: reg = ((modrm >> 3) & 7) | rex_r;
5187: mod = (modrm >> 6) & 3;
5188: if (mod == 3) {
5189: rm = (modrm & 7) | REX_B(s);
5190: do_xchg_reg:
1.1.1.7 ! root 5191: gen_op_mov_TN_reg(ot, 0, reg);
! 5192: gen_op_mov_TN_reg(ot, 1, rm);
! 5193: gen_op_mov_reg_T0(ot, rm);
! 5194: gen_op_mov_reg_T1(ot, reg);
1.1 root 5195: } else {
5196: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 5197: gen_op_mov_TN_reg(ot, 0, reg);
1.1 root 5198: /* for xchg, lock is implicit */
5199: if (!(prefixes & PREFIX_LOCK))
1.1.1.7 ! root 5200: gen_helper_lock();
! 5201: gen_op_ld_T1_A0(ot + s->mem_index);
! 5202: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 5203: if (!(prefixes & PREFIX_LOCK))
1.1.1.7 ! root 5204: gen_helper_unlock();
! 5205: gen_op_mov_reg_T1(ot, reg);
1.1 root 5206: }
5207: break;
5208: case 0xc4: /* les Gv */
5209: if (CODE64(s))
5210: goto illegal_op;
5211: op = R_ES;
5212: goto do_lxx;
5213: case 0xc5: /* lds Gv */
5214: if (CODE64(s))
5215: goto illegal_op;
5216: op = R_DS;
5217: goto do_lxx;
5218: case 0x1b2: /* lss Gv */
5219: op = R_SS;
5220: goto do_lxx;
5221: case 0x1b4: /* lfs Gv */
5222: op = R_FS;
5223: goto do_lxx;
5224: case 0x1b5: /* lgs Gv */
5225: op = R_GS;
5226: do_lxx:
5227: ot = dflag ? OT_LONG : OT_WORD;
5228: modrm = ldub_code(s->pc++);
5229: reg = ((modrm >> 3) & 7) | rex_r;
5230: mod = (modrm >> 6) & 3;
5231: if (mod == 3)
5232: goto illegal_op;
5233: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 5234: gen_op_ld_T1_A0(ot + s->mem_index);
1.1 root 5235: gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
5236: /* load the segment first to handle exceptions properly */
1.1.1.7 ! root 5237: gen_op_ldu_T0_A0(OT_WORD + s->mem_index);
1.1 root 5238: gen_movl_seg_T0(s, op, pc_start - s->cs_base);
5239: /* then put the data */
1.1.1.7 ! root 5240: gen_op_mov_reg_T1(ot, reg);
1.1 root 5241: if (s->is_jmp) {
5242: gen_jmp_im(s->pc - s->cs_base);
5243: gen_eob(s);
5244: }
5245: break;
1.1.1.6 root 5246:
1.1 root 5247: /************************/
5248: /* shifts */
5249: case 0xc0:
5250: case 0xc1:
5251: /* shift Ev,Ib */
5252: shift = 2;
5253: grp2:
5254: {
5255: if ((b & 1) == 0)
5256: ot = OT_BYTE;
5257: else
5258: ot = dflag + OT_WORD;
1.1.1.6 root 5259:
1.1 root 5260: modrm = ldub_code(s->pc++);
5261: mod = (modrm >> 6) & 3;
5262: op = (modrm >> 3) & 7;
1.1.1.6 root 5263:
1.1 root 5264: if (mod != 3) {
5265: if (shift == 2) {
5266: s->rip_offset = 1;
5267: }
5268: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
5269: opreg = OR_TMP0;
5270: } else {
5271: opreg = (modrm & 7) | REX_B(s);
5272: }
5273:
5274: /* simpler op */
5275: if (shift == 0) {
5276: gen_shift(s, op, ot, opreg, OR_ECX);
5277: } else {
5278: if (shift == 2) {
5279: shift = ldub_code(s->pc++);
5280: }
5281: gen_shifti(s, op, ot, opreg, shift);
5282: }
5283: }
5284: break;
5285: case 0xd0:
5286: case 0xd1:
5287: /* shift Ev,1 */
5288: shift = 1;
5289: goto grp2;
5290: case 0xd2:
5291: case 0xd3:
5292: /* shift Ev,cl */
5293: shift = 0;
5294: goto grp2;
5295:
5296: case 0x1a4: /* shld imm */
5297: op = 0;
5298: shift = 1;
5299: goto do_shiftd;
5300: case 0x1a5: /* shld cl */
5301: op = 0;
5302: shift = 0;
5303: goto do_shiftd;
5304: case 0x1ac: /* shrd imm */
5305: op = 1;
5306: shift = 1;
5307: goto do_shiftd;
5308: case 0x1ad: /* shrd cl */
5309: op = 1;
5310: shift = 0;
5311: do_shiftd:
5312: ot = dflag + OT_WORD;
5313: modrm = ldub_code(s->pc++);
5314: mod = (modrm >> 6) & 3;
5315: rm = (modrm & 7) | REX_B(s);
5316: reg = ((modrm >> 3) & 7) | rex_r;
5317: if (mod != 3) {
5318: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 5319: opreg = OR_TMP0;
1.1 root 5320: } else {
1.1.1.7 ! root 5321: opreg = rm;
1.1 root 5322: }
1.1.1.7 ! root 5323: gen_op_mov_TN_reg(ot, 1, reg);
1.1.1.6 root 5324:
1.1 root 5325: if (shift) {
5326: val = ldub_code(s->pc++);
1.1.1.7 ! root 5327: tcg_gen_movi_tl(cpu_T3, val);
1.1 root 5328: } else {
1.1.1.7 ! root 5329: tcg_gen_ld_tl(cpu_T3, cpu_env, offsetof(CPUState, regs[R_ECX]));
1.1 root 5330: }
1.1.1.7 ! root 5331: gen_shiftd_rm_T1_T3(s, ot, opreg, op);
1.1 root 5332: break;
5333:
5334: /************************/
5335: /* floats */
1.1.1.6 root 5336: case 0xd8 ... 0xdf:
1.1 root 5337: if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
5338: /* if CR0.EM or CR0.TS are set, generate an FPU exception */
5339: /* XXX: what to do if illegal op ? */
5340: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
5341: break;
5342: }
5343: modrm = ldub_code(s->pc++);
5344: mod = (modrm >> 6) & 3;
5345: rm = modrm & 7;
5346: op = ((b & 7) << 3) | ((modrm >> 3) & 7);
5347: if (mod != 3) {
5348: /* memory op */
5349: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
5350: switch(op) {
5351: case 0x00 ... 0x07: /* fxxxs */
5352: case 0x10 ... 0x17: /* fixxxl */
5353: case 0x20 ... 0x27: /* fxxxl */
5354: case 0x30 ... 0x37: /* fixxx */
5355: {
5356: int op1;
5357: op1 = op & 7;
5358:
5359: switch(op >> 4) {
5360: case 0:
1.1.1.7 ! root 5361: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 5362: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5363: gen_helper_flds_FT0(cpu_tmp2_i32);
1.1 root 5364: break;
5365: case 1:
1.1.1.7 ! root 5366: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 5367: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5368: gen_helper_fildl_FT0(cpu_tmp2_i32);
1.1 root 5369: break;
5370: case 2:
1.1.1.7 ! root 5371: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
! 5372: (s->mem_index >> 2) - 1);
! 5373: gen_helper_fldl_FT0(cpu_tmp1_i64);
1.1 root 5374: break;
5375: case 3:
5376: default:
1.1.1.7 ! root 5377: gen_op_lds_T0_A0(OT_WORD + s->mem_index);
! 5378: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5379: gen_helper_fildl_FT0(cpu_tmp2_i32);
1.1 root 5380: break;
5381: }
1.1.1.6 root 5382:
1.1.1.7 ! root 5383: gen_helper_fp_arith_ST0_FT0(op1);
1.1 root 5384: if (op1 == 3) {
5385: /* fcomp needs pop */
1.1.1.7 ! root 5386: gen_helper_fpop();
1.1 root 5387: }
5388: }
5389: break;
5390: case 0x08: /* flds */
5391: case 0x0a: /* fsts */
5392: case 0x0b: /* fstps */
1.1.1.3 root 5393: case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */
5394: case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */
5395: case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */
1.1 root 5396: switch(op & 7) {
5397: case 0:
5398: switch(op >> 4) {
5399: case 0:
1.1.1.7 ! root 5400: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 5401: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5402: gen_helper_flds_ST0(cpu_tmp2_i32);
1.1 root 5403: break;
5404: case 1:
1.1.1.7 ! root 5405: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 5406: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5407: gen_helper_fildl_ST0(cpu_tmp2_i32);
1.1 root 5408: break;
5409: case 2:
1.1.1.7 ! root 5410: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
! 5411: (s->mem_index >> 2) - 1);
! 5412: gen_helper_fldl_ST0(cpu_tmp1_i64);
1.1 root 5413: break;
5414: case 3:
5415: default:
1.1.1.7 ! root 5416: gen_op_lds_T0_A0(OT_WORD + s->mem_index);
! 5417: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5418: gen_helper_fildl_ST0(cpu_tmp2_i32);
1.1 root 5419: break;
5420: }
5421: break;
1.1.1.3 root 5422: case 1:
1.1.1.7 ! root 5423: /* XXX: the corresponding CPUID bit must be tested ! */
1.1.1.3 root 5424: switch(op >> 4) {
5425: case 1:
1.1.1.7 ! root 5426: gen_helper_fisttl_ST0(cpu_tmp2_i32);
! 5427: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5428: gen_op_st_T0_A0(OT_LONG + s->mem_index);
1.1.1.3 root 5429: break;
5430: case 2:
1.1.1.7 ! root 5431: gen_helper_fisttll_ST0(cpu_tmp1_i64);
! 5432: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
! 5433: (s->mem_index >> 2) - 1);
1.1.1.3 root 5434: break;
5435: case 3:
5436: default:
1.1.1.7 ! root 5437: gen_helper_fistt_ST0(cpu_tmp2_i32);
! 5438: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5439: gen_op_st_T0_A0(OT_WORD + s->mem_index);
! 5440: break;
1.1.1.3 root 5441: }
1.1.1.7 ! root 5442: gen_helper_fpop();
1.1.1.3 root 5443: break;
1.1 root 5444: default:
5445: switch(op >> 4) {
5446: case 0:
1.1.1.7 ! root 5447: gen_helper_fsts_ST0(cpu_tmp2_i32);
! 5448: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5449: gen_op_st_T0_A0(OT_LONG + s->mem_index);
1.1 root 5450: break;
5451: case 1:
1.1.1.7 ! root 5452: gen_helper_fistl_ST0(cpu_tmp2_i32);
! 5453: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5454: gen_op_st_T0_A0(OT_LONG + s->mem_index);
1.1 root 5455: break;
5456: case 2:
1.1.1.7 ! root 5457: gen_helper_fstl_ST0(cpu_tmp1_i64);
! 5458: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
! 5459: (s->mem_index >> 2) - 1);
1.1 root 5460: break;
5461: case 3:
5462: default:
1.1.1.7 ! root 5463: gen_helper_fist_ST0(cpu_tmp2_i32);
! 5464: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5465: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 5466: break;
5467: }
5468: if ((op & 7) == 3)
1.1.1.7 ! root 5469: gen_helper_fpop();
1.1 root 5470: break;
5471: }
5472: break;
5473: case 0x0c: /* fldenv mem */
1.1.1.7 ! root 5474: if (s->cc_op != CC_OP_DYNAMIC)
! 5475: gen_op_set_cc_op(s->cc_op);
! 5476: gen_jmp_im(pc_start - s->cs_base);
! 5477: gen_helper_fldenv(
! 5478: cpu_A0, tcg_const_i32(s->dflag));
1.1 root 5479: break;
5480: case 0x0d: /* fldcw mem */
1.1.1.7 ! root 5481: gen_op_ld_T0_A0(OT_WORD + s->mem_index);
! 5482: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5483: gen_helper_fldcw(cpu_tmp2_i32);
1.1 root 5484: break;
5485: case 0x0e: /* fnstenv mem */
1.1.1.7 ! root 5486: if (s->cc_op != CC_OP_DYNAMIC)
! 5487: gen_op_set_cc_op(s->cc_op);
! 5488: gen_jmp_im(pc_start - s->cs_base);
! 5489: gen_helper_fstenv(cpu_A0, tcg_const_i32(s->dflag));
1.1 root 5490: break;
5491: case 0x0f: /* fnstcw mem */
1.1.1.7 ! root 5492: gen_helper_fnstcw(cpu_tmp2_i32);
! 5493: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5494: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 5495: break;
5496: case 0x1d: /* fldt mem */
1.1.1.7 ! root 5497: if (s->cc_op != CC_OP_DYNAMIC)
! 5498: gen_op_set_cc_op(s->cc_op);
! 5499: gen_jmp_im(pc_start - s->cs_base);
! 5500: gen_helper_fldt_ST0(cpu_A0);
1.1 root 5501: break;
5502: case 0x1f: /* fstpt mem */
1.1.1.7 ! root 5503: if (s->cc_op != CC_OP_DYNAMIC)
! 5504: gen_op_set_cc_op(s->cc_op);
! 5505: gen_jmp_im(pc_start - s->cs_base);
! 5506: gen_helper_fstt_ST0(cpu_A0);
! 5507: gen_helper_fpop();
1.1 root 5508: break;
5509: case 0x2c: /* frstor mem */
1.1.1.7 ! root 5510: if (s->cc_op != CC_OP_DYNAMIC)
! 5511: gen_op_set_cc_op(s->cc_op);
! 5512: gen_jmp_im(pc_start - s->cs_base);
! 5513: gen_helper_frstor(cpu_A0, tcg_const_i32(s->dflag));
1.1 root 5514: break;
5515: case 0x2e: /* fnsave mem */
1.1.1.7 ! root 5516: if (s->cc_op != CC_OP_DYNAMIC)
! 5517: gen_op_set_cc_op(s->cc_op);
! 5518: gen_jmp_im(pc_start - s->cs_base);
! 5519: gen_helper_fsave(cpu_A0, tcg_const_i32(s->dflag));
1.1 root 5520: break;
5521: case 0x2f: /* fnstsw mem */
1.1.1.7 ! root 5522: gen_helper_fnstsw(cpu_tmp2_i32);
! 5523: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5524: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 5525: break;
5526: case 0x3c: /* fbld */
1.1.1.7 ! root 5527: if (s->cc_op != CC_OP_DYNAMIC)
! 5528: gen_op_set_cc_op(s->cc_op);
! 5529: gen_jmp_im(pc_start - s->cs_base);
! 5530: gen_helper_fbld_ST0(cpu_A0);
1.1 root 5531: break;
5532: case 0x3e: /* fbstp */
1.1.1.7 ! root 5533: if (s->cc_op != CC_OP_DYNAMIC)
! 5534: gen_op_set_cc_op(s->cc_op);
! 5535: gen_jmp_im(pc_start - s->cs_base);
! 5536: gen_helper_fbst_ST0(cpu_A0);
! 5537: gen_helper_fpop();
1.1 root 5538: break;
5539: case 0x3d: /* fildll */
1.1.1.7 ! root 5540: tcg_gen_qemu_ld64(cpu_tmp1_i64, cpu_A0,
! 5541: (s->mem_index >> 2) - 1);
! 5542: gen_helper_fildll_ST0(cpu_tmp1_i64);
1.1 root 5543: break;
5544: case 0x3f: /* fistpll */
1.1.1.7 ! root 5545: gen_helper_fistll_ST0(cpu_tmp1_i64);
! 5546: tcg_gen_qemu_st64(cpu_tmp1_i64, cpu_A0,
! 5547: (s->mem_index >> 2) - 1);
! 5548: gen_helper_fpop();
1.1 root 5549: break;
5550: default:
5551: goto illegal_op;
5552: }
5553: } else {
5554: /* register float ops */
5555: opreg = rm;
5556:
5557: switch(op) {
5558: case 0x08: /* fld sti */
1.1.1.7 ! root 5559: gen_helper_fpush();
! 5560: gen_helper_fmov_ST0_STN(tcg_const_i32((opreg + 1) & 7));
1.1 root 5561: break;
5562: case 0x09: /* fxchg sti */
5563: case 0x29: /* fxchg4 sti, undocumented op */
5564: case 0x39: /* fxchg7 sti, undocumented op */
1.1.1.7 ! root 5565: gen_helper_fxchg_ST0_STN(tcg_const_i32(opreg));
1.1 root 5566: break;
5567: case 0x0a: /* grp d9/2 */
5568: switch(rm) {
5569: case 0: /* fnop */
5570: /* check exceptions (FreeBSD FPU probe) */
5571: if (s->cc_op != CC_OP_DYNAMIC)
5572: gen_op_set_cc_op(s->cc_op);
5573: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 5574: gen_helper_fwait();
1.1 root 5575: break;
5576: default:
5577: goto illegal_op;
5578: }
5579: break;
5580: case 0x0c: /* grp d9/4 */
5581: switch(rm) {
5582: case 0: /* fchs */
1.1.1.7 ! root 5583: gen_helper_fchs_ST0();
1.1 root 5584: break;
5585: case 1: /* fabs */
1.1.1.7 ! root 5586: gen_helper_fabs_ST0();
1.1 root 5587: break;
5588: case 4: /* ftst */
1.1.1.7 ! root 5589: gen_helper_fldz_FT0();
! 5590: gen_helper_fcom_ST0_FT0();
1.1 root 5591: break;
5592: case 5: /* fxam */
1.1.1.7 ! root 5593: gen_helper_fxam_ST0();
1.1 root 5594: break;
5595: default:
5596: goto illegal_op;
5597: }
5598: break;
5599: case 0x0d: /* grp d9/5 */
5600: {
5601: switch(rm) {
5602: case 0:
1.1.1.7 ! root 5603: gen_helper_fpush();
! 5604: gen_helper_fld1_ST0();
1.1 root 5605: break;
5606: case 1:
1.1.1.7 ! root 5607: gen_helper_fpush();
! 5608: gen_helper_fldl2t_ST0();
1.1 root 5609: break;
5610: case 2:
1.1.1.7 ! root 5611: gen_helper_fpush();
! 5612: gen_helper_fldl2e_ST0();
1.1 root 5613: break;
5614: case 3:
1.1.1.7 ! root 5615: gen_helper_fpush();
! 5616: gen_helper_fldpi_ST0();
1.1 root 5617: break;
5618: case 4:
1.1.1.7 ! root 5619: gen_helper_fpush();
! 5620: gen_helper_fldlg2_ST0();
1.1 root 5621: break;
5622: case 5:
1.1.1.7 ! root 5623: gen_helper_fpush();
! 5624: gen_helper_fldln2_ST0();
1.1 root 5625: break;
5626: case 6:
1.1.1.7 ! root 5627: gen_helper_fpush();
! 5628: gen_helper_fldz_ST0();
1.1 root 5629: break;
5630: default:
5631: goto illegal_op;
5632: }
5633: }
5634: break;
5635: case 0x0e: /* grp d9/6 */
5636: switch(rm) {
5637: case 0: /* f2xm1 */
1.1.1.7 ! root 5638: gen_helper_f2xm1();
1.1 root 5639: break;
5640: case 1: /* fyl2x */
1.1.1.7 ! root 5641: gen_helper_fyl2x();
1.1 root 5642: break;
5643: case 2: /* fptan */
1.1.1.7 ! root 5644: gen_helper_fptan();
1.1 root 5645: break;
5646: case 3: /* fpatan */
1.1.1.7 ! root 5647: gen_helper_fpatan();
1.1 root 5648: break;
5649: case 4: /* fxtract */
1.1.1.7 ! root 5650: gen_helper_fxtract();
1.1 root 5651: break;
5652: case 5: /* fprem1 */
1.1.1.7 ! root 5653: gen_helper_fprem1();
1.1 root 5654: break;
5655: case 6: /* fdecstp */
1.1.1.7 ! root 5656: gen_helper_fdecstp();
1.1 root 5657: break;
5658: default:
5659: case 7: /* fincstp */
1.1.1.7 ! root 5660: gen_helper_fincstp();
1.1 root 5661: break;
5662: }
5663: break;
5664: case 0x0f: /* grp d9/7 */
5665: switch(rm) {
5666: case 0: /* fprem */
1.1.1.7 ! root 5667: gen_helper_fprem();
1.1 root 5668: break;
5669: case 1: /* fyl2xp1 */
1.1.1.7 ! root 5670: gen_helper_fyl2xp1();
1.1 root 5671: break;
5672: case 2: /* fsqrt */
1.1.1.7 ! root 5673: gen_helper_fsqrt();
1.1 root 5674: break;
5675: case 3: /* fsincos */
1.1.1.7 ! root 5676: gen_helper_fsincos();
1.1 root 5677: break;
5678: case 5: /* fscale */
1.1.1.7 ! root 5679: gen_helper_fscale();
1.1 root 5680: break;
5681: case 4: /* frndint */
1.1.1.7 ! root 5682: gen_helper_frndint();
1.1 root 5683: break;
5684: case 6: /* fsin */
1.1.1.7 ! root 5685: gen_helper_fsin();
1.1 root 5686: break;
5687: default:
5688: case 7: /* fcos */
1.1.1.7 ! root 5689: gen_helper_fcos();
1.1 root 5690: break;
5691: }
5692: break;
5693: case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
5694: case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
5695: case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
5696: {
5697: int op1;
1.1.1.6 root 5698:
1.1 root 5699: op1 = op & 7;
5700: if (op >= 0x20) {
1.1.1.7 ! root 5701: gen_helper_fp_arith_STN_ST0(op1, opreg);
1.1 root 5702: if (op >= 0x30)
1.1.1.7 ! root 5703: gen_helper_fpop();
1.1 root 5704: } else {
1.1.1.7 ! root 5705: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5706: gen_helper_fp_arith_ST0_FT0(op1);
1.1 root 5707: }
5708: }
5709: break;
5710: case 0x02: /* fcom */
5711: case 0x22: /* fcom2, undocumented op */
1.1.1.7 ! root 5712: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5713: gen_helper_fcom_ST0_FT0();
1.1 root 5714: break;
5715: case 0x03: /* fcomp */
5716: case 0x23: /* fcomp3, undocumented op */
5717: case 0x32: /* fcomp5, undocumented op */
1.1.1.7 ! root 5718: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5719: gen_helper_fcom_ST0_FT0();
! 5720: gen_helper_fpop();
1.1 root 5721: break;
5722: case 0x15: /* da/5 */
5723: switch(rm) {
5724: case 1: /* fucompp */
1.1.1.7 ! root 5725: gen_helper_fmov_FT0_STN(tcg_const_i32(1));
! 5726: gen_helper_fucom_ST0_FT0();
! 5727: gen_helper_fpop();
! 5728: gen_helper_fpop();
1.1 root 5729: break;
5730: default:
5731: goto illegal_op;
5732: }
5733: break;
5734: case 0x1c:
5735: switch(rm) {
5736: case 0: /* feni (287 only, just do nop here) */
5737: break;
5738: case 1: /* fdisi (287 only, just do nop here) */
5739: break;
5740: case 2: /* fclex */
1.1.1.7 ! root 5741: gen_helper_fclex();
1.1 root 5742: break;
5743: case 3: /* fninit */
1.1.1.7 ! root 5744: gen_helper_fninit();
1.1 root 5745: break;
5746: case 4: /* fsetpm (287 only, just do nop here) */
5747: break;
5748: default:
5749: goto illegal_op;
5750: }
5751: break;
5752: case 0x1d: /* fucomi */
5753: if (s->cc_op != CC_OP_DYNAMIC)
5754: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 5755: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5756: gen_helper_fucomi_ST0_FT0();
1.1 root 5757: s->cc_op = CC_OP_EFLAGS;
5758: break;
5759: case 0x1e: /* fcomi */
5760: if (s->cc_op != CC_OP_DYNAMIC)
5761: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 5762: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5763: gen_helper_fcomi_ST0_FT0();
1.1 root 5764: s->cc_op = CC_OP_EFLAGS;
5765: break;
5766: case 0x28: /* ffree sti */
1.1.1.7 ! root 5767: gen_helper_ffree_STN(tcg_const_i32(opreg));
1.1.1.6 root 5768: break;
1.1 root 5769: case 0x2a: /* fst sti */
1.1.1.7 ! root 5770: gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
1.1 root 5771: break;
5772: case 0x2b: /* fstp sti */
5773: case 0x0b: /* fstp1 sti, undocumented op */
5774: case 0x3a: /* fstp8 sti, undocumented op */
5775: case 0x3b: /* fstp9 sti, undocumented op */
1.1.1.7 ! root 5776: gen_helper_fmov_STN_ST0(tcg_const_i32(opreg));
! 5777: gen_helper_fpop();
1.1 root 5778: break;
5779: case 0x2c: /* fucom st(i) */
1.1.1.7 ! root 5780: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5781: gen_helper_fucom_ST0_FT0();
1.1 root 5782: break;
5783: case 0x2d: /* fucomp st(i) */
1.1.1.7 ! root 5784: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5785: gen_helper_fucom_ST0_FT0();
! 5786: gen_helper_fpop();
1.1 root 5787: break;
5788: case 0x33: /* de/3 */
5789: switch(rm) {
5790: case 1: /* fcompp */
1.1.1.7 ! root 5791: gen_helper_fmov_FT0_STN(tcg_const_i32(1));
! 5792: gen_helper_fcom_ST0_FT0();
! 5793: gen_helper_fpop();
! 5794: gen_helper_fpop();
1.1 root 5795: break;
5796: default:
5797: goto illegal_op;
5798: }
5799: break;
5800: case 0x38: /* ffreep sti, undocumented op */
1.1.1.7 ! root 5801: gen_helper_ffree_STN(tcg_const_i32(opreg));
! 5802: gen_helper_fpop();
1.1 root 5803: break;
5804: case 0x3c: /* df/4 */
5805: switch(rm) {
5806: case 0:
1.1.1.7 ! root 5807: gen_helper_fnstsw(cpu_tmp2_i32);
! 5808: tcg_gen_extu_i32_tl(cpu_T[0], cpu_tmp2_i32);
! 5809: gen_op_mov_reg_T0(OT_WORD, R_EAX);
1.1 root 5810: break;
5811: default:
5812: goto illegal_op;
5813: }
5814: break;
5815: case 0x3d: /* fucomip */
5816: if (s->cc_op != CC_OP_DYNAMIC)
5817: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 5818: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5819: gen_helper_fucomi_ST0_FT0();
! 5820: gen_helper_fpop();
1.1 root 5821: s->cc_op = CC_OP_EFLAGS;
5822: break;
5823: case 0x3e: /* fcomip */
5824: if (s->cc_op != CC_OP_DYNAMIC)
5825: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 5826: gen_helper_fmov_FT0_STN(tcg_const_i32(opreg));
! 5827: gen_helper_fcomi_ST0_FT0();
! 5828: gen_helper_fpop();
1.1 root 5829: s->cc_op = CC_OP_EFLAGS;
5830: break;
5831: case 0x10 ... 0x13: /* fcmovxx */
5832: case 0x18 ... 0x1b:
5833: {
1.1.1.7 ! root 5834: int op1, l1;
! 5835: static const uint8_t fcmov_cc[8] = {
1.1 root 5836: (JCC_B << 1),
5837: (JCC_Z << 1),
5838: (JCC_BE << 1),
5839: (JCC_P << 1),
5840: };
1.1.1.7 ! root 5841: op1 = fcmov_cc[op & 3] | (((op >> 3) & 1) ^ 1);
! 5842: l1 = gen_new_label();
! 5843: gen_jcc1(s, s->cc_op, op1, l1);
! 5844: gen_helper_fmov_ST0_STN(tcg_const_i32(opreg));
! 5845: gen_set_label(l1);
1.1 root 5846: }
5847: break;
5848: default:
5849: goto illegal_op;
5850: }
5851: }
5852: break;
5853: /************************/
5854: /* string ops */
5855:
5856: case 0xa4: /* movsS */
5857: case 0xa5:
5858: if ((b & 1) == 0)
5859: ot = OT_BYTE;
5860: else
5861: ot = dflag + OT_WORD;
5862:
5863: if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
5864: gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
5865: } else {
5866: gen_movs(s, ot);
5867: }
5868: break;
1.1.1.6 root 5869:
1.1 root 5870: case 0xaa: /* stosS */
5871: case 0xab:
5872: if ((b & 1) == 0)
5873: ot = OT_BYTE;
5874: else
5875: ot = dflag + OT_WORD;
5876:
5877: if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
5878: gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
5879: } else {
5880: gen_stos(s, ot);
5881: }
5882: break;
5883: case 0xac: /* lodsS */
5884: case 0xad:
5885: if ((b & 1) == 0)
5886: ot = OT_BYTE;
5887: else
5888: ot = dflag + OT_WORD;
5889: if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
5890: gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
5891: } else {
5892: gen_lods(s, ot);
5893: }
5894: break;
5895: case 0xae: /* scasS */
5896: case 0xaf:
5897: if ((b & 1) == 0)
5898: ot = OT_BYTE;
5899: else
5900: ot = dflag + OT_WORD;
5901: if (prefixes & PREFIX_REPNZ) {
5902: gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
5903: } else if (prefixes & PREFIX_REPZ) {
5904: gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
5905: } else {
5906: gen_scas(s, ot);
5907: s->cc_op = CC_OP_SUBB + ot;
5908: }
5909: break;
5910:
5911: case 0xa6: /* cmpsS */
5912: case 0xa7:
5913: if ((b & 1) == 0)
5914: ot = OT_BYTE;
5915: else
5916: ot = dflag + OT_WORD;
5917: if (prefixes & PREFIX_REPNZ) {
5918: gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
5919: } else if (prefixes & PREFIX_REPZ) {
5920: gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
5921: } else {
5922: gen_cmps(s, ot);
5923: s->cc_op = CC_OP_SUBB + ot;
5924: }
5925: break;
5926: case 0x6c: /* insS */
5927: case 0x6d:
5928: if ((b & 1) == 0)
5929: ot = OT_BYTE;
5930: else
5931: ot = dflag ? OT_LONG : OT_WORD;
1.1.1.7 ! root 5932: gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
1.1.1.6 root 5933: gen_op_andl_T0_ffff();
1.1.1.7 ! root 5934: gen_check_io(s, ot, pc_start - s->cs_base,
! 5935: SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) | 4);
1.1 root 5936: if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
5937: gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
5938: } else {
5939: gen_ins(s, ot);
1.1.1.7 ! root 5940: if (use_icount) {
! 5941: gen_jmp(s, s->pc - s->cs_base);
! 5942: }
1.1 root 5943: }
5944: break;
5945: case 0x6e: /* outsS */
5946: case 0x6f:
5947: if ((b & 1) == 0)
5948: ot = OT_BYTE;
5949: else
5950: ot = dflag ? OT_LONG : OT_WORD;
1.1.1.7 ! root 5951: gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
1.1.1.6 root 5952: gen_op_andl_T0_ffff();
1.1.1.7 ! root 5953: gen_check_io(s, ot, pc_start - s->cs_base,
! 5954: svm_is_rep(prefixes) | 4);
1.1 root 5955: if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
5956: gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
5957: } else {
5958: gen_outs(s, ot);
1.1.1.7 ! root 5959: if (use_icount) {
! 5960: gen_jmp(s, s->pc - s->cs_base);
! 5961: }
1.1 root 5962: }
5963: break;
5964:
5965: /************************/
5966: /* port I/O */
1.1.1.6 root 5967:
1.1 root 5968: case 0xe4:
5969: case 0xe5:
5970: if ((b & 1) == 0)
5971: ot = OT_BYTE;
5972: else
5973: ot = dflag ? OT_LONG : OT_WORD;
5974: val = ldub_code(s->pc++);
5975: gen_op_movl_T0_im(val);
1.1.1.7 ! root 5976: gen_check_io(s, ot, pc_start - s->cs_base,
! 5977: SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
! 5978: if (use_icount)
! 5979: gen_io_start();
! 5980: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 5981: gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32);
! 5982: gen_op_mov_reg_T1(ot, R_EAX);
! 5983: if (use_icount) {
! 5984: gen_io_end();
! 5985: gen_jmp(s, s->pc - s->cs_base);
! 5986: }
1.1 root 5987: break;
5988: case 0xe6:
5989: case 0xe7:
5990: if ((b & 1) == 0)
5991: ot = OT_BYTE;
5992: else
5993: ot = dflag ? OT_LONG : OT_WORD;
5994: val = ldub_code(s->pc++);
5995: gen_op_movl_T0_im(val);
1.1.1.7 ! root 5996: gen_check_io(s, ot, pc_start - s->cs_base,
! 5997: svm_is_rep(prefixes));
! 5998: gen_op_mov_TN_reg(ot, 1, R_EAX);
! 5999:
! 6000: if (use_icount)
! 6001: gen_io_start();
! 6002: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 6003: tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
! 6004: tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
! 6005: gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
! 6006: if (use_icount) {
! 6007: gen_io_end();
! 6008: gen_jmp(s, s->pc - s->cs_base);
! 6009: }
1.1 root 6010: break;
6011: case 0xec:
6012: case 0xed:
6013: if ((b & 1) == 0)
6014: ot = OT_BYTE;
6015: else
6016: ot = dflag ? OT_LONG : OT_WORD;
1.1.1.7 ! root 6017: gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
1.1 root 6018: gen_op_andl_T0_ffff();
1.1.1.7 ! root 6019: gen_check_io(s, ot, pc_start - s->cs_base,
! 6020: SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes));
! 6021: if (use_icount)
! 6022: gen_io_start();
! 6023: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 6024: gen_helper_in_func(ot, cpu_T[1], cpu_tmp2_i32);
! 6025: gen_op_mov_reg_T1(ot, R_EAX);
! 6026: if (use_icount) {
! 6027: gen_io_end();
! 6028: gen_jmp(s, s->pc - s->cs_base);
! 6029: }
1.1 root 6030: break;
6031: case 0xee:
6032: case 0xef:
6033: if ((b & 1) == 0)
6034: ot = OT_BYTE;
6035: else
6036: ot = dflag ? OT_LONG : OT_WORD;
1.1.1.7 ! root 6037: gen_op_mov_TN_reg(OT_WORD, 0, R_EDX);
1.1 root 6038: gen_op_andl_T0_ffff();
1.1.1.7 ! root 6039: gen_check_io(s, ot, pc_start - s->cs_base,
! 6040: svm_is_rep(prefixes));
! 6041: gen_op_mov_TN_reg(ot, 1, R_EAX);
! 6042:
! 6043: if (use_icount)
! 6044: gen_io_start();
! 6045: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 6046: tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
! 6047: tcg_gen_trunc_tl_i32(cpu_tmp3_i32, cpu_T[1]);
! 6048: gen_helper_out_func(ot, cpu_tmp2_i32, cpu_tmp3_i32);
! 6049: if (use_icount) {
! 6050: gen_io_end();
! 6051: gen_jmp(s, s->pc - s->cs_base);
! 6052: }
1.1 root 6053: break;
6054:
6055: /************************/
6056: /* control */
6057: case 0xc2: /* ret im */
6058: val = ldsw_code(s->pc);
6059: s->pc += 2;
6060: gen_pop_T0(s);
6061: if (CODE64(s) && s->dflag)
6062: s->dflag = 2;
6063: gen_stack_update(s, val + (2 << s->dflag));
6064: if (s->dflag == 0)
6065: gen_op_andl_T0_ffff();
6066: gen_op_jmp_T0();
6067: gen_eob(s);
6068: break;
6069: case 0xc3: /* ret */
6070: gen_pop_T0(s);
6071: gen_pop_update(s);
6072: if (s->dflag == 0)
6073: gen_op_andl_T0_ffff();
6074: gen_op_jmp_T0();
6075: gen_eob(s);
6076: break;
6077: case 0xca: /* lret im */
6078: val = ldsw_code(s->pc);
6079: s->pc += 2;
6080: do_lret:
6081: if (s->pe && !s->vm86) {
6082: if (s->cc_op != CC_OP_DYNAMIC)
6083: gen_op_set_cc_op(s->cc_op);
6084: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6085: gen_helper_lret_protected(tcg_const_i32(s->dflag),
! 6086: tcg_const_i32(val));
1.1 root 6087: } else {
6088: gen_stack_A0(s);
6089: /* pop offset */
1.1.1.7 ! root 6090: gen_op_ld_T0_A0(1 + s->dflag + s->mem_index);
1.1 root 6091: if (s->dflag == 0)
6092: gen_op_andl_T0_ffff();
6093: /* NOTE: keeping EIP updated is not a problem in case of
6094: exception */
6095: gen_op_jmp_T0();
6096: /* pop selector */
6097: gen_op_addl_A0_im(2 << s->dflag);
1.1.1.7 ! root 6098: gen_op_ld_T0_A0(1 + s->dflag + s->mem_index);
! 6099: gen_op_movl_seg_T0_vm(R_CS);
1.1 root 6100: /* add stack offset */
6101: gen_stack_update(s, val + (4 << s->dflag));
6102: }
6103: gen_eob(s);
6104: break;
6105: case 0xcb: /* lret */
6106: val = 0;
6107: goto do_lret;
6108: case 0xcf: /* iret */
1.1.1.7 ! root 6109: gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET);
1.1 root 6110: if (!s->pe) {
6111: /* real mode */
1.1.1.7 ! root 6112: gen_helper_iret_real(tcg_const_i32(s->dflag));
1.1 root 6113: s->cc_op = CC_OP_EFLAGS;
6114: } else if (s->vm86) {
6115: if (s->iopl != 3) {
6116: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6117: } else {
1.1.1.7 ! root 6118: gen_helper_iret_real(tcg_const_i32(s->dflag));
1.1 root 6119: s->cc_op = CC_OP_EFLAGS;
6120: }
6121: } else {
6122: if (s->cc_op != CC_OP_DYNAMIC)
6123: gen_op_set_cc_op(s->cc_op);
6124: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6125: gen_helper_iret_protected(tcg_const_i32(s->dflag),
! 6126: tcg_const_i32(s->pc - s->cs_base));
1.1 root 6127: s->cc_op = CC_OP_EFLAGS;
6128: }
6129: gen_eob(s);
6130: break;
6131: case 0xe8: /* call im */
6132: {
6133: if (dflag)
6134: tval = (int32_t)insn_get(s, OT_LONG);
6135: else
6136: tval = (int16_t)insn_get(s, OT_WORD);
6137: next_eip = s->pc - s->cs_base;
6138: tval += next_eip;
6139: if (s->dflag == 0)
6140: tval &= 0xffff;
6141: gen_movtl_T0_im(next_eip);
6142: gen_push_T0(s);
6143: gen_jmp(s, tval);
6144: }
6145: break;
6146: case 0x9a: /* lcall im */
6147: {
6148: unsigned int selector, offset;
1.1.1.6 root 6149:
1.1 root 6150: if (CODE64(s))
6151: goto illegal_op;
6152: ot = dflag ? OT_LONG : OT_WORD;
6153: offset = insn_get(s, ot);
6154: selector = insn_get(s, OT_WORD);
1.1.1.6 root 6155:
1.1 root 6156: gen_op_movl_T0_im(selector);
6157: gen_op_movl_T1_imu(offset);
6158: }
6159: goto do_lcall;
6160: case 0xe9: /* jmp im */
6161: if (dflag)
6162: tval = (int32_t)insn_get(s, OT_LONG);
6163: else
6164: tval = (int16_t)insn_get(s, OT_WORD);
6165: tval += s->pc - s->cs_base;
6166: if (s->dflag == 0)
6167: tval &= 0xffff;
1.1.1.7 ! root 6168: else if(!CODE64(s))
! 6169: tval &= 0xffffffff;
1.1 root 6170: gen_jmp(s, tval);
6171: break;
6172: case 0xea: /* ljmp im */
6173: {
6174: unsigned int selector, offset;
6175:
6176: if (CODE64(s))
6177: goto illegal_op;
6178: ot = dflag ? OT_LONG : OT_WORD;
6179: offset = insn_get(s, ot);
6180: selector = insn_get(s, OT_WORD);
1.1.1.6 root 6181:
1.1 root 6182: gen_op_movl_T0_im(selector);
6183: gen_op_movl_T1_imu(offset);
6184: }
6185: goto do_ljmp;
6186: case 0xeb: /* jmp Jb */
6187: tval = (int8_t)insn_get(s, OT_BYTE);
6188: tval += s->pc - s->cs_base;
6189: if (s->dflag == 0)
6190: tval &= 0xffff;
6191: gen_jmp(s, tval);
6192: break;
6193: case 0x70 ... 0x7f: /* jcc Jb */
6194: tval = (int8_t)insn_get(s, OT_BYTE);
6195: goto do_jcc;
6196: case 0x180 ... 0x18f: /* jcc Jv */
6197: if (dflag) {
6198: tval = (int32_t)insn_get(s, OT_LONG);
6199: } else {
1.1.1.6 root 6200: tval = (int16_t)insn_get(s, OT_WORD);
1.1 root 6201: }
6202: do_jcc:
6203: next_eip = s->pc - s->cs_base;
6204: tval += next_eip;
6205: if (s->dflag == 0)
6206: tval &= 0xffff;
6207: gen_jcc(s, b, tval, next_eip);
6208: break;
6209:
6210: case 0x190 ... 0x19f: /* setcc Gv */
6211: modrm = ldub_code(s->pc++);
6212: gen_setcc(s, b);
6213: gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
6214: break;
6215: case 0x140 ... 0x14f: /* cmov Gv, Ev */
1.1.1.7 ! root 6216: {
! 6217: int l1;
! 6218: TCGv t0;
! 6219:
! 6220: ot = dflag + OT_WORD;
! 6221: modrm = ldub_code(s->pc++);
! 6222: reg = ((modrm >> 3) & 7) | rex_r;
! 6223: mod = (modrm >> 6) & 3;
! 6224: t0 = tcg_temp_local_new();
! 6225: if (mod != 3) {
! 6226: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
! 6227: gen_op_ld_v(ot + s->mem_index, t0, cpu_A0);
! 6228: } else {
! 6229: rm = (modrm & 7) | REX_B(s);
! 6230: gen_op_mov_v_reg(ot, t0, rm);
! 6231: }
! 6232: #ifdef TARGET_X86_64
! 6233: if (ot == OT_LONG) {
! 6234: /* XXX: specific Intel behaviour ? */
! 6235: l1 = gen_new_label();
! 6236: gen_jcc1(s, s->cc_op, b ^ 1, l1);
! 6237: tcg_gen_st32_tl(t0, cpu_env, offsetof(CPUState, regs[reg]) + REG_L_OFFSET);
! 6238: gen_set_label(l1);
! 6239: tcg_gen_movi_tl(cpu_tmp0, 0);
! 6240: tcg_gen_st32_tl(cpu_tmp0, cpu_env, offsetof(CPUState, regs[reg]) + REG_LH_OFFSET);
! 6241: } else
! 6242: #endif
! 6243: {
! 6244: l1 = gen_new_label();
! 6245: gen_jcc1(s, s->cc_op, b ^ 1, l1);
! 6246: gen_op_mov_reg_v(ot, reg, t0);
! 6247: gen_set_label(l1);
! 6248: }
! 6249: tcg_temp_free(t0);
1.1 root 6250: }
6251: break;
1.1.1.6 root 6252:
1.1 root 6253: /************************/
6254: /* flags */
6255: case 0x9c: /* pushf */
1.1.1.7 ! root 6256: gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF);
1.1 root 6257: if (s->vm86 && s->iopl != 3) {
6258: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6259: } else {
6260: if (s->cc_op != CC_OP_DYNAMIC)
6261: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6262: gen_helper_read_eflags(cpu_T[0]);
1.1 root 6263: gen_push_T0(s);
6264: }
6265: break;
6266: case 0x9d: /* popf */
1.1.1.7 ! root 6267: gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF);
1.1 root 6268: if (s->vm86 && s->iopl != 3) {
6269: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6270: } else {
6271: gen_pop_T0(s);
6272: if (s->cpl == 0) {
6273: if (s->dflag) {
1.1.1.7 ! root 6274: gen_helper_write_eflags(cpu_T[0],
! 6275: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK)));
1.1 root 6276: } else {
1.1.1.7 ! root 6277: gen_helper_write_eflags(cpu_T[0],
! 6278: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff));
1.1 root 6279: }
6280: } else {
6281: if (s->cpl <= s->iopl) {
6282: if (s->dflag) {
1.1.1.7 ! root 6283: gen_helper_write_eflags(cpu_T[0],
! 6284: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK)));
1.1 root 6285: } else {
1.1.1.7 ! root 6286: gen_helper_write_eflags(cpu_T[0],
! 6287: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff));
1.1 root 6288: }
6289: } else {
6290: if (s->dflag) {
1.1.1.7 ! root 6291: gen_helper_write_eflags(cpu_T[0],
! 6292: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK)));
1.1 root 6293: } else {
1.1.1.7 ! root 6294: gen_helper_write_eflags(cpu_T[0],
! 6295: tcg_const_i32((TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff));
1.1 root 6296: }
6297: }
6298: }
6299: gen_pop_update(s);
6300: s->cc_op = CC_OP_EFLAGS;
6301: /* abort translation because TF flag may change */
6302: gen_jmp_im(s->pc - s->cs_base);
6303: gen_eob(s);
6304: }
6305: break;
6306: case 0x9e: /* sahf */
1.1.1.7 ! root 6307: if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
1.1 root 6308: goto illegal_op;
1.1.1.7 ! root 6309: gen_op_mov_TN_reg(OT_BYTE, 0, R_AH);
1.1 root 6310: if (s->cc_op != CC_OP_DYNAMIC)
6311: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6312: gen_compute_eflags(cpu_cc_src);
! 6313: tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O);
! 6314: tcg_gen_andi_tl(cpu_T[0], cpu_T[0], CC_S | CC_Z | CC_A | CC_P | CC_C);
! 6315: tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, cpu_T[0]);
1.1 root 6316: s->cc_op = CC_OP_EFLAGS;
6317: break;
6318: case 0x9f: /* lahf */
1.1.1.7 ! root 6319: if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM))
1.1 root 6320: goto illegal_op;
6321: if (s->cc_op != CC_OP_DYNAMIC)
6322: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6323: gen_compute_eflags(cpu_T[0]);
! 6324: /* Note: gen_compute_eflags() only gives the condition codes */
! 6325: tcg_gen_ori_tl(cpu_T[0], cpu_T[0], 0x02);
! 6326: gen_op_mov_reg_T0(OT_BYTE, R_AH);
1.1 root 6327: break;
6328: case 0xf5: /* cmc */
6329: if (s->cc_op != CC_OP_DYNAMIC)
6330: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6331: gen_compute_eflags(cpu_cc_src);
! 6332: tcg_gen_xori_tl(cpu_cc_src, cpu_cc_src, CC_C);
1.1 root 6333: s->cc_op = CC_OP_EFLAGS;
6334: break;
6335: case 0xf8: /* clc */
6336: if (s->cc_op != CC_OP_DYNAMIC)
6337: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6338: gen_compute_eflags(cpu_cc_src);
! 6339: tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_C);
1.1 root 6340: s->cc_op = CC_OP_EFLAGS;
6341: break;
6342: case 0xf9: /* stc */
6343: if (s->cc_op != CC_OP_DYNAMIC)
6344: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6345: gen_compute_eflags(cpu_cc_src);
! 6346: tcg_gen_ori_tl(cpu_cc_src, cpu_cc_src, CC_C);
1.1 root 6347: s->cc_op = CC_OP_EFLAGS;
6348: break;
6349: case 0xfc: /* cld */
1.1.1.7 ! root 6350: tcg_gen_movi_i32(cpu_tmp2_i32, 1);
! 6351: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df));
1.1 root 6352: break;
6353: case 0xfd: /* std */
1.1.1.7 ! root 6354: tcg_gen_movi_i32(cpu_tmp2_i32, -1);
! 6355: tcg_gen_st_i32(cpu_tmp2_i32, cpu_env, offsetof(CPUState, df));
1.1 root 6356: break;
6357:
6358: /************************/
6359: /* bit operations */
6360: case 0x1ba: /* bt/bts/btr/btc Gv, im */
6361: ot = dflag + OT_WORD;
6362: modrm = ldub_code(s->pc++);
1.1.1.3 root 6363: op = (modrm >> 3) & 7;
1.1 root 6364: mod = (modrm >> 6) & 3;
6365: rm = (modrm & 7) | REX_B(s);
6366: if (mod != 3) {
6367: s->rip_offset = 1;
6368: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 6369: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 6370: } else {
1.1.1.7 ! root 6371: gen_op_mov_TN_reg(ot, 0, rm);
1.1 root 6372: }
6373: /* load shift */
6374: val = ldub_code(s->pc++);
6375: gen_op_movl_T1_im(val);
6376: if (op < 4)
6377: goto illegal_op;
6378: op -= 4;
1.1.1.7 ! root 6379: goto bt_op;
1.1 root 6380: case 0x1a3: /* bt Gv, Ev */
6381: op = 0;
6382: goto do_btx;
6383: case 0x1ab: /* bts */
6384: op = 1;
6385: goto do_btx;
6386: case 0x1b3: /* btr */
6387: op = 2;
6388: goto do_btx;
6389: case 0x1bb: /* btc */
6390: op = 3;
6391: do_btx:
6392: ot = dflag + OT_WORD;
6393: modrm = ldub_code(s->pc++);
6394: reg = ((modrm >> 3) & 7) | rex_r;
6395: mod = (modrm >> 6) & 3;
6396: rm = (modrm & 7) | REX_B(s);
1.1.1.7 ! root 6397: gen_op_mov_TN_reg(OT_LONG, 1, reg);
1.1 root 6398: if (mod != 3) {
6399: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
6400: /* specific case: we need to add a displacement */
1.1.1.7 ! root 6401: gen_exts(ot, cpu_T[1]);
! 6402: tcg_gen_sari_tl(cpu_tmp0, cpu_T[1], 3 + ot);
! 6403: tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, ot);
! 6404: tcg_gen_add_tl(cpu_A0, cpu_A0, cpu_tmp0);
! 6405: gen_op_ld_T0_A0(ot + s->mem_index);
1.1 root 6406: } else {
1.1.1.7 ! root 6407: gen_op_mov_TN_reg(ot, 0, rm);
! 6408: }
! 6409: bt_op:
! 6410: tcg_gen_andi_tl(cpu_T[1], cpu_T[1], (1 << (3 + ot)) - 1);
! 6411: switch(op) {
! 6412: case 0:
! 6413: tcg_gen_shr_tl(cpu_cc_src, cpu_T[0], cpu_T[1]);
! 6414: tcg_gen_movi_tl(cpu_cc_dst, 0);
! 6415: break;
! 6416: case 1:
! 6417: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
! 6418: tcg_gen_movi_tl(cpu_tmp0, 1);
! 6419: tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
! 6420: tcg_gen_or_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 6421: break;
! 6422: case 2:
! 6423: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
! 6424: tcg_gen_movi_tl(cpu_tmp0, 1);
! 6425: tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
! 6426: tcg_gen_not_tl(cpu_tmp0, cpu_tmp0);
! 6427: tcg_gen_and_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 6428: break;
! 6429: default:
! 6430: case 3:
! 6431: tcg_gen_shr_tl(cpu_tmp4, cpu_T[0], cpu_T[1]);
! 6432: tcg_gen_movi_tl(cpu_tmp0, 1);
! 6433: tcg_gen_shl_tl(cpu_tmp0, cpu_tmp0, cpu_T[1]);
! 6434: tcg_gen_xor_tl(cpu_T[0], cpu_T[0], cpu_tmp0);
! 6435: break;
1.1 root 6436: }
6437: s->cc_op = CC_OP_SARB + ot;
6438: if (op != 0) {
6439: if (mod != 3)
1.1.1.7 ! root 6440: gen_op_st_T0_A0(ot + s->mem_index);
1.1 root 6441: else
1.1.1.7 ! root 6442: gen_op_mov_reg_T0(ot, rm);
! 6443: tcg_gen_mov_tl(cpu_cc_src, cpu_tmp4);
! 6444: tcg_gen_movi_tl(cpu_cc_dst, 0);
1.1 root 6445: }
6446: break;
6447: case 0x1bc: /* bsf */
6448: case 0x1bd: /* bsr */
1.1.1.7 ! root 6449: {
! 6450: int label1;
! 6451: TCGv t0;
! 6452:
! 6453: ot = dflag + OT_WORD;
! 6454: modrm = ldub_code(s->pc++);
! 6455: reg = ((modrm >> 3) & 7) | rex_r;
! 6456: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
! 6457: gen_extu(ot, cpu_T[0]);
! 6458: label1 = gen_new_label();
! 6459: tcg_gen_movi_tl(cpu_cc_dst, 0);
! 6460: t0 = tcg_temp_local_new();
! 6461: tcg_gen_mov_tl(t0, cpu_T[0]);
! 6462: tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, label1);
! 6463: if (b & 1) {
! 6464: gen_helper_bsr(cpu_T[0], t0);
! 6465: } else {
! 6466: gen_helper_bsf(cpu_T[0], t0);
! 6467: }
! 6468: gen_op_mov_reg_T0(ot, reg);
! 6469: tcg_gen_movi_tl(cpu_cc_dst, 1);
! 6470: gen_set_label(label1);
! 6471: tcg_gen_discard_tl(cpu_cc_src);
! 6472: s->cc_op = CC_OP_LOGICB + ot;
! 6473: tcg_temp_free(t0);
! 6474: }
1.1 root 6475: break;
6476: /************************/
6477: /* bcd */
6478: case 0x27: /* daa */
6479: if (CODE64(s))
6480: goto illegal_op;
6481: if (s->cc_op != CC_OP_DYNAMIC)
6482: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6483: gen_helper_daa();
1.1 root 6484: s->cc_op = CC_OP_EFLAGS;
6485: break;
6486: case 0x2f: /* das */
6487: if (CODE64(s))
6488: goto illegal_op;
6489: if (s->cc_op != CC_OP_DYNAMIC)
6490: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6491: gen_helper_das();
1.1 root 6492: s->cc_op = CC_OP_EFLAGS;
6493: break;
6494: case 0x37: /* aaa */
6495: if (CODE64(s))
6496: goto illegal_op;
6497: if (s->cc_op != CC_OP_DYNAMIC)
6498: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6499: gen_helper_aaa();
1.1 root 6500: s->cc_op = CC_OP_EFLAGS;
6501: break;
6502: case 0x3f: /* aas */
6503: if (CODE64(s))
6504: goto illegal_op;
6505: if (s->cc_op != CC_OP_DYNAMIC)
6506: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6507: gen_helper_aas();
1.1 root 6508: s->cc_op = CC_OP_EFLAGS;
6509: break;
6510: case 0xd4: /* aam */
6511: if (CODE64(s))
6512: goto illegal_op;
6513: val = ldub_code(s->pc++);
1.1.1.6 root 6514: if (val == 0) {
6515: gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
6516: } else {
1.1.1.7 ! root 6517: gen_helper_aam(tcg_const_i32(val));
1.1.1.6 root 6518: s->cc_op = CC_OP_LOGICB;
6519: }
1.1 root 6520: break;
6521: case 0xd5: /* aad */
6522: if (CODE64(s))
6523: goto illegal_op;
6524: val = ldub_code(s->pc++);
1.1.1.7 ! root 6525: gen_helper_aad(tcg_const_i32(val));
1.1 root 6526: s->cc_op = CC_OP_LOGICB;
6527: break;
6528: /************************/
6529: /* misc */
6530: case 0x90: /* nop */
6531: /* XXX: xchg + rex handling */
6532: /* XXX: correct lock test for all insn */
6533: if (prefixes & PREFIX_LOCK)
6534: goto illegal_op;
1.1.1.6 root 6535: if (prefixes & PREFIX_REPZ) {
6536: gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE);
6537: }
1.1 root 6538: break;
6539: case 0x9b: /* fwait */
1.1.1.6 root 6540: if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
1.1 root 6541: (HF_MP_MASK | HF_TS_MASK)) {
6542: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
6543: } else {
6544: if (s->cc_op != CC_OP_DYNAMIC)
6545: gen_op_set_cc_op(s->cc_op);
6546: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6547: gen_helper_fwait();
1.1 root 6548: }
6549: break;
6550: case 0xcc: /* int3 */
6551: gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
6552: break;
6553: case 0xcd: /* int N */
6554: val = ldub_code(s->pc++);
6555: if (s->vm86 && s->iopl != 3) {
1.1.1.6 root 6556: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
1.1 root 6557: } else {
6558: gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
6559: }
6560: break;
6561: case 0xce: /* into */
6562: if (CODE64(s))
6563: goto illegal_op;
6564: if (s->cc_op != CC_OP_DYNAMIC)
6565: gen_op_set_cc_op(s->cc_op);
6566: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6567: gen_helper_into(tcg_const_i32(s->pc - pc_start));
1.1 root 6568: break;
1.1.1.7 ! root 6569: #ifdef WANT_ICEBP
1.1 root 6570: case 0xf1: /* icebp (undocumented, exits to external debugger) */
1.1.1.7 ! root 6571: gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP);
1.1 root 6572: #if 1
6573: gen_debug(s, pc_start - s->cs_base);
6574: #else
6575: /* start debug */
6576: tb_flush(cpu_single_env);
6577: cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM);
6578: #endif
6579: break;
1.1.1.7 ! root 6580: #endif
1.1 root 6581: case 0xfa: /* cli */
6582: if (!s->vm86) {
6583: if (s->cpl <= s->iopl) {
1.1.1.7 ! root 6584: gen_helper_cli();
1.1 root 6585: } else {
6586: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6587: }
6588: } else {
6589: if (s->iopl == 3) {
1.1.1.7 ! root 6590: gen_helper_cli();
1.1 root 6591: } else {
6592: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6593: }
6594: }
6595: break;
6596: case 0xfb: /* sti */
6597: if (!s->vm86) {
6598: if (s->cpl <= s->iopl) {
6599: gen_sti:
1.1.1.7 ! root 6600: gen_helper_sti();
1.1 root 6601: /* interruptions are enabled only the first insn after sti */
6602: /* If several instructions disable interrupts, only the
6603: _first_ does it */
6604: if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
1.1.1.7 ! root 6605: gen_helper_set_inhibit_irq();
1.1 root 6606: /* give a chance to handle pending irqs */
6607: gen_jmp_im(s->pc - s->cs_base);
6608: gen_eob(s);
6609: } else {
6610: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6611: }
6612: } else {
6613: if (s->iopl == 3) {
6614: goto gen_sti;
6615: } else {
6616: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6617: }
6618: }
6619: break;
6620: case 0x62: /* bound */
6621: if (CODE64(s))
6622: goto illegal_op;
6623: ot = dflag ? OT_LONG : OT_WORD;
6624: modrm = ldub_code(s->pc++);
6625: reg = (modrm >> 3) & 7;
6626: mod = (modrm >> 6) & 3;
6627: if (mod == 3)
6628: goto illegal_op;
1.1.1.7 ! root 6629: gen_op_mov_TN_reg(ot, 0, reg);
1.1 root 6630: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
6631: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6632: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
1.1 root 6633: if (ot == OT_WORD)
1.1.1.7 ! root 6634: gen_helper_boundw(cpu_A0, cpu_tmp2_i32);
1.1 root 6635: else
1.1.1.7 ! root 6636: gen_helper_boundl(cpu_A0, cpu_tmp2_i32);
1.1 root 6637: break;
6638: case 0x1c8 ... 0x1cf: /* bswap reg */
6639: reg = (b & 7) | REX_B(s);
6640: #ifdef TARGET_X86_64
6641: if (dflag == 2) {
1.1.1.7 ! root 6642: gen_op_mov_TN_reg(OT_QUAD, 0, reg);
! 6643: tcg_gen_bswap_i64(cpu_T[0], cpu_T[0]);
! 6644: gen_op_mov_reg_T0(OT_QUAD, reg);
1.1.1.6 root 6645: } else
1.1 root 6646: {
1.1.1.7 ! root 6647: TCGv_i32 tmp0;
! 6648: gen_op_mov_TN_reg(OT_LONG, 0, reg);
! 6649:
! 6650: tmp0 = tcg_temp_new_i32();
! 6651: tcg_gen_trunc_i64_i32(tmp0, cpu_T[0]);
! 6652: tcg_gen_bswap_i32(tmp0, tmp0);
! 6653: tcg_gen_extu_i32_i64(cpu_T[0], tmp0);
! 6654: gen_op_mov_reg_T0(OT_LONG, reg);
! 6655: }
! 6656: #else
! 6657: {
! 6658: gen_op_mov_TN_reg(OT_LONG, 0, reg);
! 6659: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]);
! 6660: gen_op_mov_reg_T0(OT_LONG, reg);
1.1 root 6661: }
1.1.1.7 ! root 6662: #endif
1.1 root 6663: break;
6664: case 0xd6: /* salc */
6665: if (CODE64(s))
6666: goto illegal_op;
6667: if (s->cc_op != CC_OP_DYNAMIC)
6668: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6669: gen_compute_eflags_c(cpu_T[0]);
! 6670: tcg_gen_neg_tl(cpu_T[0], cpu_T[0]);
! 6671: gen_op_mov_reg_T0(OT_BYTE, R_EAX);
1.1 root 6672: break;
6673: case 0xe0: /* loopnz */
6674: case 0xe1: /* loopz */
6675: case 0xe2: /* loop */
6676: case 0xe3: /* jecxz */
6677: {
1.1.1.7 ! root 6678: int l1, l2, l3;
1.1 root 6679:
6680: tval = (int8_t)insn_get(s, OT_BYTE);
6681: next_eip = s->pc - s->cs_base;
6682: tval += next_eip;
6683: if (s->dflag == 0)
6684: tval &= 0xffff;
1.1.1.6 root 6685:
1.1 root 6686: l1 = gen_new_label();
6687: l2 = gen_new_label();
1.1.1.7 ! root 6688: l3 = gen_new_label();
1.1 root 6689: b &= 3;
1.1.1.7 ! root 6690: switch(b) {
! 6691: case 0: /* loopnz */
! 6692: case 1: /* loopz */
! 6693: if (s->cc_op != CC_OP_DYNAMIC)
! 6694: gen_op_set_cc_op(s->cc_op);
! 6695: gen_op_add_reg_im(s->aflag, R_ECX, -1);
! 6696: gen_op_jz_ecx(s->aflag, l3);
! 6697: gen_compute_eflags(cpu_tmp0);
! 6698: tcg_gen_andi_tl(cpu_tmp0, cpu_tmp0, CC_Z);
! 6699: if (b == 0) {
! 6700: tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, l1);
! 6701: } else {
! 6702: tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, l1);
! 6703: }
! 6704: break;
! 6705: case 2: /* loop */
! 6706: gen_op_add_reg_im(s->aflag, R_ECX, -1);
! 6707: gen_op_jnz_ecx(s->aflag, l1);
! 6708: break;
! 6709: default:
! 6710: case 3: /* jcxz */
! 6711: gen_op_jz_ecx(s->aflag, l1);
! 6712: break;
1.1 root 6713: }
6714:
1.1.1.7 ! root 6715: gen_set_label(l3);
1.1 root 6716: gen_jmp_im(next_eip);
1.1.1.7 ! root 6717: tcg_gen_br(l2);
! 6718:
1.1 root 6719: gen_set_label(l1);
6720: gen_jmp_im(tval);
6721: gen_set_label(l2);
6722: gen_eob(s);
6723: }
6724: break;
6725: case 0x130: /* wrmsr */
6726: case 0x132: /* rdmsr */
6727: if (s->cpl != 0) {
6728: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6729: } else {
1.1.1.7 ! root 6730: if (s->cc_op != CC_OP_DYNAMIC)
! 6731: gen_op_set_cc_op(s->cc_op);
! 6732: gen_jmp_im(pc_start - s->cs_base);
1.1.1.6 root 6733: if (b & 2) {
1.1.1.7 ! root 6734: gen_helper_rdmsr();
1.1.1.6 root 6735: } else {
1.1.1.7 ! root 6736: gen_helper_wrmsr();
1.1.1.6 root 6737: }
1.1 root 6738: }
6739: break;
6740: case 0x131: /* rdtsc */
1.1.1.7 ! root 6741: if (s->cc_op != CC_OP_DYNAMIC)
! 6742: gen_op_set_cc_op(s->cc_op);
1.1 root 6743: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6744: if (use_icount)
! 6745: gen_io_start();
! 6746: gen_helper_rdtsc();
! 6747: if (use_icount) {
! 6748: gen_io_end();
! 6749: gen_jmp(s, s->pc - s->cs_base);
! 6750: }
1.1 root 6751: break;
1.1.1.6 root 6752: case 0x133: /* rdpmc */
1.1.1.7 ! root 6753: if (s->cc_op != CC_OP_DYNAMIC)
! 6754: gen_op_set_cc_op(s->cc_op);
1.1.1.6 root 6755: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6756: gen_helper_rdpmc();
1.1.1.6 root 6757: break;
1.1 root 6758: case 0x134: /* sysenter */
1.1.1.7 ! root 6759: /* For Intel SYSENTER is valid on 64-bit */
! 6760: if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
1.1 root 6761: goto illegal_op;
6762: if (!s->pe) {
6763: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6764: } else {
6765: if (s->cc_op != CC_OP_DYNAMIC) {
6766: gen_op_set_cc_op(s->cc_op);
6767: s->cc_op = CC_OP_DYNAMIC;
6768: }
6769: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6770: gen_helper_sysenter();
1.1 root 6771: gen_eob(s);
6772: }
6773: break;
6774: case 0x135: /* sysexit */
1.1.1.7 ! root 6775: /* For Intel SYSEXIT is valid on 64-bit */
! 6776: if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
1.1 root 6777: goto illegal_op;
6778: if (!s->pe) {
6779: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6780: } else {
6781: if (s->cc_op != CC_OP_DYNAMIC) {
6782: gen_op_set_cc_op(s->cc_op);
6783: s->cc_op = CC_OP_DYNAMIC;
6784: }
6785: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6786: gen_helper_sysexit(tcg_const_i32(dflag));
1.1 root 6787: gen_eob(s);
6788: }
6789: break;
6790: #ifdef TARGET_X86_64
6791: case 0x105: /* syscall */
6792: /* XXX: is it usable in real mode ? */
6793: if (s->cc_op != CC_OP_DYNAMIC) {
6794: gen_op_set_cc_op(s->cc_op);
6795: s->cc_op = CC_OP_DYNAMIC;
6796: }
6797: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6798: gen_helper_syscall(tcg_const_i32(s->pc - pc_start));
1.1 root 6799: gen_eob(s);
6800: break;
6801: case 0x107: /* sysret */
6802: if (!s->pe) {
6803: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6804: } else {
6805: if (s->cc_op != CC_OP_DYNAMIC) {
6806: gen_op_set_cc_op(s->cc_op);
6807: s->cc_op = CC_OP_DYNAMIC;
6808: }
6809: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6810: gen_helper_sysret(tcg_const_i32(s->dflag));
1.1 root 6811: /* condition codes are modified only in long mode */
6812: if (s->lma)
6813: s->cc_op = CC_OP_EFLAGS;
6814: gen_eob(s);
6815: }
6816: break;
6817: #endif
6818: case 0x1a2: /* cpuid */
1.1.1.7 ! root 6819: if (s->cc_op != CC_OP_DYNAMIC)
! 6820: gen_op_set_cc_op(s->cc_op);
! 6821: gen_jmp_im(pc_start - s->cs_base);
! 6822: gen_helper_cpuid();
1.1 root 6823: break;
6824: case 0xf4: /* hlt */
6825: if (s->cpl != 0) {
6826: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6827: } else {
6828: if (s->cc_op != CC_OP_DYNAMIC)
6829: gen_op_set_cc_op(s->cc_op);
1.1.1.7 ! root 6830: gen_jmp_im(pc_start - s->cs_base);
! 6831: gen_helper_hlt(tcg_const_i32(s->pc - pc_start));
1.1 root 6832: s->is_jmp = 3;
6833: }
6834: break;
6835: case 0x100:
6836: modrm = ldub_code(s->pc++);
6837: mod = (modrm >> 6) & 3;
6838: op = (modrm >> 3) & 7;
6839: switch(op) {
6840: case 0: /* sldt */
6841: if (!s->pe || s->vm86)
6842: goto illegal_op;
1.1.1.7 ! root 6843: gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ);
! 6844: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,ldt.selector));
1.1 root 6845: ot = OT_WORD;
6846: if (mod == 3)
6847: ot += s->dflag;
6848: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
6849: break;
6850: case 2: /* lldt */
6851: if (!s->pe || s->vm86)
6852: goto illegal_op;
6853: if (s->cpl != 0) {
6854: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6855: } else {
1.1.1.7 ! root 6856: gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE);
1.1 root 6857: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
6858: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6859: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 6860: gen_helper_lldt(cpu_tmp2_i32);
1.1 root 6861: }
6862: break;
6863: case 1: /* str */
6864: if (!s->pe || s->vm86)
6865: goto illegal_op;
1.1.1.7 ! root 6866: gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ);
! 6867: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,tr.selector));
1.1 root 6868: ot = OT_WORD;
6869: if (mod == 3)
6870: ot += s->dflag;
6871: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
6872: break;
6873: case 3: /* ltr */
6874: if (!s->pe || s->vm86)
6875: goto illegal_op;
6876: if (s->cpl != 0) {
6877: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
6878: } else {
1.1.1.7 ! root 6879: gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE);
1.1 root 6880: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
6881: gen_jmp_im(pc_start - s->cs_base);
1.1.1.7 ! root 6882: tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_T[0]);
! 6883: gen_helper_ltr(cpu_tmp2_i32);
1.1 root 6884: }
6885: break;
6886: case 4: /* verr */
6887: case 5: /* verw */
6888: if (!s->pe || s->vm86)
6889: goto illegal_op;
6890: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
6891: if (s->cc_op != CC_OP_DYNAMIC)
6892: gen_op_set_cc_op(s->cc_op);
6893: if (op == 4)
1.1.1.7 ! root 6894: gen_helper_verr(cpu_T[0]);
1.1 root 6895: else
1.1.1.7 ! root 6896: gen_helper_verw(cpu_T[0]);
1.1 root 6897: s->cc_op = CC_OP_EFLAGS;
6898: break;
6899: default:
6900: goto illegal_op;
6901: }
6902: break;
6903: case 0x101:
6904: modrm = ldub_code(s->pc++);
6905: mod = (modrm >> 6) & 3;
6906: op = (modrm >> 3) & 7;
1.1.1.4 root 6907: rm = modrm & 7;
1.1 root 6908: switch(op) {
6909: case 0: /* sgdt */
6910: if (mod == 3)
6911: goto illegal_op;
1.1.1.7 ! root 6912: gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
1.1 root 6913: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 6914: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.limit));
! 6915: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1 root 6916: gen_add_A0_im(s, 2);
1.1.1.7 ! root 6917: tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, gdt.base));
1.1 root 6918: if (!s->dflag)
6919: gen_op_andl_T0_im(0xffffff);
1.1.1.7 ! root 6920: gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
1.1 root 6921: break;
1.1.1.4 root 6922: case 1:
6923: if (mod == 3) {
6924: switch (rm) {
6925: case 0: /* monitor */
6926: if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
6927: s->cpl != 0)
6928: goto illegal_op;
1.1.1.7 ! root 6929: if (s->cc_op != CC_OP_DYNAMIC)
! 6930: gen_op_set_cc_op(s->cc_op);
1.1.1.4 root 6931: gen_jmp_im(pc_start - s->cs_base);
6932: #ifdef TARGET_X86_64
6933: if (s->aflag == 2) {
1.1.1.7 ! root 6934: gen_op_movq_A0_reg(R_EAX);
1.1.1.6 root 6935: } else
1.1.1.4 root 6936: #endif
6937: {
1.1.1.7 ! root 6938: gen_op_movl_A0_reg(R_EAX);
1.1.1.4 root 6939: if (s->aflag == 0)
6940: gen_op_andl_A0_ffff();
6941: }
6942: gen_add_A0_ds_seg(s);
1.1.1.7 ! root 6943: gen_helper_monitor(cpu_A0);
1.1.1.4 root 6944: break;
6945: case 1: /* mwait */
6946: if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
6947: s->cpl != 0)
6948: goto illegal_op;
6949: if (s->cc_op != CC_OP_DYNAMIC) {
6950: gen_op_set_cc_op(s->cc_op);
6951: s->cc_op = CC_OP_DYNAMIC;
6952: }
1.1.1.7 ! root 6953: gen_jmp_im(pc_start - s->cs_base);
! 6954: gen_helper_mwait(tcg_const_i32(s->pc - pc_start));
1.1.1.4 root 6955: gen_eob(s);
6956: break;
6957: default:
6958: goto illegal_op;
6959: }
6960: } else { /* sidt */
1.1.1.7 ! root 6961: gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
1.1.1.4 root 6962: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 6963: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.limit));
! 6964: gen_op_st_T0_A0(OT_WORD + s->mem_index);
1.1.1.4 root 6965: gen_add_A0_im(s, 2);
1.1.1.7 ! root 6966: tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, idt.base));
1.1.1.4 root 6967: if (!s->dflag)
6968: gen_op_andl_T0_im(0xffffff);
1.1.1.7 ! root 6969: gen_op_st_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
1.1.1.4 root 6970: }
6971: break;
1.1 root 6972: case 2: /* lgdt */
6973: case 3: /* lidt */
1.1.1.6 root 6974: if (mod == 3) {
1.1.1.7 ! root 6975: if (s->cc_op != CC_OP_DYNAMIC)
! 6976: gen_op_set_cc_op(s->cc_op);
! 6977: gen_jmp_im(pc_start - s->cs_base);
1.1.1.6 root 6978: switch(rm) {
6979: case 0: /* VMRUN */
1.1.1.7 ! root 6980: if (!(s->flags & HF_SVME_MASK) || !s->pe)
! 6981: goto illegal_op;
! 6982: if (s->cpl != 0) {
! 6983: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
1.1.1.6 root 6984: break;
1.1.1.7 ! root 6985: } else {
! 6986: gen_helper_vmrun(tcg_const_i32(s->aflag),
! 6987: tcg_const_i32(s->pc - pc_start));
! 6988: tcg_gen_exit_tb(0);
! 6989: s->is_jmp = 3;
! 6990: }
1.1.1.6 root 6991: break;
6992: case 1: /* VMMCALL */
1.1.1.7 ! root 6993: if (!(s->flags & HF_SVME_MASK))
! 6994: goto illegal_op;
! 6995: gen_helper_vmmcall();
1.1.1.6 root 6996: break;
6997: case 2: /* VMLOAD */
1.1.1.7 ! root 6998: if (!(s->flags & HF_SVME_MASK) || !s->pe)
! 6999: goto illegal_op;
! 7000: if (s->cpl != 0) {
! 7001: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
! 7002: break;
! 7003: } else {
! 7004: gen_helper_vmload(tcg_const_i32(s->aflag));
! 7005: }
1.1.1.6 root 7006: break;
7007: case 3: /* VMSAVE */
1.1.1.7 ! root 7008: if (!(s->flags & HF_SVME_MASK) || !s->pe)
! 7009: goto illegal_op;
! 7010: if (s->cpl != 0) {
! 7011: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
! 7012: break;
! 7013: } else {
! 7014: gen_helper_vmsave(tcg_const_i32(s->aflag));
! 7015: }
1.1.1.6 root 7016: break;
7017: case 4: /* STGI */
1.1.1.7 ! root 7018: if ((!(s->flags & HF_SVME_MASK) &&
! 7019: !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
! 7020: !s->pe)
! 7021: goto illegal_op;
! 7022: if (s->cpl != 0) {
! 7023: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
! 7024: break;
! 7025: } else {
! 7026: gen_helper_stgi();
! 7027: }
1.1.1.6 root 7028: break;
7029: case 5: /* CLGI */
1.1.1.7 ! root 7030: if (!(s->flags & HF_SVME_MASK) || !s->pe)
! 7031: goto illegal_op;
! 7032: if (s->cpl != 0) {
! 7033: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
! 7034: break;
! 7035: } else {
! 7036: gen_helper_clgi();
! 7037: }
1.1.1.6 root 7038: break;
7039: case 6: /* SKINIT */
1.1.1.7 ! root 7040: if ((!(s->flags & HF_SVME_MASK) &&
! 7041: !(s->cpuid_ext3_features & CPUID_EXT3_SKINIT)) ||
! 7042: !s->pe)
! 7043: goto illegal_op;
! 7044: gen_helper_skinit();
1.1.1.6 root 7045: break;
7046: case 7: /* INVLPGA */
1.1.1.7 ! root 7047: if (!(s->flags & HF_SVME_MASK) || !s->pe)
! 7048: goto illegal_op;
! 7049: if (s->cpl != 0) {
! 7050: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
! 7051: break;
! 7052: } else {
! 7053: gen_helper_invlpga(tcg_const_i32(s->aflag));
! 7054: }
1.1.1.6 root 7055: break;
7056: default:
7057: goto illegal_op;
7058: }
7059: } else if (s->cpl != 0) {
1.1 root 7060: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7061: } else {
1.1.1.7 ! root 7062: gen_svm_check_intercept(s, pc_start,
! 7063: op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE);
1.1 root 7064: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 7065: gen_op_ld_T1_A0(OT_WORD + s->mem_index);
1.1 root 7066: gen_add_A0_im(s, 2);
1.1.1.7 ! root 7067: gen_op_ld_T0_A0(CODE64(s) + OT_LONG + s->mem_index);
1.1 root 7068: if (!s->dflag)
7069: gen_op_andl_T0_im(0xffffff);
7070: if (op == 2) {
1.1.1.7 ! root 7071: tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,gdt.base));
! 7072: tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,gdt.limit));
1.1 root 7073: } else {
1.1.1.7 ! root 7074: tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,idt.base));
! 7075: tcg_gen_st32_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,idt.limit));
1.1 root 7076: }
7077: }
7078: break;
7079: case 4: /* smsw */
1.1.1.7 ! root 7080: gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
! 7081: #if defined TARGET_X86_64 && defined WORDS_BIGENDIAN
! 7082: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0]) + 4);
! 7083: #else
! 7084: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,cr[0]));
! 7085: #endif
1.1 root 7086: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
7087: break;
7088: case 6: /* lmsw */
7089: if (s->cpl != 0) {
7090: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7091: } else {
1.1.1.7 ! root 7092: gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
1.1 root 7093: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
1.1.1.7 ! root 7094: gen_helper_lmsw(cpu_T[0]);
1.1 root 7095: gen_jmp_im(s->pc - s->cs_base);
7096: gen_eob(s);
7097: }
7098: break;
7099: case 7: /* invlpg */
7100: if (s->cpl != 0) {
7101: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7102: } else {
7103: if (mod == 3) {
7104: #ifdef TARGET_X86_64
1.1.1.4 root 7105: if (CODE64(s) && rm == 0) {
1.1 root 7106: /* swapgs */
1.1.1.7 ! root 7107: tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,segs[R_GS].base));
! 7108: tcg_gen_ld_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,kernelgsbase));
! 7109: tcg_gen_st_tl(cpu_T[1], cpu_env, offsetof(CPUX86State,segs[R_GS].base));
! 7110: tcg_gen_st_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,kernelgsbase));
1.1.1.6 root 7111: } else
1.1 root 7112: #endif
7113: {
7114: goto illegal_op;
7115: }
7116: } else {
1.1.1.7 ! root 7117: if (s->cc_op != CC_OP_DYNAMIC)
! 7118: gen_op_set_cc_op(s->cc_op);
! 7119: gen_jmp_im(pc_start - s->cs_base);
1.1 root 7120: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 7121: gen_helper_invlpg(cpu_A0);
1.1 root 7122: gen_jmp_im(s->pc - s->cs_base);
7123: gen_eob(s);
7124: }
7125: }
7126: break;
7127: default:
7128: goto illegal_op;
7129: }
7130: break;
7131: case 0x108: /* invd */
7132: case 0x109: /* wbinvd */
7133: if (s->cpl != 0) {
7134: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7135: } else {
1.1.1.7 ! root 7136: gen_svm_check_intercept(s, pc_start, (b & 2) ? SVM_EXIT_INVD : SVM_EXIT_WBINVD);
1.1 root 7137: /* nothing to do */
7138: }
7139: break;
7140: case 0x63: /* arpl or movslS (x86_64) */
7141: #ifdef TARGET_X86_64
7142: if (CODE64(s)) {
7143: int d_ot;
7144: /* d_ot is the size of destination */
7145: d_ot = dflag + OT_WORD;
7146:
7147: modrm = ldub_code(s->pc++);
7148: reg = ((modrm >> 3) & 7) | rex_r;
7149: mod = (modrm >> 6) & 3;
7150: rm = (modrm & 7) | REX_B(s);
1.1.1.6 root 7151:
1.1 root 7152: if (mod == 3) {
1.1.1.7 ! root 7153: gen_op_mov_TN_reg(OT_LONG, 0, rm);
1.1 root 7154: /* sign extend */
7155: if (d_ot == OT_QUAD)
1.1.1.7 ! root 7156: tcg_gen_ext32s_tl(cpu_T[0], cpu_T[0]);
! 7157: gen_op_mov_reg_T0(d_ot, reg);
1.1 root 7158: } else {
7159: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
7160: if (d_ot == OT_QUAD) {
1.1.1.7 ! root 7161: gen_op_lds_T0_A0(OT_LONG + s->mem_index);
1.1 root 7162: } else {
1.1.1.7 ! root 7163: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
1.1 root 7164: }
1.1.1.7 ! root 7165: gen_op_mov_reg_T0(d_ot, reg);
1.1 root 7166: }
1.1.1.6 root 7167: } else
1.1 root 7168: #endif
7169: {
1.1.1.7 ! root 7170: int label1;
! 7171: TCGv t0, t1, t2;
! 7172:
1.1 root 7173: if (!s->pe || s->vm86)
7174: goto illegal_op;
1.1.1.7 ! root 7175: t0 = tcg_temp_local_new();
! 7176: t1 = tcg_temp_local_new();
! 7177: t2 = tcg_temp_local_new();
! 7178: ot = OT_WORD;
1.1 root 7179: modrm = ldub_code(s->pc++);
7180: reg = (modrm >> 3) & 7;
7181: mod = (modrm >> 6) & 3;
7182: rm = modrm & 7;
7183: if (mod != 3) {
7184: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 7185: gen_op_ld_v(ot + s->mem_index, t0, cpu_A0);
1.1 root 7186: } else {
1.1.1.7 ! root 7187: gen_op_mov_v_reg(ot, t0, rm);
1.1 root 7188: }
1.1.1.7 ! root 7189: gen_op_mov_v_reg(ot, t1, reg);
! 7190: tcg_gen_andi_tl(cpu_tmp0, t0, 3);
! 7191: tcg_gen_andi_tl(t1, t1, 3);
! 7192: tcg_gen_movi_tl(t2, 0);
! 7193: label1 = gen_new_label();
! 7194: tcg_gen_brcond_tl(TCG_COND_GE, cpu_tmp0, t1, label1);
! 7195: tcg_gen_andi_tl(t0, t0, ~3);
! 7196: tcg_gen_or_tl(t0, t0, t1);
! 7197: tcg_gen_movi_tl(t2, CC_Z);
! 7198: gen_set_label(label1);
1.1 root 7199: if (mod != 3) {
1.1.1.7 ! root 7200: gen_op_st_v(ot + s->mem_index, t0, cpu_A0);
1.1 root 7201: } else {
1.1.1.7 ! root 7202: gen_op_mov_reg_v(ot, rm, t0);
1.1 root 7203: }
1.1.1.7 ! root 7204: if (s->cc_op != CC_OP_DYNAMIC)
! 7205: gen_op_set_cc_op(s->cc_op);
! 7206: gen_compute_eflags(cpu_cc_src);
! 7207: tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, ~CC_Z);
! 7208: tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, t2);
! 7209: s->cc_op = CC_OP_EFLAGS;
! 7210: tcg_temp_free(t0);
! 7211: tcg_temp_free(t1);
! 7212: tcg_temp_free(t2);
1.1 root 7213: }
7214: break;
7215: case 0x102: /* lar */
7216: case 0x103: /* lsl */
1.1.1.7 ! root 7217: {
! 7218: int label1;
! 7219: TCGv t0;
! 7220: if (!s->pe || s->vm86)
! 7221: goto illegal_op;
! 7222: ot = dflag ? OT_LONG : OT_WORD;
! 7223: modrm = ldub_code(s->pc++);
! 7224: reg = ((modrm >> 3) & 7) | rex_r;
! 7225: gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
! 7226: t0 = tcg_temp_local_new();
! 7227: if (s->cc_op != CC_OP_DYNAMIC)
! 7228: gen_op_set_cc_op(s->cc_op);
! 7229: if (b == 0x102)
! 7230: gen_helper_lar(t0, cpu_T[0]);
! 7231: else
! 7232: gen_helper_lsl(t0, cpu_T[0]);
! 7233: tcg_gen_andi_tl(cpu_tmp0, cpu_cc_src, CC_Z);
! 7234: label1 = gen_new_label();
! 7235: tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
! 7236: gen_op_mov_reg_v(ot, reg, t0);
! 7237: gen_set_label(label1);
! 7238: s->cc_op = CC_OP_EFLAGS;
! 7239: tcg_temp_free(t0);
! 7240: }
1.1 root 7241: break;
7242: case 0x118:
7243: modrm = ldub_code(s->pc++);
7244: mod = (modrm >> 6) & 3;
7245: op = (modrm >> 3) & 7;
7246: switch(op) {
7247: case 0: /* prefetchnta */
7248: case 1: /* prefetchnt0 */
7249: case 2: /* prefetchnt0 */
7250: case 3: /* prefetchnt0 */
7251: if (mod == 3)
7252: goto illegal_op;
7253: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
7254: /* nothing more to do */
7255: break;
1.1.1.5 root 7256: default: /* nop (multi byte) */
7257: gen_nop_modrm(s, modrm);
7258: break;
1.1 root 7259: }
7260: break;
1.1.1.5 root 7261: case 0x119 ... 0x11f: /* nop (multi byte) */
7262: modrm = ldub_code(s->pc++);
7263: gen_nop_modrm(s, modrm);
7264: break;
1.1 root 7265: case 0x120: /* mov reg, crN */
7266: case 0x122: /* mov crN, reg */
7267: if (s->cpl != 0) {
7268: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7269: } else {
7270: modrm = ldub_code(s->pc++);
7271: if ((modrm & 0xc0) != 0xc0)
7272: goto illegal_op;
7273: rm = (modrm & 7) | REX_B(s);
7274: reg = ((modrm >> 3) & 7) | rex_r;
7275: if (CODE64(s))
7276: ot = OT_QUAD;
7277: else
7278: ot = OT_LONG;
7279: switch(reg) {
7280: case 0:
7281: case 2:
7282: case 3:
7283: case 4:
7284: case 8:
1.1.1.7 ! root 7285: if (s->cc_op != CC_OP_DYNAMIC)
! 7286: gen_op_set_cc_op(s->cc_op);
! 7287: gen_jmp_im(pc_start - s->cs_base);
1.1 root 7288: if (b & 2) {
1.1.1.7 ! root 7289: gen_op_mov_TN_reg(ot, 0, rm);
! 7290: gen_helper_write_crN(tcg_const_i32(reg), cpu_T[0]);
1.1 root 7291: gen_jmp_im(s->pc - s->cs_base);
7292: gen_eob(s);
7293: } else {
1.1.1.7 ! root 7294: gen_helper_read_crN(cpu_T[0], tcg_const_i32(reg));
! 7295: gen_op_mov_reg_T0(ot, rm);
1.1 root 7296: }
7297: break;
7298: default:
7299: goto illegal_op;
7300: }
7301: }
7302: break;
7303: case 0x121: /* mov reg, drN */
7304: case 0x123: /* mov drN, reg */
7305: if (s->cpl != 0) {
7306: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7307: } else {
7308: modrm = ldub_code(s->pc++);
7309: if ((modrm & 0xc0) != 0xc0)
7310: goto illegal_op;
7311: rm = (modrm & 7) | REX_B(s);
7312: reg = ((modrm >> 3) & 7) | rex_r;
7313: if (CODE64(s))
7314: ot = OT_QUAD;
7315: else
7316: ot = OT_LONG;
7317: /* XXX: do it dynamically with CR4.DE bit */
7318: if (reg == 4 || reg == 5 || reg >= 8)
7319: goto illegal_op;
7320: if (b & 2) {
1.1.1.6 root 7321: gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
1.1.1.7 ! root 7322: gen_op_mov_TN_reg(ot, 0, rm);
! 7323: gen_helper_movl_drN_T0(tcg_const_i32(reg), cpu_T[0]);
1.1 root 7324: gen_jmp_im(s->pc - s->cs_base);
7325: gen_eob(s);
7326: } else {
1.1.1.6 root 7327: gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg);
1.1.1.7 ! root 7328: tcg_gen_ld_tl(cpu_T[0], cpu_env, offsetof(CPUX86State,dr[reg]));
! 7329: gen_op_mov_reg_T0(ot, rm);
1.1 root 7330: }
7331: }
7332: break;
7333: case 0x106: /* clts */
7334: if (s->cpl != 0) {
7335: gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
7336: } else {
1.1.1.6 root 7337: gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
1.1.1.7 ! root 7338: gen_helper_clts();
1.1 root 7339: /* abort block because static cpu state changed */
7340: gen_jmp_im(s->pc - s->cs_base);
7341: gen_eob(s);
7342: }
7343: break;
1.1.1.7 ! root 7344: /* MMX/3DNow!/SSE/SSE2/SSE3/SSSE3/SSE4 support */
1.1 root 7345: case 0x1c3: /* MOVNTI reg, mem */
7346: if (!(s->cpuid_features & CPUID_SSE2))
7347: goto illegal_op;
7348: ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
7349: modrm = ldub_code(s->pc++);
7350: mod = (modrm >> 6) & 3;
7351: if (mod == 3)
7352: goto illegal_op;
7353: reg = ((modrm >> 3) & 7) | rex_r;
7354: /* generate a generic store */
7355: gen_ldst_modrm(s, modrm, ot, reg, 1);
7356: break;
7357: case 0x1ae:
7358: modrm = ldub_code(s->pc++);
7359: mod = (modrm >> 6) & 3;
7360: op = (modrm >> 3) & 7;
7361: switch(op) {
7362: case 0: /* fxsave */
1.1.1.6 root 7363: if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
1.1.1.3 root 7364: (s->flags & HF_EM_MASK))
1.1 root 7365: goto illegal_op;
1.1.1.3 root 7366: if (s->flags & HF_TS_MASK) {
7367: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
7368: break;
7369: }
1.1 root 7370: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 7371: if (s->cc_op != CC_OP_DYNAMIC)
! 7372: gen_op_set_cc_op(s->cc_op);
! 7373: gen_jmp_im(pc_start - s->cs_base);
! 7374: gen_helper_fxsave(cpu_A0, tcg_const_i32((s->dflag == 2)));
1.1 root 7375: break;
7376: case 1: /* fxrstor */
1.1.1.6 root 7377: if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
1.1.1.3 root 7378: (s->flags & HF_EM_MASK))
1.1 root 7379: goto illegal_op;
1.1.1.3 root 7380: if (s->flags & HF_TS_MASK) {
7381: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
7382: break;
7383: }
1.1 root 7384: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
1.1.1.7 ! root 7385: if (s->cc_op != CC_OP_DYNAMIC)
! 7386: gen_op_set_cc_op(s->cc_op);
! 7387: gen_jmp_im(pc_start - s->cs_base);
! 7388: gen_helper_fxrstor(cpu_A0, tcg_const_i32((s->dflag == 2)));
1.1 root 7389: break;
7390: case 2: /* ldmxcsr */
7391: case 3: /* stmxcsr */
7392: if (s->flags & HF_TS_MASK) {
7393: gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
7394: break;
7395: }
7396: if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) ||
7397: mod == 3)
7398: goto illegal_op;
7399: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
7400: if (op == 2) {
1.1.1.7 ! root 7401: gen_op_ld_T0_A0(OT_LONG + s->mem_index);
! 7402: tcg_gen_st32_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
1.1 root 7403: } else {
1.1.1.7 ! root 7404: tcg_gen_ld32u_tl(cpu_T[0], cpu_env, offsetof(CPUX86State, mxcsr));
! 7405: gen_op_st_T0_A0(OT_LONG + s->mem_index);
1.1 root 7406: }
7407: break;
7408: case 5: /* lfence */
7409: case 6: /* mfence */
7410: if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
7411: goto illegal_op;
7412: break;
7413: case 7: /* sfence / clflush */
7414: if ((modrm & 0xc7) == 0xc0) {
7415: /* sfence */
1.1.1.7 ! root 7416: /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */
1.1 root 7417: if (!(s->cpuid_features & CPUID_SSE))
7418: goto illegal_op;
7419: } else {
7420: /* clflush */
7421: if (!(s->cpuid_features & CPUID_CLFLUSH))
7422: goto illegal_op;
7423: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
7424: }
7425: break;
7426: default:
7427: goto illegal_op;
7428: }
7429: break;
1.1.1.7 ! root 7430: case 0x10d: /* 3DNow! prefetch(w) */
1.1 root 7431: modrm = ldub_code(s->pc++);
1.1.1.7 ! root 7432: mod = (modrm >> 6) & 3;
! 7433: if (mod == 3)
! 7434: goto illegal_op;
1.1 root 7435: gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
7436: /* ignore for now */
7437: break;
1.1.1.5 root 7438: case 0x1aa: /* rsm */
1.1.1.7 ! root 7439: gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM);
1.1.1.5 root 7440: if (!(s->flags & HF_SMM_MASK))
7441: goto illegal_op;
7442: if (s->cc_op != CC_OP_DYNAMIC) {
7443: gen_op_set_cc_op(s->cc_op);
7444: s->cc_op = CC_OP_DYNAMIC;
7445: }
7446: gen_jmp_im(s->pc - s->cs_base);
1.1.1.7 ! root 7447: gen_helper_rsm();
1.1.1.5 root 7448: gen_eob(s);
7449: break;
1.1.1.7 ! root 7450: case 0x1b8: /* SSE4.2 popcnt */
! 7451: if ((prefixes & (PREFIX_REPZ | PREFIX_LOCK | PREFIX_REPNZ)) !=
! 7452: PREFIX_REPZ)
! 7453: goto illegal_op;
! 7454: if (!(s->cpuid_ext_features & CPUID_EXT_POPCNT))
! 7455: goto illegal_op;
! 7456:
! 7457: modrm = ldub_code(s->pc++);
! 7458: reg = ((modrm >> 3) & 7);
! 7459:
! 7460: if (s->prefix & PREFIX_DATA)
! 7461: ot = OT_WORD;
! 7462: else if (s->dflag != 2)
! 7463: ot = OT_LONG;
! 7464: else
! 7465: ot = OT_QUAD;
! 7466:
! 7467: gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
! 7468: gen_helper_popcnt(cpu_T[0], cpu_T[0], tcg_const_i32(ot));
! 7469: gen_op_mov_reg_T0(ot, reg);
! 7470:
! 7471: s->cc_op = CC_OP_EFLAGS;
! 7472: break;
! 7473: case 0x10e ... 0x10f:
! 7474: /* 3DNow! instructions, ignore prefixes */
! 7475: s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA);
1.1 root 7476: case 0x110 ... 0x117:
7477: case 0x128 ... 0x12f:
1.1.1.7 ! root 7478: case 0x138 ... 0x13a:
1.1 root 7479: case 0x150 ... 0x177:
7480: case 0x17c ... 0x17f:
7481: case 0x1c2:
7482: case 0x1c4 ... 0x1c6:
7483: case 0x1d0 ... 0x1fe:
7484: gen_sse(s, b, pc_start, rex_r);
7485: break;
7486: default:
7487: goto illegal_op;
7488: }
7489: /* lock generation */
7490: if (s->prefix & PREFIX_LOCK)
1.1.1.7 ! root 7491: gen_helper_unlock();
1.1 root 7492: return s->pc;
7493: illegal_op:
7494: if (s->prefix & PREFIX_LOCK)
1.1.1.7 ! root 7495: gen_helper_unlock();
1.1 root 7496: /* XXX: ensure that no lock was generated */
7497: gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
7498: return s->pc;
7499: }
7500:
7501: void optimize_flags_init(void)
7502: {
1.1.1.7 ! root 7503: #if TCG_TARGET_REG_BITS == 32
! 7504: assert(sizeof(CCTable) == (1 << 3));
! 7505: #else
! 7506: assert(sizeof(CCTable) == (1 << 4));
! 7507: #endif
! 7508: cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
! 7509: cpu_cc_op = tcg_global_mem_new_i32(TCG_AREG0,
! 7510: offsetof(CPUState, cc_op), "cc_op");
! 7511: cpu_cc_src = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_src),
! 7512: "cc_src");
! 7513: cpu_cc_dst = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_dst),
! 7514: "cc_dst");
! 7515: cpu_cc_tmp = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, cc_tmp),
! 7516: "cc_tmp");
! 7517:
! 7518: /* register helpers */
! 7519: #define GEN_HELPER 2
! 7520: #include "helper.h"
1.1 root 7521: }
7522:
7523: /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
7524: basic block 'tb'. If search_pc is TRUE, also generate PC
7525: information for each intermediate instruction. */
1.1.1.7 ! root 7526: static inline void gen_intermediate_code_internal(CPUState *env,
! 7527: TranslationBlock *tb,
! 7528: int search_pc)
1.1 root 7529: {
7530: DisasContext dc1, *dc = &dc1;
7531: target_ulong pc_ptr;
7532: uint16_t *gen_opc_end;
1.1.1.7 ! root 7533: CPUBreakpoint *bp;
1.1.1.6 root 7534: int j, lj, cflags;
7535: uint64_t flags;
1.1 root 7536: target_ulong pc_start;
7537: target_ulong cs_base;
1.1.1.7 ! root 7538: int num_insns;
! 7539: int max_insns;
1.1.1.6 root 7540:
1.1 root 7541: /* generate intermediate code */
7542: pc_start = tb->pc;
7543: cs_base = tb->cs_base;
7544: flags = tb->flags;
7545: cflags = tb->cflags;
7546:
7547: dc->pe = (flags >> HF_PE_SHIFT) & 1;
7548: dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
7549: dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
7550: dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
7551: dc->f_st = 0;
7552: dc->vm86 = (flags >> VM_SHIFT) & 1;
7553: dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
7554: dc->iopl = (flags >> IOPL_SHIFT) & 3;
7555: dc->tf = (flags >> TF_SHIFT) & 1;
7556: dc->singlestep_enabled = env->singlestep_enabled;
7557: dc->cc_op = CC_OP_DYNAMIC;
7558: dc->cs_base = cs_base;
7559: dc->tb = tb;
7560: dc->popl_esp_hack = 0;
7561: /* select memory access functions */
7562: dc->mem_index = 0;
7563: if (flags & HF_SOFTMMU_MASK) {
7564: if (dc->cpl == 3)
7565: dc->mem_index = 2 * 4;
7566: else
7567: dc->mem_index = 1 * 4;
7568: }
7569: dc->cpuid_features = env->cpuid_features;
1.1.1.4 root 7570: dc->cpuid_ext_features = env->cpuid_ext_features;
1.1.1.7 ! root 7571: dc->cpuid_ext2_features = env->cpuid_ext2_features;
! 7572: dc->cpuid_ext3_features = env->cpuid_ext3_features;
1.1 root 7573: #ifdef TARGET_X86_64
7574: dc->lma = (flags >> HF_LMA_SHIFT) & 1;
7575: dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
7576: #endif
7577: dc->flags = flags;
7578: dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
7579: (flags & HF_INHIBIT_IRQ_MASK)
7580: #ifndef CONFIG_SOFTMMU
7581: || (flags & HF_SOFTMMU_MASK)
7582: #endif
7583: );
7584: #if 0
7585: /* check addseg logic */
7586: if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
7587: printf("ERROR addseg\n");
7588: #endif
7589:
1.1.1.7 ! root 7590: cpu_T[0] = tcg_temp_new();
! 7591: cpu_T[1] = tcg_temp_new();
! 7592: cpu_A0 = tcg_temp_new();
! 7593: cpu_T3 = tcg_temp_new();
! 7594:
! 7595: cpu_tmp0 = tcg_temp_new();
! 7596: cpu_tmp1_i64 = tcg_temp_new_i64();
! 7597: cpu_tmp2_i32 = tcg_temp_new_i32();
! 7598: cpu_tmp3_i32 = tcg_temp_new_i32();
! 7599: cpu_tmp4 = tcg_temp_new();
! 7600: cpu_tmp5 = tcg_temp_new();
! 7601: cpu_tmp6 = tcg_temp_new();
! 7602: cpu_ptr0 = tcg_temp_new_ptr();
! 7603: cpu_ptr1 = tcg_temp_new_ptr();
! 7604:
1.1 root 7605: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
7606:
7607: dc->is_jmp = DISAS_NEXT;
7608: pc_ptr = pc_start;
7609: lj = -1;
1.1.1.7 ! root 7610: num_insns = 0;
! 7611: max_insns = tb->cflags & CF_COUNT_MASK;
! 7612: if (max_insns == 0)
! 7613: max_insns = CF_COUNT_MASK;
1.1 root 7614:
1.1.1.7 ! root 7615: gen_icount_start();
1.1 root 7616: for(;;) {
1.1.1.7 ! root 7617: if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
! 7618: TAILQ_FOREACH(bp, &env->breakpoints, entry) {
! 7619: if (bp->pc == pc_ptr) {
1.1 root 7620: gen_debug(dc, pc_ptr - dc->cs_base);
7621: break;
7622: }
7623: }
7624: }
7625: if (search_pc) {
7626: j = gen_opc_ptr - gen_opc_buf;
7627: if (lj < j) {
7628: lj++;
7629: while (lj < j)
7630: gen_opc_instr_start[lj++] = 0;
7631: }
7632: gen_opc_pc[lj] = pc_ptr;
7633: gen_opc_cc_op[lj] = dc->cc_op;
7634: gen_opc_instr_start[lj] = 1;
1.1.1.7 ! root 7635: gen_opc_icount[lj] = num_insns;
1.1 root 7636: }
1.1.1.7 ! root 7637: if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
! 7638: gen_io_start();
! 7639:
1.1 root 7640: pc_ptr = disas_insn(dc, pc_ptr);
1.1.1.7 ! root 7641: num_insns++;
1.1 root 7642: /* stop translation if indicated */
7643: if (dc->is_jmp)
7644: break;
7645: /* if single step mode, we generate only one instruction and
7646: generate an exception */
7647: /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
7648: the flag and abort the translation to give the irqs a
7649: change to be happen */
1.1.1.6 root 7650: if (dc->tf || dc->singlestep_enabled ||
1.1.1.7 ! root 7651: (flags & HF_INHIBIT_IRQ_MASK)) {
1.1 root 7652: gen_jmp_im(pc_ptr - dc->cs_base);
7653: gen_eob(dc);
7654: break;
7655: }
7656: /* if too long translation, stop generation too */
7657: if (gen_opc_ptr >= gen_opc_end ||
1.1.1.7 ! root 7658: (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32) ||
! 7659: num_insns >= max_insns) {
1.1 root 7660: gen_jmp_im(pc_ptr - dc->cs_base);
7661: gen_eob(dc);
7662: break;
7663: }
7664: }
1.1.1.7 ! root 7665: if (tb->cflags & CF_LAST_IO)
! 7666: gen_io_end();
! 7667: gen_icount_end(tb, num_insns);
1.1 root 7668: *gen_opc_ptr = INDEX_op_end;
7669: /* we don't forget to fill the last values */
7670: if (search_pc) {
7671: j = gen_opc_ptr - gen_opc_buf;
7672: lj++;
7673: while (lj <= j)
7674: gen_opc_instr_start[lj++] = 0;
7675: }
1.1.1.6 root 7676:
1.1 root 7677: #ifdef DEBUG_DISAS
1.1.1.7 ! root 7678: log_cpu_state_mask(CPU_LOG_TB_CPU, env, X86_DUMP_CCOP);
! 7679: if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
1.1 root 7680: int disas_flags;
1.1.1.7 ! root 7681: qemu_log("----------------\n");
! 7682: qemu_log("IN: %s\n", lookup_symbol(pc_start));
1.1 root 7683: #ifdef TARGET_X86_64
7684: if (dc->code64)
7685: disas_flags = 2;
7686: else
7687: #endif
7688: disas_flags = !dc->code32;
1.1.1.7 ! root 7689: log_target_disas(pc_start, pc_ptr - pc_start, disas_flags);
! 7690: qemu_log("\n");
1.1 root 7691: }
7692: #endif
7693:
1.1.1.7 ! root 7694: if (!search_pc) {
1.1 root 7695: tb->size = pc_ptr - pc_start;
1.1.1.7 ! root 7696: tb->icount = num_insns;
! 7697: }
1.1 root 7698: }
7699:
1.1.1.7 ! root 7700: void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
1.1 root 7701: {
1.1.1.7 ! root 7702: gen_intermediate_code_internal(env, tb, 0);
1.1 root 7703: }
7704:
1.1.1.7 ! root 7705: void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
1.1 root 7706: {
1.1.1.7 ! root 7707: gen_intermediate_code_internal(env, tb, 1);
1.1 root 7708: }
7709:
1.1.1.7 ! root 7710: void gen_pc_load(CPUState *env, TranslationBlock *tb,
! 7711: unsigned long searched_pc, int pc_pos, void *puc)
! 7712: {
! 7713: int cc_op;
! 7714: #ifdef DEBUG_DISAS
! 7715: if (qemu_loglevel_mask(CPU_LOG_TB_OP)) {
! 7716: int i;
! 7717: qemu_log("RESTORE:\n");
! 7718: for(i = 0;i <= pc_pos; i++) {
! 7719: if (gen_opc_instr_start[i]) {
! 7720: qemu_log("0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
! 7721: }
! 7722: }
! 7723: qemu_log("spc=0x%08lx pc_pos=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
! 7724: searched_pc, pc_pos, gen_opc_pc[pc_pos] - tb->cs_base,
! 7725: (uint32_t)tb->cs_base);
! 7726: }
! 7727: #endif
! 7728: env->eip = gen_opc_pc[pc_pos] - tb->cs_base;
! 7729: cc_op = gen_opc_cc_op[pc_pos];
! 7730: if (cc_op != CC_OP_DYNAMIC)
! 7731: env->cc_op = cc_op;
! 7732: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.