mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-25 15:14:31 +00:00
added pusha/popa/rdtsc/bcd ops
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@27 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
55480af80e
commit
27362c82e9
3
TODO
3
TODO
@ -1,4 +1,7 @@
|
|||||||
|
- daa/das
|
||||||
- optimize translated cache chaining (DLL PLT like system)
|
- 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
|
- optimize inverse flags propagation (easy by generating intermediate
|
||||||
micro operation array).
|
micro operation array).
|
||||||
- signals
|
- signals
|
||||||
|
@ -114,7 +114,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
//#define USE_X86LDOUBLE
|
#define USE_X86LDOUBLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_X86LDOUBLE
|
#ifdef USE_X86LDOUBLE
|
||||||
|
@ -87,7 +87,7 @@ int cpu_x86_inl(int addr)
|
|||||||
|
|
||||||
void usage(void)
|
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"
|
"usage: gemu [-d] program [arguments...]\n"
|
||||||
"Linux x86 emulator\n"
|
"Linux x86 emulator\n"
|
||||||
);
|
);
|
||||||
|
237
op-i386.c
237
op-i386.c
@ -628,6 +628,236 @@ void op_addl_ESP_im(void)
|
|||||||
ESP += PARAM1;
|
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 */
|
/* flags handling */
|
||||||
|
|
||||||
/* slow jumps cases (compute x86 flags) */
|
/* slow jumps cases (compute x86 flags) */
|
||||||
@ -836,6 +1066,13 @@ void OPPROTO op_cmc(void)
|
|||||||
CC_SRC = eflags;
|
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)
|
static int compute_all_eflags(void)
|
||||||
{
|
{
|
||||||
return CC_SRC;
|
return CC_SRC;
|
||||||
|
@ -1511,6 +1511,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
|
|||||||
gen_op_popl_T0();
|
gen_op_popl_T0();
|
||||||
gen_op_mov_reg_T0[OT_LONG][b & 7]();
|
gen_op_mov_reg_T0[OT_LONG][b & 7]();
|
||||||
break;
|
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 0x68: /* push Iv */
|
||||||
case 0x6a:
|
case 0x6a:
|
||||||
ot = dflag ? OT_LONG : OT_WORD;
|
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_op_popl_T0();
|
||||||
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
|
gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
|
||||||
break;
|
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 */
|
case 0xc9: /* leave */
|
||||||
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
|
||||||
gen_op_mov_reg_T0[OT_LONG][R_ESP]();
|
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;
|
s->cc_op = CC_OP_LOGICB + ot;
|
||||||
break;
|
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 */
|
/* misc */
|
||||||
case 0x90: /* nop */
|
case 0x90: /* nop */
|
||||||
break;
|
break;
|
||||||
@ -2505,19 +2563,26 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
|
|||||||
*is_jmp_ptr = 1;
|
*is_jmp_ptr = 1;
|
||||||
break;
|
break;
|
||||||
case 0x1c8 ... 0x1cf: /* bswap reg */
|
case 0x1c8 ... 0x1cf: /* bswap reg */
|
||||||
reg = b & 7;
|
reg = b & 7;
|
||||||
gen_op_mov_TN_reg[OT_LONG][0][reg]();
|
gen_op_mov_TN_reg[OT_LONG][0][reg]();
|
||||||
gen_op_bswapl_T0();
|
gen_op_bswapl_T0();
|
||||||
gen_op_mov_reg_T0[OT_LONG][reg]();
|
gen_op_mov_reg_T0[OT_LONG][reg]();
|
||||||
break;
|
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
|
#if 0
|
||||||
case 0x1a2: /* cpuid */
|
case 0x1a2: /* cpuid */
|
||||||
gen_insn0(OP_ASM);
|
gen_insn0(OP_ASM);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
error("unknown opcode %x", b);
|
error("unknown opcode 0x%x", b);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return (long)s->pc;
|
return (long)s->pc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user