summaryrefslogtreecommitdiff
path: root/translate-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-01 17:13:26 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-01 17:13:26 +0000
commit367e86e8476d6373a00d0e56a29b03c4b8f3e2ee (patch)
tree3cfad136fffefb2c5d8635b3b82fe4a587b4f1f4 /translate-i386.c
parent7bfdb6d18c7bb5792c896a0bf6cf1ad7431630cb (diff)
downloadqemu-367e86e8476d6373a00d0e56a29b03c4b8f3e2ee.tar.gz
new x86 CPU core
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@14 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r--translate-i386.c2133
1 files changed, 2133 insertions, 0 deletions
diff --git a/translate-i386.c b/translate-i386.c
new file mode 100644
index 0000000000..0c1b95a923
--- /dev/null
+++ b/translate-i386.c
@@ -0,0 +1,2133 @@
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include "cpu-i386.h"
+
+static uint8_t *gen_code_ptr;
+int __op_param1, __op_param2, __op_param3;
+
+/* supress that */
+static void error(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+#define PREFIX_REPZ 1
+#define PREFIX_REPNZ 2
+#define PREFIX_LOCK 4
+#define PREFIX_CS 8
+#define PREFIX_SS 0x10
+#define PREFIX_DS 0x20
+#define PREFIX_ES 0x40
+#define PREFIX_FS 0x80
+#define PREFIX_GS 0x100
+#define PREFIX_DATA 0x200
+#define PREFIX_ADR 0x400
+#define PREFIX_FWAIT 0x800
+
+typedef struct DisasContext {
+ /* current insn context */
+ int prefix;
+ int aflag, dflag;
+ uint8_t *pc; /* current pc */
+ uint8_t *runtime_pc; /* current pc in the runtime generated code */
+ int cc_op; /* current CC operation */
+ int f_st;
+} DisasContext;
+
+/* i386 arith/logic operations */
+enum {
+ OP_ADDL,
+ OP_ORL,
+ OP_ADCL,
+ OP_SBBL,
+ OP_ANDL,
+ OP_SUBL,
+ OP_XORL,
+ OP_CMPL,
+};
+
+/* i386 shift ops */
+enum {
+ OP_ROL,
+ OP_ROR,
+ OP_RCL,
+ OP_RCR,
+ OP_SHL,
+ OP_SHR,
+ OP_SHL1, /* undocumented */
+ OP_SAR = 7,
+};
+
+
+static const int fp_ops[8] = {
+#if 0
+ OP_FADDQ, OP_FMULQ, OP_CMP, OP_CMP,
+ OP_FSUBQ, OP_FSUBQ, OP_FDIVQ, OP_FDIVQ
+#endif
+};
+
+extern char cc_table, rclw_table, rclb_table;
+extern char helper_rcll_T0_T1_cc;
+extern char __udivdi3, __umoddi3;
+
+#include "op-i386.h"
+
+/* operand size */
+enum {
+ OT_BYTE = 0,
+ OT_WORD,
+ OT_LONG,
+ OT_QUAD,
+};
+
+enum {
+ /* I386 int registers */
+ OR_EAX, /* MUST be even numbered */
+ OR_ECX,
+ OR_EDX,
+ OR_EBX,
+ OR_ESP,
+ OR_EBP,
+ OR_ESI,
+ OR_EDI,
+
+ /* I386 float registers */
+ OR_ST0,
+ OR_ST1,
+ OR_ST2,
+ OR_ST3,
+ OR_ST4,
+ OR_ST5,
+ OR_ST6,
+ OR_ST7,
+ OR_TMP0, /* temporary operand register */
+ OR_TMP1,
+ OR_A0, /* temporary register used when doing address evaluation */
+ OR_EFLAGS, /* cpu flags */
+ OR_ITMP0, /* used for byte/word insertion */
+ OR_ITMP1, /* used for byte/word insertion */
+ OR_ITMP2, /* used for byte/word insertion */
+ OR_FTMP0, /* float temporary */
+ OR_DF, /* D flag, for string ops */
+ OR_ZERO, /* fixed zero register */
+ OR_IM, /* dummy immediate value register */
+ NB_OREGS,
+};
+
+#if 0
+static const double tab_const[7] = {
+ 1.0,
+ 3.32192809488736234789, /* log2(10) */
+ M_LOG2E,
+ M_PI,
+ 0.30102999566398119521, /* log10(2) */
+ M_LN2,
+ 0.0
+};
+#endif
+
+typedef void (GenOpFunc)(void);
+typedef void (GenOpFunc1)(long);
+typedef void (GenOpFunc2)(long, long);
+
+static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
+ [OT_BYTE] = {
+ gen_op_movb_EAX_T0,
+ gen_op_movb_ECX_T0,
+ gen_op_movb_EDX_T0,
+ gen_op_movb_EBX_T0,
+ gen_op_movh_EAX_T0,
+ gen_op_movh_ECX_T0,
+ gen_op_movh_EDX_T0,
+ gen_op_movh_EBX_T0,
+ },
+ [OT_WORD] = {
+ gen_op_movw_EAX_T0,
+ gen_op_movw_ECX_T0,
+ gen_op_movw_EDX_T0,
+ gen_op_movw_EBX_T0,
+ gen_op_movw_ESP_T0,
+ gen_op_movw_EBP_T0,
+ gen_op_movw_ESI_T0,
+ gen_op_movw_EDI_T0,
+ },
+ [OT_LONG] = {
+ gen_op_movl_EAX_T0,
+ gen_op_movl_ECX_T0,
+ gen_op_movl_EDX_T0,
+ gen_op_movl_EBX_T0,
+ gen_op_movl_ESP_T0,
+ gen_op_movl_EBP_T0,
+ gen_op_movl_ESI_T0,
+ gen_op_movl_EDI_T0,
+ },
+};
+
+static GenOpFunc *gen_op_mov_reg_T1[3][8] = {
+ [OT_BYTE] = {
+ gen_op_movb_EAX_T1,
+ gen_op_movb_ECX_T1,
+ gen_op_movb_EDX_T1,
+ gen_op_movb_EBX_T1,
+ gen_op_movh_EAX_T1,
+ gen_op_movh_ECX_T1,
+ gen_op_movh_EDX_T1,
+ gen_op_movh_EBX_T1,
+ },
+ [OT_WORD] = {
+ gen_op_movw_EAX_T1,
+ gen_op_movw_ECX_T1,
+ gen_op_movw_EDX_T1,
+ gen_op_movw_EBX_T1,
+ gen_op_movw_ESP_T1,
+ gen_op_movw_EBP_T1,
+ gen_op_movw_ESI_T1,
+ gen_op_movw_EDI_T1,
+ },
+ [OT_LONG] = {
+ gen_op_movl_EAX_T1,
+ gen_op_movl_ECX_T1,
+ gen_op_movl_EDX_T1,
+ gen_op_movl_EBX_T1,
+ gen_op_movl_ESP_T1,
+ gen_op_movl_EBP_T1,
+ gen_op_movl_ESI_T1,
+ gen_op_movl_EDI_T1,
+ },
+};
+
+static GenOpFunc *gen_op_mov_reg_A0[2][8] = {
+ [0] = {
+ gen_op_movw_EAX_A0,
+ gen_op_movw_ECX_A0,
+ gen_op_movw_EDX_A0,
+ gen_op_movw_EBX_A0,
+ gen_op_movw_ESP_A0,
+ gen_op_movw_EBP_A0,
+ gen_op_movw_ESI_A0,
+ gen_op_movw_EDI_A0,
+ },
+ [1] = {
+ gen_op_movl_EAX_A0,
+ gen_op_movl_ECX_A0,
+ gen_op_movl_EDX_A0,
+ gen_op_movl_EBX_A0,
+ gen_op_movl_ESP_A0,
+ gen_op_movl_EBP_A0,
+ gen_op_movl_ESI_A0,
+ gen_op_movl_EDI_A0,
+ },
+};
+
+static GenOpFunc *gen_op_mov_TN_reg[3][2][8] =
+{
+ [OT_BYTE] = {
+ {
+ gen_op_movl_T0_EAX,
+ gen_op_movl_T0_ECX,
+ gen_op_movl_T0_EDX,
+ gen_op_movl_T0_EBX,
+ gen_op_movh_T0_EAX,
+ gen_op_movh_T0_ECX,
+ gen_op_movh_T0_EDX,
+ gen_op_movh_T0_EBX,
+ },
+ {
+ gen_op_movl_T1_EAX,
+ gen_op_movl_T1_ECX,
+ gen_op_movl_T1_EDX,
+ gen_op_movl_T1_EBX,
+ gen_op_movh_T1_EAX,
+ gen_op_movh_T1_ECX,
+ gen_op_movh_T1_EDX,
+ gen_op_movh_T1_EBX,
+ },
+ },
+ [OT_WORD] = {
+ {
+ gen_op_movl_T0_EAX,
+ gen_op_movl_T0_ECX,
+ gen_op_movl_T0_EDX,
+ gen_op_movl_T0_EBX,
+ gen_op_movl_T0_ESP,
+ gen_op_movl_T0_EBP,
+ gen_op_movl_T0_ESI,
+ gen_op_movl_T0_EDI,
+ },
+ {
+ gen_op_movl_T1_EAX,
+ gen_op_movl_T1_ECX,
+ gen_op_movl_T1_EDX,
+ gen_op_movl_T1_EBX,
+ gen_op_movl_T1_ESP,
+ gen_op_movl_T1_EBP,
+ gen_op_movl_T1_ESI,
+ gen_op_movl_T1_EDI,
+ },
+ },
+ [OT_LONG] = {
+ {
+ gen_op_movl_T0_EAX,
+ gen_op_movl_T0_ECX,
+ gen_op_movl_T0_EDX,
+ gen_op_movl_T0_EBX,
+ gen_op_movl_T0_ESP,
+ gen_op_movl_T0_EBP,
+ gen_op_movl_T0_ESI,
+ gen_op_movl_T0_EDI,
+ },
+ {
+ gen_op_movl_T1_EAX,
+ gen_op_movl_T1_ECX,
+ gen_op_movl_T1_EDX,
+ gen_op_movl_T1_EBX,
+ gen_op_movl_T1_ESP,
+ gen_op_movl_T1_EBP,
+ gen_op_movl_T1_ESI,
+ gen_op_movl_T1_EDI,
+ },
+ },
+};
+
+static GenOpFunc *gen_op_movl_A0_reg[8] = {
+ gen_op_movl_A0_EAX,
+ gen_op_movl_A0_ECX,
+ gen_op_movl_A0_EDX,
+ gen_op_movl_A0_EBX,
+ gen_op_movl_A0_ESP,
+ gen_op_movl_A0_EBP,
+ gen_op_movl_A0_ESI,
+ gen_op_movl_A0_EDI,
+};
+
+static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = {
+ [0] = {
+ gen_op_addl_A0_EAX,
+ gen_op_addl_A0_ECX,
+ gen_op_addl_A0_EDX,
+ gen_op_addl_A0_EBX,
+ gen_op_addl_A0_ESP,
+ gen_op_addl_A0_EBP,
+ gen_op_addl_A0_ESI,
+ gen_op_addl_A0_EDI,
+ },
+ [1] = {
+ gen_op_addl_A0_EAX_s1,
+ gen_op_addl_A0_ECX_s1,
+ gen_op_addl_A0_EDX_s1,
+ gen_op_addl_A0_EBX_s1,
+ gen_op_addl_A0_ESP_s1,
+ gen_op_addl_A0_EBP_s1,
+ gen_op_addl_A0_ESI_s1,
+ gen_op_addl_A0_EDI_s1,
+ },
+ [2] = {
+ gen_op_addl_A0_EAX_s2,
+ gen_op_addl_A0_ECX_s2,
+ gen_op_addl_A0_EDX_s2,
+ gen_op_addl_A0_EBX_s2,
+ gen_op_addl_A0_ESP_s2,
+ gen_op_addl_A0_EBP_s2,
+ gen_op_addl_A0_ESI_s2,
+ gen_op_addl_A0_EDI_s2,
+ },
+ [3] = {
+ gen_op_addl_A0_EAX_s3,
+ gen_op_addl_A0_ECX_s3,
+ gen_op_addl_A0_EDX_s3,
+ gen_op_addl_A0_EBX_s3,
+ gen_op_addl_A0_ESP_s3,
+ gen_op_addl_A0_EBP_s3,
+ gen_op_addl_A0_ESI_s3,
+ gen_op_addl_A0_EDI_s3,
+ },
+};
+
+static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
+ gen_op_addl_T0_T1_cc,
+ gen_op_orl_T0_T1_cc,
+ gen_op_adcl_T0_T1_cc,
+ gen_op_sbbl_T0_T1_cc,
+ gen_op_andl_T0_T1_cc,
+ gen_op_subl_T0_T1_cc,
+ gen_op_xorl_T0_T1_cc,
+ gen_op_cmpl_T0_T1_cc,
+};
+
+static const int cc_op_arithb[8] = {
+ CC_OP_ADDB,
+ CC_OP_LOGICB,
+ CC_OP_ADDB,
+ CC_OP_SUBB,
+ CC_OP_LOGICB,
+ CC_OP_SUBB,
+ CC_OP_LOGICB,
+ CC_OP_SUBB,
+};
+
+static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
+ [OT_BYTE] = {
+ gen_op_rolb_T0_T1_cc,
+ gen_op_rorb_T0_T1_cc,
+ gen_op_rclb_T0_T1_cc,
+ gen_op_rcrb_T0_T1_cc,
+ gen_op_shlb_T0_T1_cc,
+ gen_op_shrb_T0_T1_cc,
+ gen_op_shlb_T0_T1_cc,
+ gen_op_sarb_T0_T1_cc,
+ },
+ [OT_WORD] = {
+ gen_op_rolw_T0_T1_cc,
+ gen_op_rorw_T0_T1_cc,
+ gen_op_rclw_T0_T1_cc,
+ gen_op_rcrw_T0_T1_cc,
+ gen_op_shlw_T0_T1_cc,
+ gen_op_shrw_T0_T1_cc,
+ gen_op_shlw_T0_T1_cc,
+ gen_op_sarw_T0_T1_cc,
+ },
+ [OT_LONG] = {
+ gen_op_roll_T0_T1_cc,
+ gen_op_rorl_T0_T1_cc,
+ gen_op_rcll_T0_T1_cc,
+ gen_op_rcrl_T0_T1_cc,
+ gen_op_shll_T0_T1_cc,
+ gen_op_shrl_T0_T1_cc,
+ gen_op_shll_T0_T1_cc,
+ gen_op_sarl_T0_T1_cc,
+ },
+};
+
+static GenOpFunc *gen_op_lds_T0_A0[3] = {
+ gen_op_ldsb_T0_A0,
+ gen_op_ldsw_T0_A0,
+};
+
+static GenOpFunc *gen_op_ldu_T0_A0[3] = {
+ gen_op_ldub_T0_A0,
+ gen_op_lduw_T0_A0,
+};
+
+/* sign does not matter */
+static GenOpFunc *gen_op_ld_T0_A0[3] = {
+ gen_op_ldub_T0_A0,
+ gen_op_lduw_T0_A0,
+ gen_op_ldl_T0_A0,
+};
+
+static GenOpFunc *gen_op_ld_T1_A0[3] = {
+ gen_op_ldub_T1_A0,
+ gen_op_lduw_T1_A0,
+ gen_op_ldl_T1_A0,
+};
+
+static GenOpFunc *gen_op_st_T0_A0[3] = {
+ gen_op_stb_T0_A0,
+ gen_op_stw_T0_A0,
+ gen_op_stl_T0_A0,
+};
+
+static GenOpFunc *gen_op_movs[6] = {
+ gen_op_movsb,
+ gen_op_movsw,
+ gen_op_movsl,
+ gen_op_rep_movsb,
+ gen_op_rep_movsw,
+ gen_op_rep_movsl,
+};
+
+static GenOpFunc *gen_op_stos[6] = {
+ gen_op_stosb,
+ gen_op_stosw,
+ gen_op_stosl,
+ gen_op_rep_stosb,
+ gen_op_rep_stosw,
+ gen_op_rep_stosl,
+};
+
+static GenOpFunc *gen_op_lods[6] = {
+ gen_op_lodsb,
+ gen_op_lodsw,
+ gen_op_lodsl,
+ gen_op_rep_lodsb,
+ gen_op_rep_lodsw,
+ gen_op_rep_lodsl,
+};
+
+static GenOpFunc *gen_op_scas[9] = {
+ gen_op_scasb,
+ gen_op_scasw,
+ gen_op_scasl,
+ gen_op_repz_scasb,
+ gen_op_repz_scasw,
+ gen_op_repz_scasl,
+ gen_op_repnz_scasb,
+ gen_op_repnz_scasw,
+ gen_op_repnz_scasl,
+};
+
+static GenOpFunc *gen_op_cmps[9] = {
+ gen_op_cmpsb,
+ gen_op_cmpsw,
+ gen_op_cmpsl,
+ gen_op_repz_cmpsb,
+ gen_op_repz_cmpsw,
+ gen_op_repz_cmpsl,
+ gen_op_repnz_cmpsb,
+ gen_op_repnz_cmpsw,
+ gen_op_repnz_cmpsl,
+};
+
+static GenOpFunc *gen_op_ins[6] = {
+ gen_op_insb,
+ gen_op_insw,
+ gen_op_insl,
+ gen_op_rep_insb,
+ gen_op_rep_insw,
+ gen_op_rep_insl,
+};
+
+
+static GenOpFunc *gen_op_outs[6] = {
+ gen_op_outsb,
+ gen_op_outsw,
+ gen_op_outsl,
+ gen_op_rep_outsb,
+ gen_op_rep_outsw,
+ gen_op_rep_outsl,
+};
+
+enum {
+ JCC_O,
+ JCC_B,
+ JCC_Z,
+ JCC_BE,
+ JCC_S,
+ JCC_P,
+ JCC_L,
+ JCC_LE,
+};
+
+static GenOpFunc2 *gen_jcc_slow[8] = {
+ gen_op_jo_cc,
+ gen_op_jb_cc,
+ gen_op_jz_cc,
+ gen_op_jbe_cc,
+ gen_op_js_cc,
+ gen_op_jp_cc,
+ gen_op_jl_cc,
+ gen_op_jle_cc,
+};
+
+static GenOpFunc2 *gen_jcc_sub[3][8] = {
+ [OT_BYTE] = {
+ NULL,
+ gen_op_jb_subb,
+ gen_op_jz_subb,
+ gen_op_jbe_subb,
+ gen_op_js_subb,
+ NULL,
+ gen_op_jl_subb,
+ gen_op_jle_subb,
+ },
+ [OT_WORD] = {
+ NULL,
+ gen_op_jb_subw,
+ gen_op_jz_subw,
+ gen_op_jbe_subw,
+ gen_op_js_subw,
+ NULL,
+ gen_op_jl_subw,
+ gen_op_jle_subw,
+ },
+ [OT_LONG] = {
+ NULL,
+ gen_op_jb_subl,
+ gen_op_jz_subl,
+ gen_op_jbe_subl,
+ gen_op_js_subl,
+ NULL,
+ gen_op_jl_subl,
+ gen_op_jle_subl,
+ },
+};
+
+static GenOpFunc *gen_setcc_slow[8] = {
+ gen_op_seto_T0_cc,
+ gen_op_setb_T0_cc,
+ gen_op_setz_T0_cc,
+ gen_op_setbe_T0_cc,
+ gen_op_sets_T0_cc,
+ gen_op_setp_T0_cc,
+ gen_op_setl_T0_cc,
+ gen_op_setle_T0_cc,
+};
+
+static GenOpFunc *gen_setcc_sub[3][8] = {
+ [OT_BYTE] = {
+ NULL,
+ gen_op_setb_T0_subb,
+ gen_op_setz_T0_subb,
+ gen_op_setbe_T0_subb,
+ gen_op_sets_T0_subb,
+ NULL,
+ gen_op_setl_T0_subb,
+ gen_op_setle_T0_subb,
+ },
+ [OT_WORD] = {
+ NULL,
+ gen_op_setb_T0_subw,
+ gen_op_setz_T0_subw,
+ gen_op_setbe_T0_subw,
+ gen_op_sets_T0_subw,
+ NULL,
+ gen_op_setl_T0_subw,
+ gen_op_setle_T0_subw,
+ },
+ [OT_LONG] = {
+ NULL,
+ gen_op_setb_T0_subl,
+ gen_op_setz_T0_subl,
+ gen_op_setbe_T0_subl,
+ gen_op_sets_T0_subl,
+ NULL,
+ gen_op_setl_T0_subl,
+ gen_op_setle_T0_subl,
+ },
+};
+
+static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
+{
+ if (d != OR_TMP0)
+ gen_op_mov_TN_reg[ot][0][d]();
+ if (s != OR_TMP1)
+ gen_op_mov_TN_reg[ot][1][s]();
+ if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s1->cc_op);
+ gen_op_arith_T0_T1_cc[op]();
+ if (d != OR_TMP0 && op != OP_CMPL)
+ gen_op_mov_reg_T0[ot][d]();
+ s1->cc_op = cc_op_arithb[op] + ot;
+}
+
+static void gen_opi(DisasContext *s1, int op, int ot, int d, int c)
+{
+ gen_op1_movl_T1_im(c);
+ gen_op(s1, op, ot, d, OR_TMP0);
+}
+
+static void gen_inc(DisasContext *s1, int ot, int d, int c)
+{
+ if (d != OR_TMP0)
+ gen_op_mov_TN_reg[ot][0][d]();
+ if (s1->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s1->cc_op);
+ if (c > 0)
+ gen_op_incl_T0_cc();
+ else
+ gen_op_decl_T0_cc();
+ if (d != OR_TMP0)
+ gen_op_mov_reg_T0[ot][d]();
+}
+
+static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
+{
+ if (d != OR_TMP0)
+ gen_op_mov_TN_reg[ot][0][d]();
+ if (s != OR_TMP1)
+ gen_op_mov_TN_reg[ot][1][s]();
+ switch(op) {
+ case OP_ROL:
+ case OP_ROR:
+ case OP_RCL:
+ case OP_RCR:
+ /* only C and O are modified, so we must update flags dynamically */
+ if (s1->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s1->cc_op);
+ gen_op_shift_T0_T1_cc[ot][op]();
+ break;
+ default:
+ gen_op_shift_T0_T1_cc[ot][op]();
+ break;
+ }
+ if (d != OR_TMP0)
+ gen_op_mov_reg_T0[ot][d]();
+ s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
+}
+
+static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
+{
+ /* currently not optimized */
+ gen_op1_movl_T1_im(c);
+ gen_shift(s1, op, ot, d, OR_TMP1);
+}
+
+static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
+{
+ int havesib;
+ int havebase;
+ int base, disp;
+ int index = 0;
+ int scale = 0;
+ int reg1, reg2, opreg;
+ int mod, rm, code;
+
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+
+ if (s->aflag) {
+
+ havesib = 0;
+ havebase = 1;
+ base = rm;
+
+ if (base == 4) {
+ havesib = 1;
+ code = ldub(s->pc++);
+ scale = (code >> 6) & 3;
+ index = (code >> 3) & 7;
+ base = code & 7;
+ }
+
+ switch (mod) {
+ case 0:
+ if (base == 5) {
+ havebase = 0;
+ disp = ldl(s->pc);
+ s->pc += 4;
+ } else {
+ disp = 0;
+ }
+ break;
+ case 1:
+ disp = (int8_t)ldub(s->pc++);
+ break;
+ default:
+ case 2:
+ disp = ldl(s->pc);
+ s->pc += 4;
+ break;
+ }
+
+ reg1 = OR_ZERO;
+ reg2 = OR_ZERO;
+
+ if (havebase || (havesib && (index != 4 || scale != 0))) {
+ if (havebase)
+ reg1 = OR_EAX + base;
+ if (havesib && index != 4) {
+ if (havebase)
+ reg2 = index + OR_EAX;
+ else
+ reg1 = index + OR_EAX;
+ }
+ }
+ /* XXX: disp only ? */
+ if (reg2 == OR_ZERO) {
+ /* op: disp + (reg1 << scale) */
+ if (reg1 == OR_ZERO) {
+ gen_op1_movl_A0_im(disp);
+ } else if (scale == 0 && disp == 0) {
+ gen_op_movl_A0_reg[reg1]();
+ } else {
+ gen_op_addl_A0_reg_sN[scale][reg1]();
+ }
+ } else {
+ /* op: disp + reg1 + (reg2 << scale) */
+ if (disp != 0) {
+ gen_op1_movl_A0_im(disp);
+ gen_op_addl_A0_reg_sN[0][reg1]();
+ } else {
+ gen_op_movl_A0_reg[reg1]();
+ }
+ gen_op_addl_A0_reg_sN[scale][reg2]();
+ }
+ opreg = OR_A0;
+ } else {
+ fprintf(stderr, "16 bit addressing not supported\n");
+ disp = 0;
+ opreg = 0;
+ }
+ *reg_ptr = opreg;
+ *offset_ptr = disp;
+}
+
+/* generate modrm memory load or store of 'reg'. TMP0 is used if reg !=
+ OR_TMP0 */
+static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
+{
+ int mod, rm, opreg, disp;
+
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ if (mod == 3) {
+ if (is_store) {
+ if (reg != OR_TMP0)
+ gen_op_mov_TN_reg[ot][0][reg]();
+ gen_op_mov_reg_T0[ot][rm]();
+ } else {
+ gen_op_mov_TN_reg[ot][0][rm]();
+ if (reg != OR_TMP0)
+ gen_op_mov_reg_T0[ot][reg]();
+ }
+ } else {
+ gen_lea_modrm(s, modrm, &opreg, &disp);
+ if (is_store) {
+ if (reg != OR_TMP0)
+ gen_op_mov_TN_reg[ot][0][reg]();
+ gen_op_st_T0_A0[ot]();
+ } else {
+ gen_op_ld_T0_A0[ot]();
+ if (reg != OR_TMP0)
+ gen_op_mov_reg_T0[ot][reg]();
+ }
+ }
+}
+
+static inline uint32_t insn_get(DisasContext *s, int ot)
+{
+ uint32_t ret;
+
+ switch(ot) {
+ case OT_BYTE:
+ ret = ldub(s->pc);
+ s->pc++;
+ break;
+ case OT_WORD:
+ ret = lduw(s->pc);
+ s->pc += 2;
+ break;
+ default:
+ case OT_LONG:
+ ret = ldl(s->pc);
+ s->pc += 4;
+ break;
+ }
+ return ret;
+}
+
+static void gen_jcc(DisasContext *s, int b, int val)
+{
+ int inv, jcc_op;
+ GenOpFunc2 *func;
+
+ inv = b & 1;
+ jcc_op = (b >> 1) & 7;
+ switch(s->cc_op) {
+ /* we optimize the cmp/jcc case */
+ case CC_OP_SUBB:
+ case CC_OP_SUBW:
+ case CC_OP_SUBL:
+ func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
+ if (!func)
+ goto slow_jcc;
+ break;
+
+ /* some jumps are easy to compute */
+ case CC_OP_ADDB:
+ case CC_OP_ADDW:
+ case CC_OP_ADDL:
+ case CC_OP_LOGICB:
+ case CC_OP_LOGICW:
+ case CC_OP_LOGICL:
+ case CC_OP_INCB:
+ case CC_OP_INCW:
+ case CC_OP_INCL:
+ case CC_OP_DECB:
+ case CC_OP_DECW:
+ case CC_OP_DECL:
+ case CC_OP_SHLB:
+ case CC_OP_SHLW:
+ case CC_OP_SHLL:
+ switch(jcc_op) {
+ case JCC_Z:
+ func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
+ break;
+ case JCC_S:
+ func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
+ break;
+ default:
+ goto slow_jcc;
+ }
+ break;
+ default:
+ slow_jcc:
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ func = gen_jcc_slow[jcc_op];
+ break;
+ }
+ if (!inv) {
+ func(val, (long)s->pc);
+ } else {
+ func((long)s->pc, val);
+ }
+}
+
+static void gen_setcc(DisasContext *s, int b)
+{
+ int inv, jcc_op;
+ GenOpFunc *func;
+
+ inv = b & 1;
+ jcc_op = (b >> 1) & 7;
+ switch(s->cc_op) {
+ /* we optimize the cmp/jcc case */
+ case CC_OP_SUBB:
+ case CC_OP_SUBW:
+ case CC_OP_SUBL:
+ func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
+ if (!func)
+ goto slow_jcc;
+ break;
+
+ /* some jumps are easy to compute */
+ case CC_OP_ADDB:
+ case CC_OP_ADDW:
+ case CC_OP_ADDL:
+ case CC_OP_LOGICB:
+ case CC_OP_LOGICW:
+ case CC_OP_LOGICL:
+ case CC_OP_INCB:
+ case CC_OP_INCW:
+ case CC_OP_INCL:
+ case CC_OP_DECB:
+ case CC_OP_DECW:
+ case CC_OP_DECL:
+ case CC_OP_SHLB:
+ case CC_OP_SHLW:
+ case CC_OP_SHLL:
+ switch(jcc_op) {
+ case JCC_Z:
+ func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op];
+ break;
+ case JCC_S:
+ func = gen_setcc_sub[s->cc_op - CC_OP_ADDB][jcc_op];
+ break;
+ default:
+ goto slow_jcc;
+ }
+ break;
+ default:
+ slow_jcc:
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ func = gen_setcc_slow[jcc_op];
+ break;
+ }
+ func();
+ if (inv) {
+ gen_op_xor_T0_1();
+ }
+}
+
+/* return the size of the intruction. Return -1 if no insn found */
+int disas_insn(DisasContext *s, uint8_t *pc_start)
+{
+ int b, prefixes, aflag, dflag;
+ int shift, ot;
+ int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
+
+ s->pc = pc_start;
+ prefixes = 0;
+ aflag = 1;
+ dflag = 1;
+ // cur_pc = s->pc; /* for insn generation */
+ next_byte:
+ b = ldub(s->pc);
+ if (b < 0)
+ return -1;
+ s->pc++;
+ /* check prefixes */
+ switch (b) {
+ case 0xf3:
+ prefixes |= PREFIX_REPZ;
+ goto next_byte;
+ case 0xf2:
+ prefixes |= PREFIX_REPNZ;
+ goto next_byte;
+ case 0xf0:
+ prefixes |= PREFIX_LOCK;
+ goto next_byte;
+ case 0x2e:
+ prefixes |= PREFIX_CS;
+ goto next_byte;
+ case 0x36:
+ prefixes |= PREFIX_SS;
+ goto next_byte;
+ case 0x3e:
+ prefixes |= PREFIX_DS;
+ goto next_byte;
+ case 0x26:
+ prefixes |= PREFIX_ES;
+ goto next_byte;
+ case 0x64:
+ prefixes |= PREFIX_FS;
+ goto next_byte;
+ case 0x65:
+ prefixes |= PREFIX_GS;
+ goto next_byte;
+ case 0x66:
+ prefixes |= PREFIX_DATA;
+ goto next_byte;
+ case 0x67:
+ prefixes |= PREFIX_ADR;
+ goto next_byte;
+ case 0x9b:
+ prefixes |= PREFIX_FWAIT;
+ goto next_byte;
+ }
+
+ if (prefixes & PREFIX_DATA)
+ dflag ^= 1;
+ if (prefixes & PREFIX_ADR)
+ aflag ^= 1;
+
+ s->prefix = prefixes;
+ s->aflag = aflag;
+ s->dflag = dflag;
+
+ /* now check op code */
+ reswitch:
+ switch(b) {
+ case 0x0f:
+ /**************************/
+ /* extended op code */
+ b = ldub(s->pc++) | 0x100;
+ goto reswitch;
+
+ /**************************/
+ /* arith & logic */
+ case 0x00 ... 0x05:
+ case 0x08 ... 0x0d:
+ case 0x10 ... 0x15:
+ case 0x18 ... 0x1d:
+ case 0x20 ... 0x25:
+ case 0x28 ... 0x2d:
+ case 0x30 ... 0x35:
+ case 0x38 ... 0x3d:
+ {
+ int op, f, val;
+ op = (b >> 3) & 7;
+ f = (b >> 1) & 3;
+
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ switch(f) {
+ case 0: /* OP Ev, Gv */
+ modrm = ldub(s->pc++);
+ reg = ((modrm >> 3) & 7) + OR_EAX;
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot]();
+ opreg = OR_TMP0;
+ } else {
+ opreg = OR_EAX + rm;
+ }
+ gen_op(s, op, ot, opreg, reg);
+ if (mod != 3 && op != 7) {
+ gen_op_st_T0_A0[ot]();
+ }
+ break;
+ case 1: /* OP Gv, Ev */
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ reg = ((modrm >> 3) & 7) + OR_EAX;
+ rm = modrm & 7;
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T1_A0[ot]();
+ opreg = OR_TMP1;
+ } else {
+ opreg = OR_EAX + rm;
+ }
+ gen_op(s, op, ot, reg, opreg);
+ break;
+ case 2: /* OP A, Iv */
+ val = insn_get(s, ot);
+ gen_opi(s, op, ot, OR_EAX, val);
+ break;
+ }
+ }
+ break;
+
+ case 0x80: /* GRP1 */
+ case 0x81:
+ case 0x83:
+ {
+ int val;
+
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ op = (modrm >> 3) & 7;
+
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot]();
+ opreg = OR_TMP0;
+ } else {
+ opreg = rm + OR_EAX;
+ }
+
+ switch(b) {
+ default:
+ case 0x80:
+ case 0x81:
+ val = insn_get(s, ot);
+ break;
+ case 0x83:
+ val = (int8_t)insn_get(s, OT_BYTE);
+ break;
+ }
+
+ gen_opi(s, op, ot, opreg, val);
+ if (op != 7 && mod != 3) {
+ gen_op_st_T0_A0[ot]();
+ }
+ }
+ break;
+
+ /**************************/
+ /* inc, dec, and other misc arith */
+ case 0x40 ... 0x47: /* inc Gv */
+ ot = dflag ? OT_LONG : OT_WORD;
+ gen_inc(s, ot, OR_EAX + (b & 7), 1);
+ break;
+ case 0x48 ... 0x4f: /* dec Gv */
+ ot = dflag ? OT_LONG : OT_WORD;
+ gen_inc(s, ot, OR_EAX + (b & 7), -1);
+ break;
+ case 0xf6: /* GRP3 */
+ case 0xf7:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ op = (modrm >> 3) & 7;
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot]();
+ } else {
+ gen_op_mov_TN_reg[ot][0][rm]();
+ }
+
+ switch(op) {
+ case 0: /* test */
+ val = insn_get(s, ot);
+ gen_op1_movl_T1_im(val);
+ gen_op_testl_T0_T1_cc();
+ s->cc_op = CC_OP_LOGICB + ot;
+ break;
+ case 2: /* not */
+ gen_op_notl_T0();
+ if (mod != 3) {
+ gen_op_st_T0_A0[ot]();
+ } else {
+ gen_op_mov_reg_T0[ot][rm]();
+ }
+ break;
+ case 3: /* neg */
+ gen_op_negl_T0_cc();
+ if (mod != 3) {
+ gen_op_st_T0_A0[ot]();
+ } else {
+ gen_op_mov_reg_T0[ot][rm]();
+ }
+ s->cc_op = CC_OP_SUBB + ot;
+ break;
+ case 4: /* mul */
+ switch(ot) {
+ case OT_BYTE:
+ gen_op_mulb_AL_T0();
+ break;
+ case OT_WORD:
+ gen_op_mulw_AX_T0();
+ break;
+ default:
+ case OT_LONG:
+ gen_op_mull_EAX_T0();
+ break;
+ }
+ break;
+ case 5: /* imul */
+ switch(ot) {
+ case OT_BYTE:
+ gen_op_imulb_AL_T0();
+ break;
+ case OT_WORD:
+ gen_op_imulw_AX_T0();
+ break;
+ default:
+ case OT_LONG:
+ gen_op_imull_EAX_T0();
+ break;
+ }
+ break;
+ case 6: /* div */
+ switch(ot) {
+ case OT_BYTE:
+ gen_op_divb_AL_T0();
+ break;
+ case OT_WORD:
+ gen_op_divw_AX_T0();
+ break;
+ default:
+ case OT_LONG:
+ gen_op_divl_EAX_T0();
+ break;
+ }
+ break;
+ case 7: /* idiv */
+ switch(ot) {
+ case OT_BYTE:
+ gen_op_idivb_AL_T0();
+ break;
+ case OT_WORD:
+ gen_op_idivw_AX_T0();
+ break;
+ default:
+ case OT_LONG:
+ gen_op_idivl_EAX_T0();
+ break;
+ }
+ break;
+ default:
+ error("GRP3: bad instruction");
+ return -1;
+ }
+ break;
+
+ case 0xfe: /* GRP4 */
+ case 0xff: /* GRP5 */
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ op = (modrm >> 3) & 7;
+ if (op >= 2 && b == 0xfe) {
+ error("GRP4: bad instruction");
+ return -1;
+ }
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot]();
+ } else {
+ gen_op_mov_TN_reg[ot][0][rm]();
+ }
+
+ switch(op) {
+ case 0: /* inc Ev */
+ gen_inc(s, ot, OR_TMP0, 1);
+ if (mod != 3)
+ gen_op_st_T0_A0[ot]();
+ break;
+ case 1: /* dec Ev */
+ gen_inc(s, ot, OR_TMP0, -1);
+ if (mod != 3)
+ gen_op_st_T0_A0[ot]();
+ break;
+ case 2: /* call Ev */
+ gen_op1_movl_T1_im((long)s->pc);
+ gen_op_pushl_T1();
+ gen_op_jmp_T0();
+ break;
+ case 4: /* jmp Ev */
+ gen_op_jmp_T0();
+ break;
+ case 6: /* push Ev */
+ gen_op_pushl_T0();
+ break;
+ default:
+ error("GRP5: bad instruction");
+ return -1;
+ }
+ break;
+
+ case 0x84: /* test Ev, Gv */
+ case 0x85:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ reg = (modrm >> 3) & 7;
+
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+ gen_op_mov_TN_reg[ot][1][reg + OR_EAX]();
+ gen_op_testl_T0_T1_cc();
+ s->cc_op = CC_OP_LOGICB + ot;
+ break;
+
+ case 0xa8: /* test eAX, Iv */
+ case 0xa9:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ val = insn_get(s, ot);
+
+ gen_op_mov_TN_reg[ot][0][OR_EAX]();
+ gen_op1_movl_T1_im(val);
+ gen_op_testl_T0_T1_cc();
+ s->cc_op = CC_OP_LOGICB + ot;
+ break;
+
+ case 0x98: /* CWDE/CBW */
+ if (dflag)
+ gen_op_movswl_EAX_AX();
+ else
+ gen_op_movsbw_AX_AL();
+ break;
+ case 0x99: /* CDQ/CWD */
+ if (dflag)
+ gen_op_movslq_EDX_EAX();
+ else
+ gen_op_movswl_DX_AX();
+ break;
+ case 0x1af: /* imul Gv, Ev */
+ case 0x69: /* imul Gv, Ev, I */
+ case 0x6b:
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = ((modrm >> 3) & 7) + OR_EAX;
+
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+ if (b == 0x69) {
+ val = insn_get(s, ot);
+ gen_op1_movl_T1_im(val);
+ } else if (b == 0x6b) {
+ val = insn_get(s, OT_BYTE);
+ gen_op1_movl_T1_im(val);
+ } else {
+ gen_op_mov_TN_reg[ot][1][reg]();
+ }
+
+ if (ot == OT_LONG) {
+ op_imull_T0_T1();
+ } else {
+ op_imulw_T0_T1();
+ }
+ gen_op_mov_reg_T0[ot][reg]();
+ break;
+
+ /**************************/
+ /* push/pop */
+ case 0x50 ... 0x57: /* push */
+ gen_op_mov_TN_reg[OT_LONG][0][(b & 7)]();
+ gen_op_pushl_T0();
+ break;
+ case 0x58 ... 0x5f: /* pop */
+ gen_op_popl_T0();
+ gen_op_mov_reg_T0[OT_LONG][reg]();
+ break;
+ case 0x68: /* push Iv */
+ case 0x6a:
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (b == 0x68)
+ val = insn_get(s, ot);
+ else
+ val = (int8_t)insn_get(s, OT_BYTE);
+ gen_op1_movl_T0_im(val);
+ gen_op_pushl_T0();
+ break;
+ case 0x8f: /* pop Ev */
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ gen_op_popl_T0();
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+ break;
+ case 0xc9: /* leave */
+ gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
+ gen_op_mov_reg_T0[OT_LONG][R_ESP]();
+ gen_op_popl_T0();
+ gen_op_mov_reg_T0[OT_LONG][R_EBP]();
+ break;
+ /**************************/
+ /* mov */
+ case 0x88:
+ case 0x89: /* mov Gv, Ev */
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+
+ /* generate a generic store */
+ gen_ldst_modrm(s, modrm, ot, OR_EAX + reg, 1);
+ break;
+ case 0xc6:
+ case 0xc7: /* mov Ev, Iv */
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+
+ val = insn_get(s, ot);
+ gen_op1_movl_T0_im(val);
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
+ break;
+ case 0x8a:
+ case 0x8b: /* mov Ev, Gv */
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+
+ gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+ gen_op_mov_reg_T0[ot][reg]();
+ break;
+
+ case 0x1b6: /* movzbS Gv, Eb */
+ case 0x1b7: /* movzwS Gv, Eb */
+ case 0x1be: /* movsbS Gv, Eb */
+ case 0x1bf: /* movswS Gv, Eb */
+ {
+ int d_ot;
+ /* d_ot is the size of destination */
+ d_ot = dflag + OT_WORD;
+ /* ot is the size of source */
+ ot = (b & 1) + OT_BYTE;
+ modrm = ldub(s->pc++);
+ reg = ((modrm >> 3) & 7) + OR_EAX;
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+
+ if (mod == 3) {
+ gen_op_mov_TN_reg[ot][0][rm]();
+ switch(ot | (b & 8)) {
+ case OT_BYTE:
+ gen_op_movzbl_T0_T0();
+ break;
+ case OT_BYTE | 8:
+ gen_op_movsbl_T0_T0();
+ break;
+ case OT_WORD:
+ gen_op_movzwl_T0_T0();
+ break;
+ default:
+ case OT_WORD | 8:
+ gen_op_movswl_T0_T0();
+ break;
+ }
+ gen_op_mov_reg_T0[d_ot][reg]();
+ } else {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ if (b & 8) {
+ gen_op_lds_T0_A0[ot]();
+ } else {
+ gen_op_ldu_T0_A0[ot]();
+ }
+ gen_op_mov_reg_T0[d_ot][reg]();
+ }
+ }
+ break;
+
+ case 0x8d: /* lea */
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_mov_reg_A0[ot - OT_WORD][reg]();
+ break;
+
+ case 0xa0: /* mov EAX, Ov */
+ case 0xa1:
+ case 0xa2: /* mov Ov, EAX */
+ case 0xa3:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (s->aflag)
+ offset_addr = insn_get(s, OT_LONG);
+ else
+ offset_addr = insn_get(s, OT_WORD);
+
+ if ((b & 2) == 0) {
+ gen_op_ld_T0_A0[ot]();
+ gen_op_mov_reg_T0[ot][R_EAX]();
+ } else {
+ gen_op_mov_TN_reg[ot][0][R_EAX]();
+ gen_op_st_T0_A0[ot]();
+ }
+ break;
+
+ case 0xb0 ... 0xb7: /* mov R, Ib */
+ val = insn_get(s, OT_BYTE);
+ gen_op1_movl_T0_im(val);
+ gen_op_mov_reg_T0[OT_BYTE][b & 7]();
+ break;
+ case 0xb8 ... 0xbf: /* mov R, Iv */
+ ot = dflag ? OT_LONG : OT_WORD;
+ val = insn_get(s, ot);
+ reg = OR_EAX + (b & 7);
+ gen_op1_movl_T0_im(val);
+ gen_op_mov_reg_T0[ot][reg]();
+ break;
+
+ case 0x91 ... 0x97: /* xchg R, EAX */
+ ot = dflag ? OT_LONG : OT_WORD;
+ reg = b & 7;
+ gen_op_mov_TN_reg[ot][0][reg]();
+ gen_op_mov_TN_reg[ot][1][R_EAX]();
+ gen_op_mov_reg_T0[ot][R_EAX]();
+ gen_op_mov_reg_T1[ot][reg]();
+ break;
+ case 0x86:
+ case 0x87: /* xchg Ev, Gv */
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ modrm = ldub(s->pc++);
+ reg = (modrm >> 3) & 7;
+
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_mov_TN_reg[ot][0][reg]();
+ gen_op_ld_T1_A0[ot]();
+ gen_op_st_T0_A0[ot]();
+ gen_op_mov_reg_T1[ot][reg]();
+ break;
+
+ /************************/
+ /* shifts */
+ case 0xc0:
+ case 0xc1:
+ /* shift Ev,Ib */
+ shift = 2;
+ grp2:
+ {
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ op = (modrm >> 3) & 7;
+
+ if (mod != 3) {
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ gen_op_ld_T0_A0[ot]();
+ opreg = OR_TMP0;
+ } else {
+ opreg = rm + OR_EAX;
+ }
+
+ /* simpler op */
+ if (shift == 0) {
+ gen_shift(s, op, ot, opreg, OR_ECX);
+ } else {
+ if (shift == 2) {
+ shift = ldub(s->pc++);
+ }
+ gen_shifti(s, op, ot, opreg, shift);
+ }
+
+ if (mod != 3) {
+ gen_op_st_T0_A0[ot]();
+ }
+ }
+ break;
+ case 0xd0:
+ case 0xd1:
+ /* shift Ev,1 */
+ shift = 1;
+ goto grp2;
+ case 0xd2:
+ case 0xd3:
+ /* shift Ev,cl */
+ shift = 0;
+ goto grp2;
+
+ /************************/
+ /* floats */
+#if 0
+ case 0xd8 ... 0xdf:
+ modrm = ldub(s->pc++);
+ mod = (modrm >> 6) & 3;
+ rm = modrm & 7;
+ op = ((b & 7) << 3) | ((modrm >> 3) & 7);
+
+ if (mod != 3) {
+ /* memory op */
+ gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+ switch(op) {
+ case 0x00 ... 0x07: /* fxxxs */
+ case 0x10 ... 0x17: /* fixxxl */
+ case 0x20 ... 0x27: /* fxxxl */
+ case 0x30 ... 0x37: /* fixxx */
+ {
+ int op1, swap;
+ op1 = fp_ops[op & 7];
+
+ swap = 0;
+ if ((op & 7) == 5 || (op & 7) == 7)
+ swap = 1;
+
+ switch(op >> 4) {
+ case 0:
+ ot = OT_LONG;
+ is_int = 0;
+ break;
+ case 1:
+ ot = OT_LONG;
+ is_int = 1;
+ break;
+ case 2:
+ ot = OT_QUAD;
+ is_int = 0;
+ break;
+ case 3:
+ default:
+ ot = OT_WORD;
+ is_int = 1;
+ break;
+ }
+
+ /* if integer, needs to convert to float */
+ if (is_int) {
+ /* XXX: potential loss of precision if large integer */
+ gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr);
+ gen_insn2(OP_I2FL, OR_FTMP0, OR_TMP0);
+ } else {
+ gen_ld(OP_LDUB + ot, OR_FTMP0, reg_addr, offset_addr);
+ }
+ if (ot != OT_QUAD)
+ op1 += OP_FADDL - OP_FADDQ;
+
+ if (!swap)
+ gen_insn3(op1, OR_ST0, OR_ST0, OR_FTMP0);
+ else
+ gen_insn3(op1, OR_ST0, OR_FTMP0, OR_ST0);
+
+ if ((op & 7) == 3) {
+ /* fcomp needs pop */
+ gen_insn0(OP_FPOP);
+ }
+ }
+ break;
+ case 0x08: /* flds */
+ case 0x0a: /* fsts */
+ case 0x0b: /* fstps */
+ case 0x18: /* fildl */
+ case 0x1a: /* fistl */
+ case 0x1b: /* fistpl */
+ case 0x28: /* fldl */
+ case 0x2a: /* fstl */
+ case 0x2b: /* fstpl */
+ case 0x38: /* filds */
+ case 0x3a: /* fists */
+ case 0x3b: /* fistps */
+
+ switch(op >> 4) {
+ case 0:
+ ot = OT_LONG;
+ is_int = 0;
+ break;
+ case 1:
+ ot = OT_LONG;
+ is_int = 1;
+ break;
+ case 2:
+ ot = OT_QUAD;
+ is_int = 0;
+ break;
+ case 3:
+ default:
+ ot = OT_WORD;
+ is_int = 1;
+ break;
+ }
+
+ switch(op & 7) {
+ case 0:
+ gen_insn0(OP_FPUSH);
+ if (is_int) {
+ /* XXX: potential loss of precision */
+ gen_ld(OP_LDUB + ot, OR_TMP0, reg_addr, offset_addr);
+ gen_insn2(OP_I2FL, OR_ST0, OR_TMP0);
+ } else {
+ gen_ld(OP_LDUB + ot, OR_ST0, reg_addr, offset_addr);
+ }
+ break;
+ default:
+ if (is_int) {
+ gen_insn2(OP_F2IL, OR_TMP0, OR_ST0);
+ gen_st(OP_STB + ot, OR_TMP0, reg_addr, offset_addr);
+ } else {
+ gen_st(OP_STB + ot, OR_ST0, reg_addr, offset_addr);
+ }
+ if ((op & 7) == 3)
+ gen_insn0(OP_FPOP);
+ break;
+ }
+ break;
+ case 0x2f: /* fnstsw mem */
+ gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO);
+ gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr);
+ break;
+
+ case 0x3c: /* fbld */
+ case 0x3e: /* fbstp */
+ error("float BCD not hanlded");
+ return -1;
+ case 0x3d: /* fildll */
+ gen_insn0(OP_FPUSH);
+ gen_ld(OP_LDQ, OR_TMP0, reg_addr, offset_addr);
+ gen_insn2(OP_I2FQ, OR_ST0, OR_TMP0);
+ break;
+ case 0x3f: /* fistpll */
+ gen_insn2(OP_F2IQ, OR_TMP0, OR_ST0);
+ gen_st(OP_STQ, OR_TMP0, reg_addr, offset_addr);
+ gen_insn0(OP_FPOP);
+ break;
+ default:
+ error("unhandled memory FP\n");
+ return -1;
+ }
+ } else {
+ /* register float ops */
+ opreg = rm + OR_ST0;
+
+ switch(op) {
+ case 0x08: /* fld sti */
+ gen_insn0(OP_FPUSH);
+ gen_mov(OR_ST0, OR_ST0 + ((rm + 1) & 7));
+ break;
+ case 0x09: /* fxchg sti */
+ gen_mov(OR_TMP0, OR_ST0);
+ gen_mov(OR_ST0, opreg);
+ gen_mov(opreg, OR_TMP0);
+ break;
+ case 0x0a: /* grp d9/2 */
+ switch(rm) {
+ case 0: /* fnop */
+ gen_insn0(OP_NOP);
+ break;
+ default:
+ error("unhandled FP GRP d9/2\n");
+ return -1;
+ }
+ break;
+ case 0x0c: /* grp d9/4 */
+ switch(rm) {
+ case 0: /* fchs */
+ gen_insn3(OP_FSUBQ, OR_ST0, OR_ZERO, OR_ST0);
+ break;
+ case 1: /* fabs */
+ gen_insn2(OP_FABSQ, OR_ST0, OR_ST0);
+ break;
+ case 4: /* ftst */
+ gen_insn3(OP_CMP, OR_ZERO, OR_ST0, OR_ZERO);
+ break;
+ case 5: /* fxam */
+ gen_insn3(OP_FSPECIAL, OR_ZERO, OR_ST0, OR_ZERO);
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 0x0d: /* grp d9/5 */
+ {
+ if (rm == 7) {
+ error("bad GRP d9/5");
+ return -1;
+ }
+ /* XXX: needs constant load or symbol table */
+ gen_insn0(OP_FPUSH);
+ gen_ld(OP_LDQ, OR_ST0, OR_ZERO,
+ (rm * 8) + FLOAT_CONST_ADDR);
+ }
+ break;
+ case 0x0e: /* grp d9/6 */
+ switch(rm) {
+ case 0: /* f2xm1 */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO);
+ break;
+ case 1: /* fyl2x */
+ gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1);
+ gen_insn0(OP_FPOP);
+ break;
+ case 2: /* fptan */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO);
+ gen_insn0(OP_FPUSH);
+ /* load one */
+ gen_ld(OP_LDQ, OR_ST0, OR_ZERO,
+ (0 * 8) + FLOAT_CONST_ADDR);
+ break;
+ case 3: /* fpatan */
+ gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1);
+ gen_insn0(OP_FPOP);
+ break;
+ case 4: /* fxtract */
+ gen_insn0(OP_FPUSH);
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO);
+ gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO);
+ break;
+ case 5: /* fprem1 */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
+ break;
+ case 6: /* fdecstp */
+ gen_insn0(OP_FPUSH);
+ break;
+ default:
+ case 7: /* fdecstp */
+ gen_insn0(OP_FPOP);
+ break;
+ }
+ break;
+ case 0x0f: /* grp d9/7 */
+ switch(rm) {
+ case 0: /* fprem */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
+ break;
+ case 1: /* fyl2xp1 */
+ gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST0, OR_ST1);
+ gen_insn0(OP_FPOP);
+ break;
+ case 3: /* fsincos */
+ gen_insn0(OP_FPUSH);
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST1, OR_ZERO);
+ gen_insn3(OP_FSPECIAL, OR_ST1, OR_ST1, OR_ZERO);
+ break;
+ case 5: /* fscale */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ST1);
+ break;
+ case 2: /* fsqrt */
+ case 4: /* frndint */
+ case 6: /* fsin */
+ default:
+ case 7: /* fcos */
+ gen_insn3(OP_FSPECIAL, OR_ST0, OR_ST0, OR_ZERO);
+ break;
+ }
+ break;
+ case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
+ case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
+ case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
+ {
+ int op1, swap;
+
+ op1 = fp_ops[op & 7];
+ swap = 0;
+ if ((op & 7) == 5 || (op & 7) == 7)
+ swap = 1;
+ if (op >= 0x20) {
+ if (swap)
+ gen_insn3(op1, opreg, OR_ST0, opreg);
+ else
+ gen_insn3(op1, opreg, opreg, OR_ST0);
+ } else {
+ if (swap)
+ gen_insn3(op1, OR_ST0, opreg, OR_ST0);
+ else
+ gen_insn3(op1, OR_ST0, OR_ST0, opreg);
+ }
+ if (op >= 0x30)
+ gen_insn0(OP_FPOP);
+ }
+ break;
+ case 0x02: /* fcom */
+ gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg);
+ break;
+ case 0x03: /* fcomp */
+ gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg);
+ gen_insn0(OP_FPOP);
+ break;
+ case 0x15: /* da/5 */
+ switch(rm) {
+ case 1: /* fucompp */
+ gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg);
+ gen_insn0(OP_FPOP);
+ gen_insn0(OP_FPOP);
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 0x2a: /* fst sti */
+ gen_mov(opreg, OR_ST0);
+ break;
+ case 0x2b: /* fstp sti */
+ gen_mov(opreg, OR_ST0);
+ gen_insn0(OP_FPOP);
+ break;
+ case 0x33: /* de/3 */
+ switch(rm) {
+ case 1: /* fcompp */
+ gen_insn3(OP_CMP, OR_ZERO, OR_ST0, opreg);
+ gen_insn0(OP_FPOP);
+ gen_insn0(OP_FPOP);
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case 0x3c: /* df/4 */
+ switch(rm) {
+ case 0:
+ gen_insn3(OP_FNSTS, OR_EAX, OR_ZERO, OR_ZERO);
+ break;
+ default:
+ return -1;
+ }
+ break;
+ default:
+ error("unhandled FP\n");
+ return -1;
+ }
+ }
+ break;
+#endif
+ /************************/
+ /* string ops */
+ case 0xa4: /* movsS */
+ case 0xa5:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPZ) {
+ gen_op_movs[3 + ot]();
+ } else {
+ gen_op_movs[ot]();
+ }
+ break;
+
+ case 0xaa: /* stosS */
+ case 0xab:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPZ) {
+ gen_op_stos[3 + ot]();
+ } else {
+ gen_op_stos[ot]();
+ }
+ break;
+ case 0xac: /* lodsS */
+ case 0xad:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPZ) {
+ gen_op_lods[3 + ot]();
+ } else {
+ gen_op_lods[ot]();
+ }
+ break;
+ case 0xae: /* scasS */
+ case 0xaf:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPNZ) {
+ gen_op_scas[6 + ot]();
+ } else if (prefixes & PREFIX_REPZ) {
+ gen_op_scas[3 + ot]();
+ } else {
+ gen_op_scas[ot]();
+ }
+ break;
+
+ case 0xa6: /* cmpsS */
+ case 0xa7:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPNZ) {
+ gen_op_cmps[6 + ot]();
+ } else if (prefixes & PREFIX_REPZ) {
+ gen_op_cmps[3 + ot]();
+ } else {
+ gen_op_cmps[ot]();
+ }
+ break;
+
+ case 0x6c: /* insS */
+ case 0x6d:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPZ) {
+ gen_op_ins[3 + ot]();
+ } else {
+ gen_op_ins[ot]();
+ }
+ break;
+ case 0x6e: /* outsS */
+ case 0x6f:
+ if ((b & 1) == 0)
+ ot = OT_BYTE;
+ else
+ ot = dflag ? OT_LONG : OT_WORD;
+ if (prefixes & PREFIX_REPZ) {
+ gen_op_outs[3 + ot]();
+ } else {
+ gen_op_outs[ot]();
+ }
+ break;
+
+ /************************/
+ /* control */
+ case 0xc2: /* ret im */
+ /* XXX: handle stack pop ? */
+ val = ldsw(s->pc);
+ s->pc += 2;
+ gen_op_popl_T0();
+ gen_op_addl_ESP_im(val);
+ gen_op_jmp_T0();
+ break;
+ case 0xc3: /* ret */
+ gen_op_popl_T0();
+ gen_op_jmp_T0();
+ break;
+ case 0xe8: /* call */
+ val = insn_get(s, OT_LONG);
+ val += (long)s->pc;
+ gen_op1_movl_T1_im((long)s->pc);
+ gen_op_pushl_T1();
+ gen_op_jmp_im(val);
+ break;
+ case 0xe9: /* jmp */
+ val = insn_get(s, OT_LONG);
+ val += (long)s->pc;
+ gen_op_jmp_im(val);
+ break;
+ case 0xeb: /* jmp Jb */
+ val = (int8_t)insn_get(s, OT_BYTE);
+ val += (long)s->pc;
+ gen_op_jmp_im(val);
+ break;
+ case 0x70 ... 0x7f: /* jcc Jb */
+ val = (int8_t)insn_get(s, OT_BYTE);
+ val += (long)s->pc;
+ goto do_jcc;
+ case 0x180 ... 0x18f: /* jcc Jv */
+ if (dflag) {
+ val = insn_get(s, OT_LONG);
+ } else {
+ val = (int16_t)insn_get(s, OT_WORD);
+ }
+ val += (long)s->pc; /* XXX: fix 16 bit wrap */
+ do_jcc:
+ gen_jcc(s, b, val);
+ break;
+
+ case 0x190 ... 0x19f:
+ modrm = ldub(s->pc++);
+ gen_setcc(s, b);
+ gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
+ break;
+
+ /************************/
+ /* flags */
+ case 0x9c: /* pushf */
+ gen_op_movl_T0_eflags();
+ gen_op_pushl_T0();
+ break;
+ case 0x9d: /* popf */
+ gen_op_popl_T0();
+ gen_op_movl_eflags_T0();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x9e: /* sahf */
+ gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ gen_op_movb_eflags_T0();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x9f: /* lahf */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ gen_op_movl_T0_eflags();
+ gen_op_mov_reg_T0[OT_BYTE][R_AH]();
+ break;
+ case 0xf5: /* cmc */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ gen_op_cmc();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0xf8: /* clc */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ gen_op_clc();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0xf9: /* stc */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ op_set_cc_op(s->cc_op);
+ gen_op_stc();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0xfc: /* cld */
+ gen_op_cld();
+ break;
+ case 0xfd: /* std */
+ gen_op_std();
+ break;
+
+ /************************/
+ /* misc */
+ case 0x90: /* nop */
+ break;
+
+#if 0
+ case 0x1a2: /* cpuid */
+ gen_insn0(OP_ASM);
+ break;
+#endif
+ default:
+ error("unknown opcode %x", b);
+ return -1;
+ }
+ return (long)s->pc;
+}
+