summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-16 11:29:31 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-16 11:29:31 +0000
commit27362c82e9df7770554943ceda36ec4e5638c49d (patch)
tree88cbf3531a4a4f1bd90452b259ad027351e6b38f
parent55480af80e9ed58b11e9a99da25602468b17ff45 (diff)
downloadqemu-27362c82e9df7770554943ceda36ec4e5638c49d.tar.gz
added pusha/popa/rdtsc/bcd ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--TODO3
-rw-r--r--cpu-i386.h2
-rw-r--r--linux-user/main.c2
-rw-r--r--op-i386.c237
-rw-r--r--translate-i386.c79
5 files changed, 314 insertions, 9 deletions
diff --git a/TODO b/TODO
index 3b04b7dce1..caeb64d56b 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,7 @@
+- daa/das
- optimize translated cache chaining (DLL PLT like system)
+- segment ops (minimal LDT/GDT support for wine)
+- improved 16 bit support
- optimize inverse flags propagation (easy by generating intermediate
micro operation array).
- signals
diff --git a/cpu-i386.h b/cpu-i386.h
index a6464efca4..40542f283e 100644
--- a/cpu-i386.h
+++ b/cpu-i386.h
@@ -114,7 +114,7 @@ enum {
};
#ifdef __i386__
-//#define USE_X86LDOUBLE
+#define USE_X86LDOUBLE
#endif
#ifdef USE_X86LDOUBLE
diff --git a/linux-user/main.c b/linux-user/main.c
index 9927b8256a..6aefe3afb6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -87,7 +87,7 @@ int cpu_x86_inl(int addr)
void usage(void)
{
- printf("gemu version" GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
+ printf("gemu version " GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: gemu [-d] program [arguments...]\n"
"Linux x86 emulator\n"
);
diff --git a/op-i386.c b/op-i386.c
index 6bd9de0155..6d695ff90d 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -628,6 +628,236 @@ void op_addl_ESP_im(void)
ESP += PARAM1;
}
+void op_pushal(void)
+{
+ uint8_t *sp;
+ sp = (void *)(ESP - 32);
+ stl(sp, EDI);
+ stl(sp + 4, ESI);
+ stl(sp + 8, EBP);
+ stl(sp + 12, ESP);
+ stl(sp + 16, EBX);
+ stl(sp + 20, EDX);
+ stl(sp + 24, ECX);
+ stl(sp + 28, EAX);
+ ESP = (unsigned long)sp;
+}
+
+void op_pushaw(void)
+{
+ uint8_t *sp;
+ sp = (void *)(ESP - 16);
+ stw(sp, EDI);
+ stw(sp + 2, ESI);
+ stw(sp + 4, EBP);
+ stw(sp + 6, ESP);
+ stw(sp + 8, EBX);
+ stw(sp + 10, EDX);
+ stw(sp + 12, ECX);
+ stw(sp + 14, EAX);
+ ESP = (unsigned long)sp;
+}
+
+void op_popal(void)
+{
+ uint8_t *sp;
+ sp = (void *)ESP;
+ EDI = ldl(sp);
+ ESI = ldl(sp + 4);
+ EBP = ldl(sp + 8);
+ EBX = ldl(sp + 16);
+ EDX = ldl(sp + 20);
+ ECX = ldl(sp + 24);
+ EAX = ldl(sp + 28);
+ ESP = (unsigned long)sp + 32;
+}
+
+void op_popaw(void)
+{
+ uint8_t *sp;
+ sp = (void *)ESP;
+ EDI = ldl(sp);
+ ESI = ldl(sp + 2);
+ EBP = ldl(sp + 4);
+ EBX = ldl(sp + 8);
+ EDX = ldl(sp + 10);
+ ECX = ldl(sp + 12);
+ EAX = ldl(sp + 14);
+ ESP = (unsigned long)sp + 16;
+}
+
+void op_enterl(void)
+{
+ unsigned int bp, frame_temp, level;
+ uint8_t *sp;
+
+ sp = (void *)ESP;
+ bp = EBP;
+ sp -= 4;
+ stl(sp, bp);
+ frame_temp = (unsigned int)sp;
+ level = PARAM2;
+ if (level) {
+ while (level--) {
+ bp -= 4;
+ sp -= 4;
+ stl(sp, bp);
+ }
+ sp -= 4;
+ stl(sp, frame_temp);
+ }
+ EBP = frame_temp;
+ sp -= PARAM1;
+ ESP = (int)sp;
+}
+
+/* rdtsc */
+#ifndef __i386__
+uint64_t emu_time;
+#endif
+void op_rdtsc(void)
+{
+ uint64_t val;
+#ifdef __i386__
+ asm("rdtsc" : "=A" (val));
+#else
+ /* better than nothing: the time increases */
+ val = emu_time++;
+#endif
+ EAX = val;
+ EDX = val >> 32;
+}
+
+/* bcd */
+
+/* XXX: exception */
+void OPPROTO op_aam(void)
+{
+ int base = PARAM1;
+ int al, ah;
+ al = EAX & 0xff;
+ ah = al / base;
+ al = al % base;
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_DST = al;
+}
+
+void OPPROTO op_aad(void)
+{
+ int base = PARAM1;
+ int al, ah;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+ al = ((ah * base) + al) & 0xff;
+ EAX = (EAX & ~0xffff) | al;
+ CC_DST = al;
+}
+
+void OPPROTO op_aaa(void)
+{
+ int icarry;
+ int al, ah, af;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+
+ icarry = (al > 0xf9);
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al + 6) & 0x0f;
+ ah = (ah + 1 + icarry) & 0xff;
+ eflags |= CC_C | CC_A;
+ } else {
+ eflags &= ~(CC_C | CC_A);
+ al &= 0x0f;
+ }
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_aas(void)
+{
+ int icarry;
+ int al, ah, af;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+ ah = (EAX >> 8) & 0xff;
+
+ icarry = (al < 6);
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al - 6) & 0x0f;
+ ah = (ah - 1 - icarry) & 0xff;
+ eflags |= CC_C | CC_A;
+ } else {
+ eflags &= ~(CC_C | CC_A);
+ al &= 0x0f;
+ }
+ EAX = (EAX & ~0xffff) | al | (ah << 8);
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_daa(void)
+{
+ int al, af, cf;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ cf = eflags & CC_C;
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+
+ eflags = 0;
+ if (((al & 0x0f) > 9 ) || af) {
+ al = (al + 6) & 0xff;
+ eflags |= CC_A;
+ }
+ if ((al > 0x9f) || cf) {
+ al = (al + 0x60) & 0xff;
+ eflags |= CC_C;
+ }
+ EAX = (EAX & ~0xff) | al;
+ /* well, speed is not an issue here, so we compute the flags by hand */
+ eflags |= (al == 0) << 6; /* zf */
+ eflags |= parity_table[al]; /* pf */
+ eflags |= (al & 0x80); /* sf */
+ CC_SRC = eflags;
+}
+
+void OPPROTO op_das(void)
+{
+ int al, al1, af, cf;
+ int eflags;
+
+ eflags = cc_table[CC_OP].compute_all();
+ cf = eflags & CC_C;
+ af = eflags & CC_A;
+ al = EAX & 0xff;
+
+ eflags = 0;
+ al1 = al;
+ if (((al & 0x0f) > 9 ) || af) {
+ eflags |= CC_A;
+ if (al < 6 || cf)
+ eflags |= CC_C;
+ al = (al - 6) & 0xff;
+ }
+ if ((al1 > 0x99) || cf) {
+ al = (al - 0x60) & 0xff;
+ eflags |= CC_C;
+ }
+ EAX = (EAX & ~0xff) | al;
+ /* well, speed is not an issue here, so we compute the flags by hand */
+ eflags |= (al == 0) << 6; /* zf */
+ eflags |= parity_table[al]; /* pf */
+ eflags |= (al & 0x80); /* sf */
+ CC_SRC = eflags;
+}
+
/* flags handling */
/* slow jumps cases (compute x86 flags) */
@@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void)
CC_SRC = eflags;
}
+void OPPROTO op_salc(void)
+{
+ int cf;
+ cf = cc_table[CC_OP].compute_c();
+ EAX = (EAX & ~0xff) | ((-cf) & 0xff);
+}
+
static int compute_all_eflags(void)
{
return CC_SRC;
diff --git a/translate-i386.c b/translate-i386.c
index ad46e1373e..0dbaa99d92 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -1511,6 +1511,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
gen_op_popl_T0();
gen_op_mov_reg_T0[OT_LONG][b & 7]();
break;
+ case 0x60: /* pusha */
+ if (s->dflag)
+ gen_op_pushal();
+ else
+ gen_op_pushaw();
+ break;
+ case 0x61: /* popa */
+ if (s->dflag)
+ gen_op_popal();
+ else
+ gen_op_popaw();
+ break;
case 0x68: /* push Iv */
case 0x6a:
ot = dflag ? OT_LONG : OT_WORD;
@@ -1527,6 +1539,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
gen_op_popl_T0();
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
break;
+ case 0xc8: /* enter */
+ {
+ int level;
+ val = lduw(s->pc);
+ s->pc += 2;
+ level = ldub(s->pc++);
+ level &= 0x1f;
+ gen_op_enterl(val, level);
+ }
+ break;
case 0xc9: /* leave */
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
gen_op_mov_reg_T0[OT_LONG][R_ESP]();
@@ -2485,6 +2507,42 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
s->cc_op = CC_OP_LOGICB + ot;
break;
/************************/
+ /* bcd */
+ case 0x27: /* daa */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_daa();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x2f: /* das */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_das();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x37: /* aaa */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_aaa();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0x3f: /* aas */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_aas();
+ s->cc_op = CC_OP_EFLAGS;
+ break;
+ case 0xd4: /* aam */
+ val = ldub(s->pc++);
+ gen_op_aam(val);
+ s->cc_op = CC_OP_LOGICB;
+ break;
+ case 0xd5: /* aad */
+ val = ldub(s->pc++);
+ gen_op_aad(val);
+ s->cc_op = CC_OP_LOGICB;
+ break;
+ /************************/
/* misc */
case 0x90: /* nop */
break;
@@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
*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;
-
+ 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;
+ case 0xd6: /* salc */
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_salc();
+ break;
+ case 0x1a2: /* rdtsc */
+ gen_op_rdtsc();
+ break;
#if 0
case 0x1a2: /* cpuid */
gen_insn0(OP_ASM);
break;
#endif
default:
- error("unknown opcode %x", b);
+ error("unknown opcode 0x%x", b);
return -1;
}
return (long)s->pc;