From 7bfdb6d18c7bb5792c896a0bf6cf1ad7431630cb Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 1 Mar 2003 14:27:54 +0000 Subject: [PATCH] new i386 emulator core git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@13 c046a42c-6fe2-441c-8c8c-71466251a162 --- op-i386.c | 1097 ++++++++++++++++++++++++++++++++++++++++++++++ opreg_template.h | 103 +++++ 2 files changed, 1200 insertions(+) create mode 100644 op-i386.c create mode 100644 opreg_template.h diff --git a/op-i386.c b/op-i386.c new file mode 100644 index 0000000000..fdd2fa5ade --- /dev/null +++ b/op-i386.c @@ -0,0 +1,1097 @@ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +#ifdef __i386__ +register int T0 asm("esi"); +register int T1 asm("ebx"); +register int A0 asm("edi"); +register struct CPU86State *env asm("ebp"); +#define FORCE_RET() asm volatile ("ret"); +#endif +#ifdef __powerpc__ +register int T0 asm("r24"); +register int T1 asm("r25"); +register int A0 asm("r26"); +register struct CPU86State *env asm("r27"); +#define FORCE_RET() asm volatile ("blr"); +#endif +#ifdef __arm__ +register int T0 asm("r4"); +register int T1 asm("r5"); +register int A0 asm("r6"); +register struct CPU86State *env asm("r7"); +#define FORCE_RET() asm volatile ("mov pc, lr"); +#endif +#ifdef __mips__ +register int T0 asm("s0"); +register int T1 asm("s1"); +register int A0 asm("s2"); +register struct CPU86State *env asm("s3"); +#define FORCE_RET() asm volatile ("jr $31"); +#endif +#ifdef __sparc__ +register int T0 asm("l0"); +register int T1 asm("l1"); +register int A0 asm("l2"); +register struct CPU86State *env asm("l3"); +#define FORCE_RET() asm volatile ("retl ; nop"); +#endif + +#ifndef OPPROTO +#define OPPROTO +#endif + +#define xglue(x, y) x ## y +#define glue(x, y) xglue(x, y) + +#define EAX (env->regs[R_EAX]) +#define ECX (env->regs[R_ECX]) +#define EDX (env->regs[R_EDX]) +#define EBX (env->regs[R_EBX]) +#define ESP (env->regs[R_ESP]) +#define EBP (env->regs[R_EBP]) +#define ESI (env->regs[R_ESI]) +#define EDI (env->regs[R_EDI]) +#define PC (env->pc) +#define DF (env->df) + +#define CC_SRC (env->cc_src) +#define CC_DST (env->cc_dst) +#define CC_OP (env->cc_op) + +extern int __op_param1, __op_param2, __op_param3; +#define PARAM1 ((long)(&__op_param1)) +#define PARAM2 ((long)(&__op_param2)) +#define PARAM3 ((long)(&__op_param3)) + +#include "cpu-i386.h" + +typedef struct CCTable { + int (*compute_c)(void); /* return the C flag */ + int (*compute_z)(void); /* return the Z flag */ + int (*compute_s)(void); /* return the S flag */ + int (*compute_o)(void); /* return the O flag */ + int (*compute_all)(void); /* return all the flags */ +} CCTable; + +uint8_t parity_table[256] = { + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, + 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, +}; + +static int compute_eflags_all(void) +{ + return CC_SRC; +} + +static int compute_eflags_addb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_DST - CC_SRC; + cf = (uint8_t)CC_DST < (uint8_t)src1; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_subb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_SRC; + src2 = CC_SRC - CC_DST; + cf = (uint8_t)src1 < (uint8_t)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_logicb(void) +{ + cf = 0; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = 0; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_incb(void) +{ + int cf, pf, af, zf, sf, of; + int src2; + src1 = CC_DST - 1; + src2 = 1; + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_decb(void) +{ + int cf, pf, af, zf, sf, of; + int src1, src2; + src1 = CC_DST + 1; + src2 = 1; + cf = (uint8_t)src1 < (uint8_t)src2; + pf = parity_table[(uint8_t)CC_DST]; + af = (CC_DST ^ src1 ^ src2) & 0x10; + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = ((src1 ^ src2 ^ -1) & (src1 ^ CC_DST) & 0x80) << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_shlb(void) +{ + cf = CC_SRC; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = 0; /* undefined */ + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_shrb(void) +{ + cf = CC_SRC & 1; + pf = parity_table[(uint8_t)CC_DST]; + af = 0; /* undefined */ + zf = ((uint8_t)CC_DST != 0) << 6; + sf = CC_DST & 0x80; + of = sf << 4; + return cf | pf | af | zf | sf | of; +} + +static int compute_eflags_mul(void) +{ + cf = (CC_SRC != 0); + pf = 0; /* undefined */ + af = 0; /* undefined */ + zf = 0; /* undefined */ + sf = 0; /* undefined */ + of = cf << 11; + return cf | pf | af | zf | sf | of; +} + +CTable cc_table[CC_OP_NB] = { + [CC_OP_DYNAMIC] = { NULL, NULL, NULL }, + [CC_OP_EFLAGS] = { NULL, NULL, NULL }, + +}; + +/* we define the various pieces of code used by the JIT */ + +#define REG EAX +#define REGNAME _EAX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ECX +#define REGNAME _ECX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDX +#define REGNAME _EDX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBX +#define REGNAME _EBX +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESP +#define REGNAME _ESP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EBP +#define REGNAME _EBP +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG ESI +#define REGNAME _ESI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +#define REG EDI +#define REGNAME _EDI +#include "opreg_template.h" +#undef REG +#undef REGNAME + +/* operations */ + +void OPPROTO op_addl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 += T1; + CC_DST = T0; +} + +void OPPROTO op_orl_T0_T1_cc(void) +{ + T0 |= T1; + CC_DST = T0; +} + +void OPPROTO op_adcl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 = T0 + T1 + cc_table[CC_OP].compute_c(); + CC_DST = T0; +} + +void OPPROTO op_sbbl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 = T0 - T1 - cc_table[CC_OP].compute_c(); + CC_DST = T0; +} + +void OPPROTO op_andl_T0_T1_cc(void) +{ + T0 &= T1; + CC_DST = T0; +} + +void OPPROTO op_subl_T0_T1_cc(void) +{ + CC_SRC = T0; + T0 -= T1; + CC_DST = T0; +} + +void OPPROTO op_xorl_T0_T1_cc(void) +{ + T0 ^= T1; + CC_DST = T0; +} + +void OPPROTO op_cmpl_T0_T1_cc(void) +{ + CC_SRC = T0; + CC_DST = T0 - T1; +} + +void OPPROTO op_notl_T0(void) +{ + T0 = ~T0; +} + +void OPPROTO op_negl_T0_cc(void) +{ + CC_SRC = 0; + T0 = -T0; + CC_DST = T0; +} + +void OPPROTO op_incl_T0_cc(void) +{ + T0++; + CC_DST = T0; +} + +void OPPROTO op_decl_T0_cc(void) +{ + T0--; + CC_DST = T0; +} + +void OPPROTO op_testl_T0_T1_cc(void) +{ + CC_SRC = T0; + CC_DST = T0 & T1; +} + +/* shifts */ + +void OPPROTO op_roll_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (32 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLL; + } +} + +void OPPROTO op_rolw_T0_T1_cc(void) +{ + int count; + count = T1 & 0xf; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (16 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLW; + } +} + +void OPPROTO op_rolb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x7; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 << count) | (T0 >> (8 - count)); + CC_DST = T0; + CC_OP = CC_OP_ROLB; + } +} + +void OPPROTO op_rorl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (32 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORB; + } +} + +void OPPROTO op_rorw_T0_T1_cc(void) +{ + int count; + count = T1 & 0xf; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (16 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORW; + } +} + +void OPPROTO op_rorb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x7; + if (count) { + CC_SRC = T0; + T0 = (T0 >> count) | (T0 << (8 - count)); + CC_DST = T0; + CC_OP = CC_OP_RORL; + } +} + +/* modulo 17 table */ +const uint8_t rclw_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, +}; + +/* modulo 9 table */ +const uint8_t rclb_table[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, +}; + +void helper_rcll_T0_T1_cc(void) +{ + int count, res; + + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + res = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)); + if (count > 1) + res |= T0 >> (33 - count); + T0 = res; + CC_DST = T0 ^ CC_SRC; /* O is in bit 31 */ + CC_SRC >>= (32 - count); /* CC is in bit 0 */ + CC_OP = CC_OP_RCLL; + } +} + +void OPPROTO op_rcll_T0_T1_cc(void) +{ + helper_rcll_T0_T1_cc(); +} + +void OPPROTO op_rclw_T0_T1_cc(void) +{ + int count; + count = rclw_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | + (T0 >> (17 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (16 - count); + CC_OP = CC_OP_RCLW; + } +} + +void OPPROTO op_rclb_T0_T1_cc(void) +{ + int count; + count = rclb_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 << count) | (cc_table[CC_OP].compute_c() << (count - 1)) | + (T0 >> (9 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (8 - count); + CC_OP = CC_OP_RCLB; + } +} + +void OPPROTO op_rcrl_T0_T1_cc(void) +{ + int count, res; + count = T1 & 0x1f; + if (count) { + CC_SRC = T0; + res = (T0 >> count) | (cc_table[CC_OP].compute_c() << (32 - count)); + if (count > 1) + res |= T0 << (33 - count); + T0 = res; + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLL; + } +} + +void OPPROTO op_rcrw_T0_T1_cc(void) +{ + int count; + count = rclw_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (16 - count)) | + (T0 << (17 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLW; + } +} + +void OPPROTO op_rcrb_T0_T1_cc(void) +{ + int count; + count = rclb_table[T1 & 0x1f]; + if (count) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = (T0 >> count) | (cc_table[CC_OP].compute_c() << (8 - count)) | + (T0 << (9 - count)); + CC_DST = T0 ^ CC_SRC; + CC_SRC >>= (count - 1); + CC_OP = CC_OP_RCLB; + } +} + +void OPPROTO op_shll_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDL; + } else if (count) { + CC_SRC = T0 >> (32 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_shlw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDW; + } else if (count) { + CC_SRC = T0 >> (16 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_shlb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 << 1; + CC_DST = T0; + CC_OP = CC_OP_ADDB; + } else if (count) { + CC_SRC = T0 >> (8 - count); + T0 = T0 << count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +void OPPROTO op_shrl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRL; + } else if (count) { + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_shrw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + T0 = T0 & 0xffff; + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRW; + } else if (count) { + T0 = T0 & 0xffff; + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_shrb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count == 1) { + T0 = T0 & 0xff; + CC_SRC = T0; + T0 = T0 >> 1; + CC_DST = T0; + CC_OP = CC_OP_SHRB; + } else if (count) { + T0 = T0 & 0xff; + CC_SRC = T0 >> (count - 1); + T0 = T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +void OPPROTO op_sarl_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int32_t)T0 >> (count - 1); + T0 = (int32_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLL; + } +} + +void OPPROTO op_sarw_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int16_t)T0 >> (count - 1); + T0 = (int16_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLW; + } +} + +void OPPROTO op_sarb_T0_T1_cc(void) +{ + int count; + count = T1 & 0x1f; + if (count) { + CC_SRC = (int8_t)T0 >> (count - 1); + T0 = (int8_t)T0 >> count; + CC_DST = T0; + CC_OP = CC_OP_SHLB; + } +} + +/* multiply/divide */ +void OPPROTO op_mulb_AL_T0(void) +{ + unsigned int res; + res = (uint8_t)EAX * (uint8_t)T0; + EAX = (EAX & 0xffff0000) | res; + CC_SRC = (res & 0xff00); +} + +void OPPROTO op_imulb_AL_T0(void) +{ + int res; + res = (int8_t)EAX * (int8_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + CC_SRC = (res != (int8_t)res); +} + +void OPPROTO op_mulw_AX_T0(void) +{ + unsigned int res; + res = (uint16_t)EAX * (uint16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = res >> 16; +} + +void OPPROTO op_imulw_AX_T0(void) +{ + int res; + res = (int16_t)EAX * (int16_t)T0; + EAX = (EAX & 0xffff0000) | (res & 0xffff); + EDX = (EDX & 0xffff0000) | ((res >> 16) & 0xffff); + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_mull_EAX_T0(void) +{ + uint64_t res; + res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = res >> 32; +} + +void OPPROTO op_imull_EAX_T0(void) +{ + int64_t res; + res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0); + EAX = res; + EDX = res >> 32; + CC_SRC = (res != (int32_t)res); +} + +void OPPROTO op_imulw_T0_T1(void) +{ + int res; + res = (int16_t)T0 * (int16_t)T1; + T0 = res; + CC_SRC = (res != (int16_t)res); +} + +void OPPROTO op_imull_T0_T1(void) +{ + int64_t res; + res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T1); + T0 = res; + CC_SRC = (res != (int32_t)res); +} + +/* division, flags are undefined */ +/* XXX: add exceptions for overflow & div by zero */ +void OPPROTO op_divb_AL_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff); + den = (T0 & 0xff); + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_idivb_AL_T0(void) +{ + int num, den, q, r; + + num = (int16_t)EAX; + den = (int8_t)T0; + q = (num / den) & 0xff; + r = (num % den) & 0xff; + EAX = (EAX & 0xffff0000) | (r << 8) | q; +} + +void OPPROTO op_divw_AX_T0(void) +{ + unsigned int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (T0 & 0xffff); + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_idivw_AX_T0(void) +{ + int num, den, q, r; + + num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); + den = (int16_t)T0; + q = (num / den) & 0xffff; + r = (num % den) & 0xffff; + EAX = (EAX & 0xffff0000) | q; + EDX = (EDX & 0xffff0000) | r; +} + +void OPPROTO op_divl_EAX_T0(void) +{ + unsigned int den, q, r; + uint64_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = T0; + q = (num / den); + r = (num % den); + EAX = q; + EDX = r; +} + +void OPPROTO op_idivl_EAX_T0(void) +{ + int den, q, r; + int16_t num; + + num = EAX | ((uint64_t)EDX << 32); + den = (int16_t)T0; + q = (num / den); + r = (num % den); + EAX = q; + EDX = r; +} + +/* constant load */ + +void OPPROTO op1_movl_T0_im(void) +{ + T0 = PARAM1; +} + +void OPPROTO op1_movl_T1_im(void) +{ + T1 = PARAM1; +} + +void OPPROTO op1_movl_A0_im(void) +{ + A0 = PARAM1; +} + +/* memory access */ + +void OPPROTO op_ldub_T0_A0(void) +{ + T0 = ldub((uint8_t *)A0); +} + +void OPPROTO op_ldsb_T0_A0(void) +{ + T0 = ldsb((int8_t *)A0); +} + +void OPPROTO op_lduw_T0_A0(void) +{ + T0 = lduw((uint8_t *)A0); +} + +void OPPROTO op_ldsw_T0_A0(void) +{ + T0 = ldsw((int8_t *)A0); +} + +void OPPROTO op_ldl_T0_A0(void) +{ + T0 = ldl((uint8_t *)A0); +} + +void OPPROTO op_ldub_T1_A0(void) +{ + T1 = ldub((uint8_t *)A0); +} + +void OPPROTO op_ldsb_T1_A0(void) +{ + T1 = ldsb((int8_t *)A0); +} + +void OPPROTO op_lduw_T1_A0(void) +{ + T1 = lduw((uint8_t *)A0); +} + +void OPPROTO op_ldsw_T1_A0(void) +{ + T1 = ldsw((int8_t *)A0); +} + +void OPPROTO op_ldl_T1_A0(void) +{ + T1 = ldl((uint8_t *)A0); +} + +void OPPROTO op_stb_T0_A0(void) +{ + stb((uint8_t *)A0, T0); +} + +void OPPROTO op_stw_T0_A0(void) +{ + stw((uint8_t *)A0, T0); +} + +void OPPROTO op_stl_T0_A0(void) +{ + stl((uint8_t *)A0, T0); +} + +/* flags */ + +void OPPROTO op_set_cc_op(void) +{ + CC_OP = PARAM1; +} + +void OPPROTO op_movl_eflags_T0(void) +{ + CC_SRC = T0; + DF = (T0 & DIRECTION_FLAG) ? -1 : 1; +} + +void OPPROTO op_movb_eflags_T0(void) +{ + int cc_o; + cc_o = cc_table[CC_OP].compute_o(); + CC_SRC = T0 | (cc_o << 11); +} + +void OPPROTO op_movl_T0_eflags(void) +{ + cc_table[CC_OP].compute_eflags(); +} + +void OPPROTO op_cld(void) +{ + DF = 1; +} + +void OPPROTO op_std(void) +{ + DF = -1; +} + +/* jumps */ + +/* indirect jump */ +void OPPROTO op_jmp_T0(void) +{ + PC = T0; +} + +void OPPROTO op_jmp_im(void) +{ + PC = PARAM1; +} + +void OPPROTO op_jne_b(void) +{ + if ((uint8_t)CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO op_jne_w(void) +{ + if ((uint16_t)CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); +} + +void OPPROTO op_jne_l(void) +{ + if (CC_DST != 0) + PC += PARAM1; + else + PC += PARAM2; + FORCE_RET(); /* generate a return so that gcc does not generate an + early function return */ +} + +/* string ops */ + +#define ldul ldl + +#define SUFFIX b +#define SHIFT 0 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +#define SUFFIX w +#define SHIFT 1 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +#define SUFFIX l +#define SHIFT 2 +#include "opstring_template.h" +#undef SUFFIX +#undef SHIFT + +/* sign extend */ + +void OPPROTO op_movsbl_T0_T0(void) +{ + T0 = (int8_t)T0; +} + +void OPPROTO op_movzbl_T0_T0(void) +{ + T0 = (uint8_t)T0; +} + +void OPPROTO op_movswl_T0_T0(void) +{ + T0 = (int16_t)T0; +} + +void OPPROTO op_movzwl_T0_T0(void) +{ + T0 = (uint16_t)T0; +} + +void OPPROTO op_movswl_EAX_AX(void) +{ + EAX = (int16_t)EAX; +} + +void OPPROTO op_movsbw_AX_AL(void) +{ + EAX = (EAX & 0xffff0000) | ((int8_t)EAX & 0xffff); +} + +void OPPROTO op_movslq_EDX_EAX(void) +{ + EDX = (int32_t)EAX >> 31; +} + +void OPPROTO op_movswl_DX_AX(void) +{ + EDX = (EDX & 0xffff0000) | (((int16_t)EAX >> 15) & 0xffff); +} + +/* push/pop */ +/* XXX: add 16 bit operand/16 bit seg variants */ + +void op_pushl_T0(void) +{ + uint32_t offset; + offset = ESP - 4; + stl((void *)offset, T0); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_pushl_T1(void) +{ + uint32_t offset; + offset = ESP - 4; + stl((void *)offset, T1); + /* modify ESP after to handle exceptions correctly */ + ESP = offset; +} + +void op_popl_T0(void) +{ + T0 = ldl((void *)ESP); + ESP += 4; +} + +void op_addl_ESP_im(void) +{ + ESP += PARAM1; +} diff --git a/opreg_template.h b/opreg_template.h new file mode 100644 index 0000000000..6cf188ffed --- /dev/null +++ b/opreg_template.h @@ -0,0 +1,103 @@ +/* templates for various register related operations */ + +void OPPROTO glue(op_movl_A0,REGNAME)(void) +{ + A0 = REG; +} + +void OPPROTO glue(op_addl_A0,REGNAME)(void) +{ + A0 += REG; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void) +{ + A0 += REG << 1; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void) +{ + A0 += REG << 2; +} + +void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void) +{ + A0 += REG << 3; +} + +void OPPROTO glue(op_movl_T0,REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1,REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(op_movh_T0,REGNAME)(void) +{ + T0 = REG >> 8; +} + +void OPPROTO glue(op_movh_T1,REGNAME)(void) +{ + T1 = REG >> 8; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void) +{ + REG = T0; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void) +{ + REG = T1; +} + +void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) +{ + REG = A0; +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff0000) | (T0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff0000) | (T1 & 0xffff); +} + +/* NOTE: A0 high order bits are ignored */ +void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void) +{ + REG = (REG & 0xffff0000) | (A0 & 0xffff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void) +{ + REG = (REG & 0xffffff00) | (T0 & 0xff); +} + +/* NOTE: T0 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void) +{ + REG = (REG & 0xffff00ff) | ((T0 & 0xff) << 8); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void) +{ + REG = (REG & 0xffffff00) | (T1 & 0xff); +} + +/* NOTE: T1 high order bits are ignored */ +void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void) +{ + REG = (REG & 0xffff00ff) | ((T1 & 0xff) << 8); +}