added pusha/popa/rdtsc/bcd ops
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 16 Mar 2003 11:29:31 +0000 (11:29 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 16 Mar 2003 11:29:31 +0000 (11:29 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162

TODO
cpu-i386.h
linux-user/main.c
op-i386.c
translate-i386.c

diff --git a/TODO b/TODO
index 3b04b7d..caeb64d 100644 (file)
--- 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
index a6464ef..40542f2 100644 (file)
@@ -114,7 +114,7 @@ enum {
 };
 
 #ifdef __i386__
-//#define USE_X86LDOUBLE
+#define USE_X86LDOUBLE
 #endif
 
 #ifdef USE_X86LDOUBLE
index 9927b82..6aefe3a 100644 (file)
@@ -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"
            );
index 6bd9de0..6d695ff 100644 (file)
--- 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;
index ad46e13..0dbaa99 100644 (file)
@@ -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;