diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-03 23:23:09 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-03 23:23:09 +0000 |
commit | 4b74fe1f0013c622693b26141c0ed031a284a45a (patch) | |
tree | 4dfd2b0791246a7f1793e5caba05356d940314a2 /translate-i386.c | |
parent | 586314f2aa62990dead8144e780c4c8c498eece6 (diff) |
many fixes
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@19 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r-- | translate-i386.c | 291 |
1 files changed, 225 insertions, 66 deletions
diff --git a/translate-i386.c b/translate-i386.c index 20a8039048..f145a54068 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -27,7 +27,9 @@ static void error(const char *fmt, ...) va_list ap; va_start(ap, fmt); + fprintf(stderr, "\n"); vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); va_end(ap); exit(1); } @@ -98,42 +100,13 @@ enum { 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); @@ -354,14 +327,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { 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, + NULL, + NULL, 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 GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = { + [OT_BYTE] = { + gen_op_adcb_T0_T1_cc, + gen_op_sbbb_T0_T1_cc, + }, + [OT_WORD] = { + gen_op_adcw_T0_T1_cc, + gen_op_sbbw_T0_T1_cc, + }, + [OT_LONG] = { + gen_op_adcl_T0_T1_cc, + gen_op_sbbl_T0_T1_cc, + }, +}; + static const int cc_op_arithb[8] = { CC_OP_ADDB, CC_OP_LOGICB, @@ -406,6 +394,21 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = { }, }; +static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = { + [0] = { + gen_op_btw_T0_T1_cc, + gen_op_btsw_T0_T1_cc, + gen_op_btrw_T0_T1_cc, + gen_op_btcw_T0_T1_cc, + }, + [1] = { + gen_op_btl_T0_T1_cc, + gen_op_btsl_T0_T1_cc, + gen_op_btrl_T0_T1_cc, + gen_op_btcl_T0_T1_cc, + }, +}; + static GenOpFunc *gen_op_lds_T0_A0[3] = { gen_op_ldsb_T0_A0, gen_op_ldsw_T0_A0, @@ -644,18 +647,23 @@ static void gen_op(DisasContext *s1, int op, int ot, int d, int s) 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 (op == OP_ADCL || op == OP_SBBL) { + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL](); + s1->cc_op = CC_OP_DYNAMIC; + } else { + gen_op_arith_T0_T1_cc[op](); + s1->cc_op = cc_op_arithb[op] + ot; + } 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_op_movl_T1_im(c); - gen_op(s1, op, ot, d, OR_TMP0); + gen_op(s1, op, ot, d, OR_TMP1); } static void gen_inc(DisasContext *s1, int ot, int d, int c) @@ -664,10 +672,13 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c) 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) + if (c > 0) { gen_op_incl_T0_cc(); - else + s1->cc_op = CC_OP_INCB + ot; + } else { gen_op_decl_T0_cc(); + s1->cc_op = CC_OP_DECB + ot; + } if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); } @@ -678,20 +689,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s) 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; - } + /* for zero counts, flags are not updated, so must do it dynamically */ + if (s1->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s1->cc_op); + + gen_op_shift_T0_T1_cc[ot][op](); + if (d != OR_TMP0) gen_op_mov_reg_T0[ot][d](); s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ @@ -785,12 +788,65 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ } gen_op_addl_A0_reg_sN[scale][reg2](); } - opreg = OR_A0; } else { - fprintf(stderr, "16 bit addressing not supported\n"); - disp = 0; - opreg = 0; + switch (mod) { + case 0: + if (rm == 6) { + disp = lduw(s->pc); + s->pc += 2; + gen_op_movl_A0_im(disp); + goto no_rm; + } else { + disp = 0; + } + break; + case 1: + disp = (int8_t)ldub(s->pc++); + break; + default: + case 2: + disp = lduw(s->pc); + s->pc += 2; + break; + } + switch(rm) { + case 0: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 1: + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 2: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_ESI](); + break; + case 3: + gen_op_movl_A0_reg[R_EBP](); + gen_op_addl_A0_reg_sN[0][R_EDI](); + break; + case 4: + gen_op_movl_A0_reg[R_ESI](); + break; + case 5: + gen_op_movl_A0_reg[R_EDI](); + break; + case 6: + gen_op_movl_A0_reg[R_EBP](); + break; + default: + case 7: + gen_op_movl_A0_reg[R_EBX](); + break; + } + if (disp != 0) + gen_op_addl_A0_im(disp); + gen_op_andl_A0_ffff(); + no_rm: ; } + opreg = OR_A0; + disp = 0; *reg_ptr = opreg; *offset_ptr = disp; } @@ -870,6 +926,12 @@ static void gen_jcc(DisasContext *s, int b, int val) case CC_OP_ADDB: case CC_OP_ADDW: case CC_OP_ADDL: + case CC_OP_ADCB: + case CC_OP_ADCW: + case CC_OP_ADCL: + case CC_OP_SBBB: + case CC_OP_SBBW: + case CC_OP_SBBL: case CC_OP_LOGICB: case CC_OP_LOGICW: case CC_OP_LOGICL: @@ -882,6 +944,9 @@ static void gen_jcc(DisasContext *s, int b, int val) case CC_OP_SHLB: case CC_OP_SHLW: case CC_OP_SHLL: + case CC_OP_SARB: + case CC_OP_SARW: + case CC_OP_SARL: switch(jcc_op) { case JCC_Z: func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op]; @@ -1284,11 +1349,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_inc(s, ot, OR_TMP0, 1); if (mod != 3) gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); break; case 1: /* dec Ev */ gen_inc(s, ot, OR_TMP0, -1); if (mod != 3) gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); break; case 2: /* call Ev */ gen_op_movl_T1_im((long)s->pc); @@ -1359,7 +1428,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) 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); @@ -1372,9 +1440,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) } if (ot == OT_LONG) { - op_imull_T0_T1(); + gen_op_imull_T0_T1(); } else { - op_imulw_T0_T1(); + gen_op_imulw_T0_T1(); } gen_op_mov_reg_T0[ot][reg](); s->cc_op = CC_OP_MUL; @@ -1522,7 +1590,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) offset_addr = insn_get(s, OT_LONG); else offset_addr = insn_get(s, OT_WORD); - + gen_op_movl_A0_im(offset_addr); if ((b & 2) == 0) { gen_op_ld_T0_A0[ot](); gen_op_mov_reg_T0[ot][R_EAX](); @@ -1717,17 +1785,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; } break; -#if 0 + case 0x0d: /* fldcw mem */ + gen_op_fldcw_A0(); + break; + case 0x0f: /* fnstcw mem */ + gen_op_fnstcw_A0(); + 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); + gen_op_fnstsw_A0(); break; - case 0x3c: /* fbld */ case 0x3e: /* fbstp */ error("float BCD not hanlded"); return -1; -#endif case 0x3d: /* fildll */ gen_op_fpush(); gen_op_fildll_ST0_A0(); @@ -1737,7 +1807,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_fpop(); break; default: - error("unhandled memory FP\n"); + error("unhandled memory FP [op=0x%02x]\n", op); return -1; } } else { @@ -1987,11 +2057,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_scas[6 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_scas[3 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { gen_op_scas[ot](); + s->cc_op = CC_OP_SUBB + ot; } break; @@ -2002,11 +2079,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) else ot = dflag ? OT_LONG : OT_WORD; if (prefixes & PREFIX_REPNZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_cmps[6 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else if (prefixes & PREFIX_REPZ) { + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); gen_op_cmps[3 + ot](); + s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */ } else { gen_op_cmps[ot](); + s->cc_op = CC_OP_SUBB + ot; } break; @@ -2187,6 +2271,74 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) break; /************************/ + /* bit operations */ + case 0x1ba: /* bt/bts/btr/btc Gv, im */ + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + op = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + /* load shift */ + val = ldub(s->pc++); + gen_op_movl_T1_im(val); + if (op < 4) + return -1; + op -= 4; + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SHLB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); + } + break; + case 0x1a3: /* bt Gv, Ev */ + op = 0; + goto do_btx; + case 0x1ab: /* bts */ + op = 1; + goto do_btx; + case 0x1b3: /* btr */ + op = 2; + goto do_btx; + case 0x1bb: /* btc */ + op = 3; + do_btx: + ot = dflag ? OT_LONG : OT_WORD; + modrm = ldub(s->pc++); + reg = (modrm >> 3) & 7; + mod = (modrm >> 6) & 3; + rm = modrm & 7; + gen_op_mov_TN_reg[OT_LONG][1][reg](); + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* specific case: we need to add a displacement */ + if (ot == OT_WORD) + gen_op_add_bitw_A0_T1(); + else + gen_op_add_bitl_A0_T1(); + gen_op_ld_T0_A0[ot](); + } else { + gen_op_mov_TN_reg[ot][0][rm](); + } + gen_op_btx_T0_T1_cc[ot - OT_WORD][op](); + s->cc_op = CC_OP_SHLB + ot; + if (op != 0) { + if (mod != 3) + gen_op_st_T0_A0[ot](); + else + gen_op_mov_reg_T0[ot][rm](); + } + break; + + /************************/ /* misc */ case 0x90: /* nop */ break; @@ -2206,6 +2358,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr) gen_op_into((long)pc_start, (long)s->pc); *is_jmp_ptr = 1; break; + case 0x1c8 ... 0x1cf: /* bswap reg */ + reg = b & 7; + gen_op_mov_TN_reg[OT_LONG][0][reg](); + gen_op_bswapl_T0(); + gen_op_mov_reg_T0[OT_LONG][reg](); + break; + #if 0 case 0x1a2: /* cpuid */ gen_insn0(OP_ASM); |