aboutsummaryrefslogtreecommitdiff
path: root/translate-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-06-30 23:36:57 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-06-30 23:36:57 +0000
commite477b8b81ba5212747799ce71858e2b110fc6ae5 (patch)
treeb25d335ce7fa2dd3fc67dc858023e94a9ea309db /translate-i386.c
parentb118d61e556a1f5cebc991e368af7292ffa1d8f3 (diff)
correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r--translate-i386.c221
1 files changed, 194 insertions, 27 deletions
diff --git a/translate-i386.c b/translate-i386.c
index 8a7147c556..bfc988446e 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -390,6 +390,21 @@ static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
},
};
+static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = {
+ [OT_BYTE] = {
+ gen_op_adcb_mem_T0_T1_cc,
+ gen_op_sbbb_mem_T0_T1_cc,
+ },
+ [OT_WORD] = {
+ gen_op_adcw_mem_T0_T1_cc,
+ gen_op_sbbw_mem_T0_T1_cc,
+ },
+ [OT_LONG] = {
+ gen_op_adcl_mem_T0_T1_cc,
+ gen_op_sbbl_mem_T0_T1_cc,
+ },
+};
+
static const int cc_op_arithb[8] = {
CC_OP_ADDB,
CC_OP_LOGICB,
@@ -407,6 +422,12 @@ static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
gen_op_cmpxchgl_T0_T1_EAX_cc,
};
+static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = {
+ gen_op_cmpxchgb_mem_T0_T1_EAX_cc,
+ gen_op_cmpxchgw_mem_T0_T1_EAX_cc,
+ gen_op_cmpxchgl_mem_T0_T1_EAX_cc,
+};
+
static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
[OT_BYTE] = {
gen_op_rolb_T0_T1_cc,
@@ -440,6 +461,39 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
},
};
+static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = {
+ [OT_BYTE] = {
+ gen_op_rolb_mem_T0_T1_cc,
+ gen_op_rorb_mem_T0_T1_cc,
+ gen_op_rclb_mem_T0_T1_cc,
+ gen_op_rcrb_mem_T0_T1_cc,
+ gen_op_shlb_mem_T0_T1_cc,
+ gen_op_shrb_mem_T0_T1_cc,
+ gen_op_shlb_mem_T0_T1_cc,
+ gen_op_sarb_mem_T0_T1_cc,
+ },
+ [OT_WORD] = {
+ gen_op_rolw_mem_T0_T1_cc,
+ gen_op_rorw_mem_T0_T1_cc,
+ gen_op_rclw_mem_T0_T1_cc,
+ gen_op_rcrw_mem_T0_T1_cc,
+ gen_op_shlw_mem_T0_T1_cc,
+ gen_op_shrw_mem_T0_T1_cc,
+ gen_op_shlw_mem_T0_T1_cc,
+ gen_op_sarw_mem_T0_T1_cc,
+ },
+ [OT_LONG] = {
+ gen_op_roll_mem_T0_T1_cc,
+ gen_op_rorl_mem_T0_T1_cc,
+ gen_op_rcll_mem_T0_T1_cc,
+ gen_op_rcrl_mem_T0_T1_cc,
+ gen_op_shll_mem_T0_T1_cc,
+ gen_op_shrl_mem_T0_T1_cc,
+ gen_op_shll_mem_T0_T1_cc,
+ gen_op_sarl_mem_T0_T1_cc,
+ },
+};
+
static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = {
[0] = {
gen_op_shldw_T0_T1_im_cc,
@@ -462,6 +516,28 @@ static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = {
},
};
+static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = {
+ [0] = {
+ gen_op_shldw_mem_T0_T1_im_cc,
+ gen_op_shrdw_mem_T0_T1_im_cc,
+ },
+ [1] = {
+ gen_op_shldl_mem_T0_T1_im_cc,
+ gen_op_shrdl_mem_T0_T1_im_cc,
+ },
+};
+
+static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = {
+ [0] = {
+ gen_op_shldw_mem_T0_T1_ECX_cc,
+ gen_op_shrdw_mem_T0_T1_ECX_cc,
+ },
+ [1] = {
+ gen_op_shldl_mem_T0_T1_ECX_cc,
+ gen_op_shrdl_mem_T0_T1_ECX_cc,
+ },
+};
+
static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
[0] = {
gen_op_btw_T0_T1_cc,
@@ -763,11 +839,14 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
case 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]();
+ if (d != OR_TMP0) {
+ gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
+ gen_op_mov_reg_T0[ot][d]();
+ } else {
+ gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL]();
+ }
s1->cc_op = CC_OP_DYNAMIC;
- /* XXX: incorrect: CC_OP must also be modified AFTER memory access */
- gen_update_cc = gen_op_update2_cc;
- break;
+ goto the_end;
case OP_ADDL:
gen_op_addl_T0_T1();
s1->cc_op = CC_OP_ADDB + ot;
@@ -802,6 +881,7 @@ static void gen_op(DisasContext *s1, int op, int ot, int d)
exception support) */
if (gen_update_cc)
gen_update_cc();
+ the_end: ;
}
/* if d == OR_TMP0, it means memory operand (address in A0) */
@@ -831,14 +911,18 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
{
if (d != OR_TMP0)
gen_op_mov_TN_reg[ot][0][d]();
+ else
+ gen_op_ld_T0_A0[ot]();
if (s != OR_TMP1)
gen_op_mov_TN_reg[ot][1][s]();
/* for zero counts, flags are not updated, so must do it dynamically */
if (s1->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s1->cc_op);
-
- gen_op_shift_T0_T1_cc[ot][op]();
-
+
+ if (d != OR_TMP0)
+ gen_op_shift_T0_T1_cc[ot][op]();
+ else
+ gen_op_shift_mem_T0_T1_cc[ot][op]();
if (d != OR_TMP0)
gen_op_mov_reg_T0[ot][d]();
s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
@@ -1885,8 +1969,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} else {
gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
gen_op_ld_T0_A0[ot]();
- gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
- gen_op_st_T0_A0[ot]();
+ gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot]();
}
s->cc_op = CC_OP_SUBB + ot;
break;
@@ -2264,7 +2347,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
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;
@@ -2279,10 +2361,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
}
gen_shifti(s, op, ot, opreg, shift);
}
-
- if (mod != 3) {
- gen_op_st_T0_A0[ot]();
- }
}
break;
case 0xd0:
@@ -2330,7 +2408,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val = ldub(s->pc++);
val &= 0x1f;
if (val) {
- gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
+ if (mod == 3)
+ gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
+ else
+ gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val);
if (op == 0 && ot != OT_WORD)
s->cc_op = CC_OP_SHLB + ot;
else
@@ -2339,12 +2420,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
} else {
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
+ if (mod == 3)
+ gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
+ else
+ gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op]();
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
}
- if (mod != 3) {
- gen_op_st_T0_A0[ot]();
- } else {
+ if (mod == 3) {
gen_op_mov_reg_T0[ot][rm]();
}
break;
@@ -3202,6 +3284,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_st_T0_A0[ot]();
else
gen_op_mov_reg_T0[ot][rm]();
+ gen_op_update_bt_cc();
}
break;
case 0x1a3: /* bt Gv, Ev */
@@ -3240,6 +3323,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_st_T0_A0[ot]();
else
gen_op_mov_reg_T0[ot][rm]();
+ gen_op_update_bt_cc();
}
break;
case 0x1bc: /* bsf */
@@ -3640,6 +3724,13 @@ static uint16_t opc_read_flags[NB_OPS] = {
[INDEX_op_sbbw_T0_T1_cc] = CC_C,
[INDEX_op_sbbl_T0_T1_cc] = CC_C,
+ [INDEX_op_adcb_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_adcw_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_adcl_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_sbbb_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_sbbw_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_sbbl_mem_T0_T1_cc] = CC_C,
+
/* subtle: due to the incl/decl implementation, C is used */
[INDEX_op_update_inc_cc] = CC_C,
@@ -3717,23 +3808,38 @@ static uint16_t opc_read_flags[NB_OPS] = {
[INDEX_op_rcrb_T0_T1_cc] = CC_C,
[INDEX_op_rcrw_T0_T1_cc] = CC_C,
[INDEX_op_rcrl_T0_T1_cc] = CC_C,
+
+ [INDEX_op_rclb_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_rclw_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_rcll_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_rcrb_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_rcrw_mem_T0_T1_cc] = CC_C,
+ [INDEX_op_rcrl_mem_T0_T1_cc] = CC_C,
};
/* flags written by an operation */
static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_update2_cc] = CC_OSZAPC,
[INDEX_op_update1_cc] = CC_OSZAPC,
+ [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_update_neg_cc] = CC_OSZAPC,
+ /* subtle: due to the incl/decl implementation, C is used */
+ [INDEX_op_update_inc_cc] = CC_OSZAPC,
+ [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
+
[INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_update_neg_cc] = CC_OSZAPC,
- /* subtle: due to the incl/decl implementation, C is used */
- [INDEX_op_update_inc_cc] = CC_OSZAPC,
- [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
+
+ [INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_mulb_AL_T0] = CC_OSZAPC,
[INDEX_op_imulb_AL_T0] = CC_OSZAPC,
@@ -3795,6 +3901,42 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
[INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
+ [INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C,
+
+ [INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C,
+ [INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C,
+
+ [INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC,
+
+ [INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC,
+
+ [INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC,
+ [INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC,
+
+ [INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
+ [INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
+ [INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC,
+ [INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC,
+
+ [INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
+ [INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
+ [INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC,
+ [INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC,
+
[INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
[INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
@@ -3832,6 +3974,10 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
+ [INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC,
+ [INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC,
+ [INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC,
+
[INDEX_op_cmpxchg8b] = CC_Z,
[INDEX_op_lar] = CC_Z,
[INDEX_op_lsl] = CC_Z,
@@ -3844,8 +3990,10 @@ static uint16_t opc_simpler[NB_OPS] = {
[INDEX_op_update2_cc] = INDEX_op_nop,
[INDEX_op_update1_cc] = INDEX_op_nop,
[INDEX_op_update_neg_cc] = INDEX_op_nop,
+#if 0
+ /* broken: CC_OP logic must be rewritten */
[INDEX_op_update_inc_cc] = INDEX_op_nop,
-
+#endif
[INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
[INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
[INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
@@ -3854,6 +4002,14 @@ static uint16_t opc_simpler[NB_OPS] = {
[INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
[INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
+ [INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1,
+ [INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1,
+ [INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1,
+
+ [INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1,
+ [INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1,
+ [INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1,
+
[INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
[INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
[INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
@@ -3971,6 +4127,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
break;
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
+ if (!dc->tf && dc->is_jmp == DISAS_NEXT) {
+ gen_jmp(dc, ret - (unsigned long)dc->cs_base);
+ }
+
/* we must store the eflags state if it is not already done */
if (dc->is_jmp != DISAS_TB_JUMP) {
if (dc->cc_op != CC_OP_DYNAMIC)
@@ -3983,12 +4143,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
if (dc->tf) {
gen_op_raise_exception(EXCP01_SSTP);
}
- if (dc->is_jmp != 3) {
+ if (dc->is_jmp != DISAS_TB_JUMP) {
/* indicate that the hash table must be used to find the next TB */
gen_op_movl_T0_0();
}
*gen_opc_ptr = INDEX_op_end;
-
+ /* we don't forget to fill the last values */
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ lj++;
+ while (lj <= j)
+ gen_opc_instr_start[lj++] = 0;
+ }
+
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "----------------\n");