aboutsummaryrefslogtreecommitdiff
path: root/translate-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-29 20:04:28 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-29 20:04:28 +0000
commitd0a1ffc9573b15997ecdfbc9ec5ec2fc1403d0f1 (patch)
tree3cf9a2bb49e6104b2bf27904475ff45c9ebf9f84 /translate-i386.c
parentdf0f11a03b5bda2a16b8fd9530b1feeef93da8e5 (diff)
added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@198 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r--translate-i386.c135
1 files changed, 94 insertions, 41 deletions
diff --git a/translate-i386.c b/translate-i386.c
index e682d81393..3802c5e925 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -1273,21 +1273,40 @@ static void gen_pop_T0(DisasContext *s)
}
}
-static void gen_pop_update(DisasContext *s)
+static inline void gen_stack_update(DisasContext *s, int addend)
{
if (s->ss32) {
- if (s->dflag)
- gen_op_addl_ESP_4();
- else
+ if (addend == 2)
gen_op_addl_ESP_2();
+ else if (addend == 4)
+ gen_op_addl_ESP_4();
+ else
+ gen_op_addl_ESP_im(addend);
} else {
- if (s->dflag)
+ if (addend == 2)
+ gen_op_addw_ESP_2();
+ else if (addend == 4)
gen_op_addw_ESP_4();
else
- gen_op_addw_ESP_2();
+ gen_op_addw_ESP_im(addend);
}
}
+static void gen_pop_update(DisasContext *s)
+{
+ gen_stack_update(s, 2 << s->dflag);
+}
+
+static void gen_stack_A0(DisasContext *s)
+{
+ gen_op_movl_A0_ESP();
+ if (!s->ss32)
+ gen_op_andl_A0_ffff();
+ gen_op_movl_T1_A0();
+ if (s->addseg)
+ gen_op_addl_A0_seg(offsetof(CPUX86State,seg_cache[R_SS].base));
+}
+
/* NOTE: wrap around in 16 bit not fully handled */
static void gen_pusha(DisasContext *s)
{
@@ -1957,7 +1976,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
}
break;
case 0xc9: /* leave */
- /* XXX: exception not precise (ESP is update before potential exception) */
+ /* XXX: exception not precise (ESP is updated before potential exception) */
if (s->ss32) {
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_mov_reg_T0[OT_LONG][R_ESP]();
@@ -2453,9 +2472,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break;
}
break;
+ case 0x0c: /* fldenv mem */
+ gen_op_fldenv_A0(s->dflag);
+ break;
case 0x0d: /* fldcw mem */
gen_op_fldcw_A0();
break;
+ case 0x0e: /* fnstenv mem */
+ gen_op_fnstenv_A0(s->dflag);
+ break;
case 0x0f: /* fnstcw mem */
gen_op_fnstcw_A0();
break;
@@ -2467,6 +2492,12 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_fstt_ST0_A0();
gen_op_fpop();
break;
+ case 0x2c: /* frstor mem */
+ gen_op_frstor_A0(s->dflag);
+ break;
+ case 0x2e: /* fnsave mem */
+ gen_op_fnsave_A0(s->dflag);
+ break;
case 0x2f: /* fnstsw mem */
gen_op_fnstsw_A0();
break;
@@ -2672,6 +2703,20 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
goto illegal_op;
}
break;
+ case 0x1d: /* fucomi */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fucomi_ST0_FT0();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x1e: /* fcomi */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fcomi_ST0_FT0();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
case 0x2a: /* fst sti */
gen_op_fmov_STN_ST0(opreg);
break;
@@ -2709,6 +2754,22 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
goto illegal_op;
}
break;
+ case 0x3d: /* fucomip */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fucomi_ST0_FT0();
+ gen_op_fpop();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x3e: /* fcomip */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_fmov_FT0_STN(opreg);
+ gen_op_fcomi_ST0_FT0();
+ gen_op_fpop();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
default:
goto illegal_op;
}
@@ -2901,10 +2962,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val = ldsw(s->pc);
s->pc += 2;
gen_pop_T0(s);
- if (s->ss32)
- gen_op_addl_ESP_im(val + (2 << s->dflag));
- else
- gen_op_addw_ESP_im(val + (2 << s->dflag));
+ gen_stack_update(s, val + (2 << s->dflag));
if (s->dflag == 0)
gen_op_andl_T0_ffff();
gen_op_jmp_T0();
@@ -2919,63 +2977,55 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1;
break;
case 0xca: /* lret im */
- /* XXX: not restartable */
val = ldsw(s->pc);
s->pc += 2;
+ do_lret:
+ gen_stack_A0(s);
/* pop offset */
- gen_pop_T0(s);
+ gen_op_ld_T0_A0[1 + s->dflag]();
if (s->dflag == 0)
gen_op_andl_T0_ffff();
+ /* NOTE: keeping EIP updated is not a problem in case of
+ exception */
gen_op_jmp_T0();
- gen_pop_update(s);
/* pop selector */
- gen_pop_T0(s);
+ gen_op_addl_A0_im(2 << s->dflag);
+ gen_op_ld_T0_A0[1 + s->dflag]();
gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_pop_update(s);
/* add stack offset */
- if (s->ss32)
- gen_op_addl_ESP_im(val);
- else
- gen_op_addw_ESP_im(val);
+ gen_stack_update(s, val + (4 << s->dflag));
s->is_jmp = 1;
break;
case 0xcb: /* lret */
- /* XXX: not restartable */
- /* pop offset */
- gen_pop_T0(s);
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_pop_update(s);
- /* pop selector */
- gen_pop_T0(s);
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_pop_update(s);
- s->is_jmp = 1;
- break;
+ val = 0;
+ goto do_lret;
case 0xcf: /* iret */
if (s->vm86 && s->iopl != 3) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
/* XXX: not restartable */
+ gen_stack_A0(s);
/* pop offset */
- gen_pop_T0(s);
+ gen_op_ld_T0_A0[1 + s->dflag]();
if (s->dflag == 0)
gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_pop_update(s);
+ /* NOTE: keeping EIP updated is not a problem in case of
+ exception */
+ gen_op_jmp_T0();
/* pop selector */
- gen_pop_T0(s);
- gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
- gen_pop_update(s);
+ gen_op_addl_A0_im(2 << s->dflag);
+ gen_op_ld_T0_A0[1 + s->dflag]();
/* pop eflags */
- gen_pop_T0(s);
+ gen_op_addl_A0_im(2 << s->dflag);
+ gen_op_ld_T1_A0[1 + s->dflag]();
+ gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);
+ gen_op_movl_T0_T1();
if (s->dflag) {
gen_op_movl_eflags_T0();
} else {
gen_op_movw_eflags_T0();
}
- gen_pop_update(s);
+ gen_stack_update(s, (6 << s->dflag));
s->cc_op = CC_OP_EFLAGS;
}
s->is_jmp = 1;
@@ -2997,6 +3047,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x9a: /* lcall im */
{
unsigned int selector, offset;
+ /* XXX: not restartable */
ot = dflag ? OT_LONG : OT_WORD;
offset = insn_get(s, ot);
@@ -3613,6 +3664,8 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_cmpxchg8b] = CC_Z,
[INDEX_op_lar] = CC_Z,
[INDEX_op_lsl] = CC_Z,
+ [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
+ [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
};
/* simpler form of an operation if no flags need to be generated */