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;