aboutsummaryrefslogtreecommitdiff
path: root/op-i386.c
diff options
context:
space:
mode:
Diffstat (limited to 'op-i386.c')
-rw-r--r--op-i386.c183
1 files changed, 136 insertions, 47 deletions
diff --git a/op-i386.c b/op-i386.c
index 849e508e20..f7f1a9849e 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -10,7 +10,18 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
+#define bswap32(x) \
+({ \
+ uint32_t __x = (x); \
+ ((uint32_t)( \
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
+})
+
#define NULL 0
+#include <fenv.h>
typedef struct FILE FILE;
extern FILE *logfile;
@@ -18,41 +29,39 @@ extern int loglevel;
extern int fprintf(FILE *, const char *, ...);
#ifdef __i386__
-register int T0 asm("esi");
-register int T1 asm("ebx");
-register int A0 asm("edi");
+register unsigned int T0 asm("ebx");
+register unsigned int T1 asm("esi");
+register unsigned int A0 asm("edi");
register struct CPUX86State *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 unsigned int T0 asm("r24");
+register unsigned int T1 asm("r25");
+register unsigned int A0 asm("r26");
register struct CPUX86State *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 unsigned int T0 asm("r4");
+register unsigned int T1 asm("r5");
+register unsigned int A0 asm("r6");
register struct CPUX86State *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 unsigned int T0 asm("s0");
+register unsigned int T1 asm("s1");
+register unsigned int A0 asm("s2");
register struct CPUX86State *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 unsigned int T0 asm("l0");
+register unsigned int T1 asm("l1");
+register unsigned int A0 asm("l2");
register struct CPUX86State *env asm("l3");
-#define FORCE_RET() asm volatile ("retl ; nop");
#endif
+/* force GCC to generate only one epilog at the end of the function */
+#define FORCE_RET() asm volatile ("");
+
#ifndef OPPROTO
#define OPPROTO
#endif
@@ -267,20 +276,6 @@ void OPPROTO op_orl_T0_T1_cc(void)
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;
@@ -320,12 +315,14 @@ void OPPROTO op_negl_T0_cc(void)
void OPPROTO op_incl_T0_cc(void)
{
+ CC_SRC = cc_table[CC_OP].compute_c();
T0++;
CC_DST = T0;
}
void OPPROTO op_decl_T0_cc(void)
{
+ CC_SRC = cc_table[CC_OP].compute_c();
T0--;
CC_DST = T0;
}
@@ -335,6 +332,11 @@ void OPPROTO op_testl_T0_T1_cc(void)
CC_DST = T0 & T1;
}
+void OPPROTO op_bswapl_T0(void)
+{
+ T0 = bswap32(T0);
+}
+
/* multiply/divide */
void OPPROTO op_mulb_AL_T0(void)
{
@@ -399,7 +401,7 @@ void OPPROTO op_imulw_T0_T1(void)
void OPPROTO op_imull_T0_T1(void)
{
int64_t res;
- res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T1);
+ res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
T0 = res;
CC_SRC = (res != (int32_t)res);
}
@@ -468,10 +470,10 @@ void OPPROTO op_divl_EAX_T0(void)
void OPPROTO op_idivl_EAX_T0(void)
{
int den, q, r;
- int16_t num;
+ int64_t num;
num = EAX | ((uint64_t)EDX << 32);
- den = (int16_t)T0;
+ den = T0;
q = (num / den);
r = (num % den);
EAX = q;
@@ -495,6 +497,16 @@ void OPPROTO op_movl_A0_im(void)
A0 = PARAM1;
}
+void OPPROTO op_addl_A0_im(void)
+{
+ A0 += PARAM1;
+}
+
+void OPPROTO op_andl_A0_ffff(void)
+{
+ A0 = A0 & 0xffff;
+}
+
/* memory access */
void OPPROTO op_ldub_T0_A0(void)
@@ -562,7 +574,17 @@ void OPPROTO op_stl_T0_A0(void)
stl((uint8_t *)A0, T0);
}
-/* jumps */
+/* used for bit operations */
+
+void OPPROTO op_add_bitw_A0_T1(void)
+{
+ A0 += ((int32_t)T1 >> 4) << 1;
+}
+
+void OPPROTO op_add_bitl_A0_T1(void)
+{
+ A0 += ((int32_t)T1 >> 5) << 2;
+}
/* indirect jump */
@@ -938,25 +960,37 @@ CCTable cc_table[CC_OP_NB] = {
[CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
[CC_OP_ADDL] = { compute_all_addl, compute_c_addl },
+ [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb },
+ [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw },
+ [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl },
+
[CC_OP_SUBB] = { compute_all_subb, compute_c_subb },
[CC_OP_SUBW] = { compute_all_subw, compute_c_subw },
[CC_OP_SUBL] = { compute_all_subl, compute_c_subl },
+ [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb },
+ [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw },
+ [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl },
+
[CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
[CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
[CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
- [CC_OP_INCB] = { compute_all_incb, compute_c_incb },
- [CC_OP_INCW] = { compute_all_incw, compute_c_incw },
+ [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
+ [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
[CC_OP_INCL] = { compute_all_incl, compute_c_incl },
- [CC_OP_DECB] = { compute_all_decb, compute_c_incb },
- [CC_OP_DECW] = { compute_all_decw, compute_c_incw },
+ [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
+ [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
[CC_OP_DECL] = { compute_all_decl, compute_c_incl },
- [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
- [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
+ [CC_OP_SHLB] = { compute_all_shlb, compute_c_shll },
+ [CC_OP_SHLW] = { compute_all_shlw, compute_c_shll },
[CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
+
+ [CC_OP_SARB] = { compute_all_sarb, compute_c_shll },
+ [CC_OP_SARW] = { compute_all_sarw, compute_c_shll },
+ [CC_OP_SARL] = { compute_all_sarl, compute_c_shll },
};
/* floating point support */
@@ -1640,6 +1674,41 @@ void OPPROTO op_fcos(void)
helper_fcos();
}
+void OPPROTO op_fnstsw_A0(void)
+{
+ int fpus;
+ fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
+ stw((void *)A0, fpus);
+}
+
+void OPPROTO op_fnstcw_A0(void)
+{
+ stw((void *)A0, env->fpuc);
+}
+
+void OPPROTO op_fldcw_A0(void)
+{
+ int rnd_type;
+ env->fpuc = lduw((void *)A0);
+ /* set rounding mode */
+ switch(env->fpuc & RC_MASK) {
+ default:
+ case RC_NEAR:
+ rnd_type = FE_TONEAREST;
+ break;
+ case RC_DOWN:
+ rnd_type = FE_DOWNWARD;
+ break;
+ case RC_UP:
+ rnd_type = FE_UPWARD;
+ break;
+ case RC_CHOP:
+ rnd_type = FE_TOWARDZERO;
+ break;
+ }
+ fesetround(rnd_type);
+}
+
/* main execution loop */
uint8_t code_gen_buffer[65536];
@@ -1651,9 +1720,15 @@ static const char *cc_op_str[] = {
"ADDB",
"ADDW",
"ADDL",
+ "ADCB",
+ "ADCW",
+ "ADCL",
"SUBB",
"SUBW",
"SUBL",
+ "SBBB",
+ "SBBW",
+ "SBBL",
"LOGICB",
"LOGICW",
"LOGICL",
@@ -1666,6 +1741,9 @@ static const char *cc_op_str[] = {
"SHLB",
"SHLW",
"SHLL",
+ "SARB",
+ "SARW",
+ "SARL",
};
#endif
@@ -1688,13 +1766,24 @@ int cpu_x86_exec(CPUX86State *env1)
for(;;) {
#ifdef DEBUG_EXEC
if (loglevel) {
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= (DF & DIRECTION_FLAG);
fprintf(logfile,
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
- "ESI=%08x ESI=%08X EBP=%08x ESP=%08x\n"
- "CCS=%08x CCD=%08x CCOP=%s\n",
+ "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
+ "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n",
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
- env->cc_src, env->cc_dst, cc_op_str[env->cc_op]);
+ env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
+ eflags & DIRECTION_FLAG ? 'D' : '-',
+ eflags & CC_O ? 'O' : '-',
+ eflags & CC_S ? 'S' : '-',
+ eflags & CC_Z ? 'Z' : '-',
+ eflags & CC_A ? 'A' : '-',
+ eflags & CC_P ? 'P' : '-',
+ eflags & CC_C ? 'C' : '-'
+ );
}
#endif
cpu_x86_gen_code(code_gen_buffer, &code_gen_size, (uint8_t *)env->pc);