many fixes
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 3 Mar 2003 23:23:09 +0000 (23:23 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 3 Mar 2003 23:23:09 +0000 (23:23 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@19 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-i386.h
dyngen.c
linux-user/main.c
op-i386.c
ops_template.h
tests/Makefile
tests/test-i386.c
translate-i386.c

index 9add417..e528f61 100644 (file)
@@ -78,19 +78,27 @@ enum {
     CC_OP_ADDW,
     CC_OP_ADDL,
 
+    CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_ADCW,
+    CC_OP_ADCL,
+
     CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
     CC_OP_SUBW,
     CC_OP_SUBL,
 
+    CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
+    CC_OP_SBBW,
+    CC_OP_SBBL,
+
     CC_OP_LOGICB, /* modify all flags, CC_DST = res */
     CC_OP_LOGICW,
     CC_OP_LOGICL,
 
-    CC_OP_INCB, /* modify all flags except, CC_DST = res */
+    CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
     CC_OP_INCW,
     CC_OP_INCL,
 
-    CC_OP_DECB, /* modify all flags except, CC_DST = res */
+    CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C  */
     CC_OP_DECW,
     CC_OP_DECL,
 
@@ -98,6 +106,10 @@ enum {
     CC_OP_SHLW,
     CC_OP_SHLL,
 
+    CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
+    CC_OP_SARW,
+    CC_OP_SARL,
+
     CC_OP_NB,
 };
 
index ce38dca..f6b102f 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -198,14 +198,10 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
         {
             uint8_t *p;
             p = p_end - 1;
-            /* find ret */
-            while (p > p_start && *p != 0xc3)
-                p--;
-            /* skip double ret */
-            if (p > p_start && p[-1] == 0xc3)
-                p--;
             if (p == p_start)
                 error("empty code for %s", name);
+            if (p[0] != 0xc3)
+                error("ret expected at the end of %s", name);
             copy_size = p - p_start;
         }
         break;
index cdd118f..356d980 100644 (file)
@@ -128,21 +128,21 @@ int main(int argc, char **argv)
     /* Zero out image_info */
     memset(info, 0, sizeof(struct image_info));
 
-    if(elf_exec(filename, argv+1, environ, regs, info) != 0) {
+    if(elf_exec(filename, argv+optind, environ, regs, info) != 0) {
        printf("Error loading %s\n", filename);
        exit(1);
     }
     
-#if 0
-    printf("start_brk   0x%08lx\n" , info->start_brk);
-    printf("end_code    0x%08lx\n" , info->end_code);
-    printf("start_code  0x%08lx\n" , info->start_code);
-    printf("end_data    0x%08lx\n" , info->end_data);
-    printf("start_stack 0x%08lx\n" , info->start_stack);
-    printf("brk         0x%08lx\n" , info->brk);
-    printf("esp         0x%08lx\n" , regs->esp);
-    printf("eip         0x%08lx\n" , regs->eip);
-#endif
+    if (loglevel) {
+        fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
+        fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
+        fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
+        fprintf(logfile, "end_data    0x%08lx\n" , info->end_data);
+        fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
+        fprintf(logfile, "brk         0x%08lx\n" , info->brk);
+        fprintf(logfile, "esp         0x%08lx\n" , regs->esp);
+        fprintf(logfile, "eip         0x%08lx\n" , regs->eip);
+    }
 
     target_set_brk((char *)info->brk);
     syscall_init();
index 849e508..f7f1a98 100644 (file)
--- 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);
index c67fe0f..e7317ea 100644 (file)
@@ -33,7 +33,7 @@ static int glue(compute_all_add, SUFFIX)(void)
     cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
     pf = parity_table[(uint8_t)CC_DST];
     af = (CC_DST ^ src1 ^ src2) & 0x10;
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
     of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
     return cf | pf | af | zf | sf | of;
@@ -47,6 +47,29 @@ static int glue(compute_c_add, SUFFIX)(void)
     return cf;
 }
 
+static int glue(compute_all_adc, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    int src1, src2;
+    src1 = CC_SRC;
+    src2 = CC_DST - CC_SRC - 1;
+    cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_adc, SUFFIX)(void)
+{
+    int src1, cf;
+    src1 = CC_SRC;
+    cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
+    return cf;
+}
+
 static int glue(compute_all_sub, SUFFIX)(void)
 {
     int cf, pf, af, zf, sf, of;
@@ -56,9 +79,9 @@ static int glue(compute_all_sub, SUFFIX)(void)
     cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
     pf = parity_table[(uint8_t)CC_DST];
     af = (CC_DST ^ src1 ^ src2) & 0x10;
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
-    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
     return cf | pf | af | zf | sf | of;
 }
 
@@ -67,7 +90,31 @@ static int glue(compute_c_sub, SUFFIX)(void)
     int src1, src2, cf;
     src1 = CC_SRC;
     src2 = CC_SRC - CC_DST;
-    cf = (DATA_TYPE)src1 < (DATA_TYPE)src1;
+    cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
+    return cf;
+}
+
+static int glue(compute_all_sbb, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    int src1, src2;
+    src1 = CC_SRC;
+    src2 = CC_SRC - CC_DST - 1;
+    cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = (CC_DST ^ src1 ^ src2) & 0x10;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    return cf | pf | af | zf | sf | of;
+}
+
+static int glue(compute_c_sbb, SUFFIX)(void)
+{
+    int src1, src2, cf;
+    src1 = CC_SRC;
+    src2 = CC_SRC - CC_DST - 1;
+    cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
     return cf;
 }
 
@@ -77,7 +124,7 @@ static int glue(compute_all_logic, SUFFIX)(void)
     cf = 0;
     pf = parity_table[(uint8_t)CC_DST];
     af = 0;
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
     of = 0;
     return cf | pf | af | zf | sf | of;
@@ -97,16 +144,18 @@ static int glue(compute_all_inc, SUFFIX)(void)
     cf = CC_SRC;
     pf = parity_table[(uint8_t)CC_DST];
     af = (CC_DST ^ src1 ^ src2) & 0x10;
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
-    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
     return cf | pf | af | zf | sf | of;
 }
 
+#if DATA_BITS == 32
 static int glue(compute_c_inc, SUFFIX)(void)
 {
     return CC_SRC;
 }
+#endif
 
 static int glue(compute_all_dec, SUFFIX)(void)
 {
@@ -117,9 +166,9 @@ static int glue(compute_all_dec, SUFFIX)(void)
     cf = CC_SRC;
     pf = parity_table[(uint8_t)CC_DST];
     af = (CC_DST ^ src1 ^ src2) & 0x10;
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
-    of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
+    of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11;
     return cf | pf | af | zf | sf | of;
 }
 
@@ -129,16 +178,30 @@ static int glue(compute_all_shl, SUFFIX)(void)
     cf = CC_SRC & 1;
     pf = parity_table[(uint8_t)CC_DST];
     af = 0; /* undefined */
-    zf = ((DATA_TYPE)CC_DST != 0) << 6;
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
-    of = sf << 4; /* only meaniful for shr with count == 1 */
+    of = lshift(CC_SRC, 12 - DATA_BITS) & CC_O; /* only meaniful for shr with count == 1 */
     return cf | pf | af | zf | sf | of;
 }
 
+#if DATA_BITS == 32
 static int glue(compute_c_shl, SUFFIX)(void)
 {
     return CC_SRC & 1;
 }
+#endif
+
+static int glue(compute_all_sar, SUFFIX)(void)
+{
+    int cf, pf, af, zf, sf, of;
+    cf = CC_SRC & 1;
+    pf = parity_table[(uint8_t)CC_DST];
+    af = 0; /* undefined */
+    zf = ((DATA_TYPE)CC_DST == 0) << 6;
+    sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
+    of = 0; /* only meaniful for shr with count == 1 */
+    return cf | pf | af | zf | sf | of;
+}
 
 /* various optimized jumps cases */
 
@@ -157,7 +220,7 @@ void OPPROTO glue(op_jb_sub, SUFFIX)(void)
 
 void OPPROTO glue(op_jz_sub, SUFFIX)(void)
 {
-    if ((DATA_TYPE)CC_DST != 0)
+    if ((DATA_TYPE)CC_DST == 0)
         PC = PARAM1;
     else
         PC = PARAM2;
@@ -225,7 +288,7 @@ void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
 
 void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
 {
-    T0 = ((DATA_TYPE)CC_DST != 0);
+    T0 = ((DATA_TYPE)CC_DST == 0);
 }
 
 void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
@@ -275,6 +338,7 @@ void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
             (T0 & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
@@ -290,6 +354,7 @@ void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
             ((T0 >> (DATA_BITS - 1)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
@@ -305,6 +370,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
 #endif
     if (count) {
         eflags = cc_table[CC_OP].compute_all();
+        T0 &= DATA_MASK;
         src = T0;
         res = (T0 << count) | ((eflags & CC_C) << (count - 1));
         if (count > 1)
@@ -315,6 +381,7 @@ void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
             ((src >> (DATA_BITS - count)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
@@ -330,6 +397,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
 #endif
     if (count) {
         eflags = cc_table[CC_OP].compute_all();
+        T0 &= DATA_MASK;
         src = T0;
         res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
         if (count > 1)
@@ -340,6 +408,7 @@ void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
             ((src >> (count - 1)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
@@ -352,11 +421,12 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
         CC_DST = T0;
         CC_OP = CC_OP_ADDB + SHIFT;
     } else if (count) {
-        CC_SRC = T0 >> (DATA_BITS - count);
+        CC_SRC = (DATA_TYPE)T0 >> (DATA_BITS - count);
         T0 = T0 << count;
         CC_DST = T0;
         CC_OP = CC_OP_SHLB + SHIFT;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
@@ -370,6 +440,7 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
         CC_DST = T0;
         CC_OP = CC_OP_SHLB + SHIFT;
     }
+    FORCE_RET();
 }
 
 void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
@@ -381,10 +452,69 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
         CC_SRC =  src >> (count - 1);
         T0 = src >> count;
         CC_DST = T0;
-        CC_OP = CC_OP_SHLB + SHIFT;
+        CC_OP = CC_OP_SARB + SHIFT;
     }
+    FORCE_RET();
 }
 
+/* carry add/sub (we only need to set CC_OP differently) */
+
+void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
+{
+    int cf;
+    cf = cc_table[CC_OP].compute_c();
+    CC_SRC = T0;
+    T0 = T0 + T1 + cf;
+    CC_DST = T0;
+    CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
+}
+
+void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
+{
+    int cf;
+    cf = cc_table[CC_OP].compute_c();
+    CC_SRC = T0;
+    T0 = T0 - T1 - cf;
+    CC_DST = T0;
+    CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
+}
+
+/* bit operations */
+#if DATA_BITS >= 16
+
+void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    CC_SRC = T0 >> count;
+}
+
+void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    CC_SRC = T0 >> count;
+    T0 |= (1 << count);
+}
+
+void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    CC_SRC = T0 >> count;
+    T0 &= ~(1 << count);
+}
+
+void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
+{
+    int count;
+    count = T1 & SHIFT_MASK;
+    CC_SRC = T0 >> count;
+    T0 ^= (1 << count);
+}
+
+#endif
+
 /* string operations */
 /* XXX: maybe use lower level instructions to ease exception handling */
 
@@ -464,8 +594,8 @@ void OPPROTO glue(op_scas, SUFFIX)(void)
 {
     int v;
 
-    v = glue(ldu, SUFFIX)((void *)ESI);
-    ESI += (DF << SHIFT);
+    v = glue(ldu, SUFFIX)((void *)EDI);
+    EDI += (DF << SHIFT);
     CC_SRC = EAX;
     CC_DST = EAX - v;
 }
@@ -476,20 +606,14 @@ void OPPROTO glue(op_repz_scas, SUFFIX)(void)
 
     if (ECX != 0) {
         /* NOTE: the flags are not modified if ECX == 0 */
-#if SHIFT == 0
-        v1 = EAX & 0xff;
-#elif SHIFT == 1
-        v1 = EAX & 0xffff;
-#else
-        v1 = EAX;
-#endif
+        v1 = EAX & DATA_MASK;
         inc = (DF << SHIFT);
         do {
-            v2 = glue(ldu, SUFFIX)((void *)ESI);
+            v2 = glue(ldu, SUFFIX)((void *)EDI);
+            EDI += inc;
+            ECX--;
             if (v1 != v2)
                 break;
-            ESI += inc;
-            ECX--;
         } while (ECX != 0);
         CC_SRC = v1;
         CC_DST = v1 - v2;
@@ -503,20 +627,14 @@ void OPPROTO glue(op_repnz_scas, SUFFIX)(void)
 
     if (ECX != 0) {
         /* NOTE: the flags are not modified if ECX == 0 */
-#if SHIFT == 0
-        v1 = EAX & 0xff;
-#elif SHIFT == 1
-        v1 = EAX & 0xffff;
-#else
-        v1 = EAX;
-#endif
+        v1 = EAX & DATA_MASK;
         inc = (DF << SHIFT);
         do {
-            v2 = glue(ldu, SUFFIX)((void *)ESI);
+            v2 = glue(ldu, SUFFIX)((void *)EDI);
+            EDI += inc;
+            ECX--;
             if (v1 == v2)
                 break;
-            ESI += inc;
-            ECX--;
         } while (ECX != 0);
         CC_SRC = v1;
         CC_DST = v1 - v2;
@@ -543,11 +661,11 @@ void OPPROTO glue(op_repz_cmps, SUFFIX)(void)
         do {
             v1 = glue(ldu, SUFFIX)((void *)ESI);
             v2 = glue(ldu, SUFFIX)((void *)EDI);
-            if (v1 != v2)
-                break;
             ESI += inc;
             EDI += inc;
             ECX--;
+            if (v1 != v2)
+                break;
         } while (ECX != 0);
         CC_SRC = v1;
         CC_DST = v1 - v2;
@@ -563,11 +681,11 @@ void OPPROTO glue(op_repnz_cmps, SUFFIX)(void)
         do {
             v1 = glue(ldu, SUFFIX)((void *)ESI);
             v2 = glue(ldu, SUFFIX)((void *)EDI);
-            if (v1 == v2)
-                break;
             ESI += inc;
             EDI += inc;
             ECX--;
+            if (v1 == v2)
+                break;
         } while (ECX != 0);
         CC_SRC = v1;
         CC_DST = v1 - v2;
index 2c2b059..489e6b5 100644 (file)
@@ -20,7 +20,7 @@ test2: test2.c
 
 # i386 emulation test (dump various opcodes) */
 test-i386: test-i386.c test-i386.h test-i386-shift.h
-       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
+       $(CC) $(CFLAGS) $(LDFLAGS) -static -o $@ $<
 
 test: test-i386
        ./test-i386 > test-i386.ref
index 5fb9c5c..55dd9eb 100644 (file)
 #define CC_S    0x0080
 #define CC_O    0x0800
 
-/* XXX: currently no A flag */
-#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
-
 #define __init_call    __attribute__ ((unused,__section__ (".initcall.init")))
 
 static void *call_start __init_call = NULL;
 
+#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O | CC_A)
+
 #define OP add
 #include "test-i386.h"
 
@@ -67,6 +66,9 @@ static void *call_start __init_call = NULL;
 #define OP1
 #include "test-i386.h"
 
+#undef CC_MASK
+#define CC_MASK (CC_C | CC_P | CC_Z | CC_S | CC_O)
+
 #define OP shl
 #include "test-i386-shift.h"
 
@@ -268,18 +270,148 @@ void test_jcc(void)
     TEST_JCC("jns", 0, 0);
 }
 
+#undef CC_MASK
+#define CC_MASK (CC_O | CC_C)
+
+#define OP mul
+#include "test-i386-muldiv.h"
+
+#define OP imul
+#include "test-i386-muldiv.h"
+
+#undef CC_MASK
+#define CC_MASK (0)
+
+#define OP div
+#include "test-i386-muldiv.h"
+
+#define OP idiv
+#include "test-i386-muldiv.h"
+
+void test_imulw2(int op0, int op1) 
+{
+    int res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm ("push %4\n\t"
+         "popf\n\t"
+         "imulw %w2, %w0\n\t" 
+         "pushf\n\t"
+         "popl %1\n\t"
+         : "=q" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
+           "imulw", s0, s1, res, flags & CC_MASK);
+}
+
+void test_imull2(int op0, int op1) 
+{
+    int res, s1, s0, flags;
+    s0 = op0;
+    s1 = op1;
+    res = s0;
+    flags = 0;
+    asm ("push %4\n\t"
+         "popf\n\t"
+         "imull %2, %0\n\t" 
+         "pushf\n\t"
+         "popl %1\n\t"
+         : "=q" (res), "=g" (flags)
+         : "q" (s1), "0" (res), "1" (flags));
+    printf("%-10s A=%08x B=%08x R=%08x CC=%04x\n",
+           "imull", s0, s1, res, flags & CC_MASK);
+}
+
+void test_mul(void)
+{
+    test_imulb(0x1234561d, 4);
+    test_imulb(3, -4);
+    test_imulb(0x80, 0x80);
+    test_imulb(0x10, 0x10);
+
+    test_imulw(0, 0x1234001d, 45);
+    test_imulw(0, 23, -45);
+    test_imulw(0, 0x8000, 0x8000);
+    test_imulw(0, 0x100, 0x100);
+
+    test_imull(0, 0x1234001d, 45);
+    test_imull(0, 23, -45);
+    test_imull(0, 0x80000000, 0x80000000);
+    test_imull(0, 0x10000, 0x10000);
+
+    test_mulb(0x1234561d, 4);
+    test_mulb(3, -4);
+    test_mulb(0x80, 0x80);
+    test_mulb(0x10, 0x10);
+
+    test_mulw(0, 0x1234001d, 45);
+    test_mulw(0, 23, -45);
+    test_mulw(0, 0x8000, 0x8000);
+    test_mulw(0, 0x100, 0x100);
+
+    test_mull(0, 0x1234001d, 45);
+    test_mull(0, 23, -45);
+    test_mull(0, 0x80000000, 0x80000000);
+    test_mull(0, 0x10000, 0x10000);
+
+    test_imulw2(0x1234001d, 45);
+    test_imulw2(23, -45);
+    test_imulw2(0x8000, 0x8000);
+    test_imulw2(0x100, 0x100);
+
+    test_imull2(0x1234001d, 45);
+    test_imull2(23, -45);
+    test_imull2(0x80000000, 0x80000000);
+    test_imull2(0x10000, 0x10000);
+
+    test_idivb(0x12341678, 0x127e);
+    test_idivb(0x43210123, -5);
+    test_idivb(0x12340004, -1);
+
+    test_idivw(0, 0x12345678, 12347);
+    test_idivw(0, -23223, -45);
+    test_idivw(0, 0x12348000, -1);
+    test_idivw(0x12343, 0x12345678, 0x81238567);
+
+    test_idivl(0, 0x12345678, 12347);
+    test_idivl(0, -233223, -45);
+    test_idivl(0, 0x80000000, -1);
+    test_idivl(0x12343, 0x12345678, 0x81234567);
+
+    test_divb(0x12341678, 0x127e);
+    test_divb(0x43210123, -5);
+    test_divb(0x12340004, -1);
+
+    test_divw(0, 0x12345678, 12347);
+    test_divw(0, -23223, -45);
+    test_divw(0, 0x12348000, -1);
+    test_divw(0x12343, 0x12345678, 0x81238567);
+
+    test_divl(0, 0x12345678, 12347);
+    test_divl(0, -233223, -45);
+    test_divl(0, 0x80000000, -1);
+    test_divl(0x12343, 0x12345678, 0x81234567);
+}
+
+
 static void *call_end __init_call = NULL;
 
 int main(int argc, char **argv)
 {
     void **ptr;
     void (*func)(void);
+
+    test_mul();
+#if 0
     ptr = &call_start + 1;
     while (*ptr != NULL) {
         func = *ptr++;
         func();
     }
-    test_lea();
     test_jcc();
+    test_lea();
+#endif
     return 0;
 }
index 20a8039..f145a54 100644 (file)
@@ -27,7 +27,9 @@ static void error(const char *fmt, ...)
     va_list ap;
 
     va_start(ap, fmt);
+    fprintf(stderr, "\n");
     vfprintf(stderr, fmt, ap);
+    fprintf(stderr, "\n");
     va_end(ap);
     exit(1);
 }
@@ -98,42 +100,13 @@ enum {
     OR_EBP,
     OR_ESI,
     OR_EDI,
-
-    /* I386 float registers */
-    OR_ST0,
-    OR_ST1,
-    OR_ST2,
-    OR_ST3,
-    OR_ST4,
-    OR_ST5,
-    OR_ST6,
-    OR_ST7,
     OR_TMP0,    /* temporary operand register */
     OR_TMP1,
     OR_A0, /* temporary register used when doing address evaluation */
-    OR_EFLAGS,  /* cpu flags */
-    OR_ITMP0, /* used for byte/word insertion */
-    OR_ITMP1, /* used for byte/word insertion */
-    OR_ITMP2, /* used for byte/word insertion */
-    OR_FTMP0, /* float temporary */
-    OR_DF,    /* D flag, for string ops */
     OR_ZERO, /* fixed zero register */
-    OR_IM, /* dummy immediate value register */
     NB_OREGS,
 };
 
-#if 0
-static const double tab_const[7] = {
-    1.0, 
-    3.32192809488736234789, /* log2(10) */
-    M_LOG2E,
-    M_PI,
-    0.30102999566398119521, /* log10(2) */
-    M_LN2,
-    0.0
-};
-#endif
-
 typedef void (GenOpFunc)(void);
 typedef void (GenOpFunc1)(long);
 typedef void (GenOpFunc2)(long, long);
@@ -354,14 +327,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = {
 static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
     gen_op_addl_T0_T1_cc,
     gen_op_orl_T0_T1_cc,
-    gen_op_adcl_T0_T1_cc,
-    gen_op_sbbl_T0_T1_cc,
+    NULL,
+    NULL,
     gen_op_andl_T0_T1_cc,
     gen_op_subl_T0_T1_cc,
     gen_op_xorl_T0_T1_cc,
     gen_op_cmpl_T0_T1_cc,
 };
 
+static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
+    [OT_BYTE] = {
+        gen_op_adcb_T0_T1_cc,
+        gen_op_sbbb_T0_T1_cc,
+    },
+    [OT_WORD] = {
+        gen_op_adcw_T0_T1_cc,
+        gen_op_sbbw_T0_T1_cc,
+    },
+    [OT_LONG] = {
+        gen_op_adcl_T0_T1_cc,
+        gen_op_sbbl_T0_T1_cc,
+    },
+};
+
 static const int cc_op_arithb[8] = {
     CC_OP_ADDB,
     CC_OP_LOGICB,
@@ -406,6 +394,21 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
     },
 };
 
+static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
+    [0] = {
+        gen_op_btw_T0_T1_cc,
+        gen_op_btsw_T0_T1_cc,
+        gen_op_btrw_T0_T1_cc,
+        gen_op_btcw_T0_T1_cc,
+    },
+    [1] = {
+        gen_op_btl_T0_T1_cc,
+        gen_op_btsl_T0_T1_cc,
+        gen_op_btrl_T0_T1_cc,
+        gen_op_btcl_T0_T1_cc,
+    },
+};
+
 static GenOpFunc *gen_op_lds_T0_A0[3] = {
     gen_op_ldsb_T0_A0,
     gen_op_ldsw_T0_A0,
@@ -644,18 +647,23 @@ static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
         gen_op_mov_TN_reg[ot][0][d]();
     if (s != OR_TMP1)
         gen_op_mov_TN_reg[ot][1][s]();
-    if ((op == OP_ADCL || op == OP_SBBL) && s1->cc_op != CC_OP_DYNAMIC)
-        gen_op_set_cc_op(s1->cc_op);
-    gen_op_arith_T0_T1_cc[op]();
+    if (op == OP_ADCL || op == OP_SBBL) {
+        if (s1->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s1->cc_op);
+        gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
+        s1->cc_op = CC_OP_DYNAMIC;
+    } else {
+        gen_op_arith_T0_T1_cc[op]();
+        s1->cc_op = cc_op_arithb[op] + ot;
+    }
     if (d != OR_TMP0 && op != OP_CMPL)
         gen_op_mov_reg_T0[ot][d]();
-    s1->cc_op = cc_op_arithb[op] + ot;
 }
 
 static void gen_opi(DisasContext *s1, int op, int ot, int d, int c)
 {
     gen_op_movl_T1_im(c);
-    gen_op(s1, op, ot, d, OR_TMP0);
+    gen_op(s1, op, ot, d, OR_TMP1);
 }
 
 static void gen_inc(DisasContext *s1, int ot, int d, int c)
@@ -664,10 +672,13 @@ static void gen_inc(DisasContext *s1, int ot, int d, int c)
         gen_op_mov_TN_reg[ot][0][d]();
     if (s1->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(s1->cc_op);
-    if (c > 0)
+    if (c > 0) {
         gen_op_incl_T0_cc();
-    else
+        s1->cc_op = CC_OP_INCB + ot;
+    } else {
         gen_op_decl_T0_cc();
+        s1->cc_op = CC_OP_DECB + ot;
+    }
     if (d != OR_TMP0)
         gen_op_mov_reg_T0[ot][d]();
 }
@@ -678,20 +689,12 @@ static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
         gen_op_mov_TN_reg[ot][0][d]();
     if (s != OR_TMP1)
         gen_op_mov_TN_reg[ot][1][s]();
-    switch(op) {
-    case OP_ROL:
-    case OP_ROR:
-    case OP_RCL:
-    case OP_RCR:
-        /* only C and O are modified, so we must update flags dynamically */
-        if (s1->cc_op != CC_OP_DYNAMIC)
-            gen_op_set_cc_op(s1->cc_op);
-        gen_op_shift_T0_T1_cc[ot][op]();
-        break;
-    default:
-        gen_op_shift_T0_T1_cc[ot][op]();
-        break;
-    }
+    /* for zero counts, flags are not updated, so must do it dynamically */
+    if (s1->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s1->cc_op);
+
+    gen_op_shift_T0_T1_cc[ot][op]();
+
     if (d != OR_TMP0)
         gen_op_mov_reg_T0[ot][d]();
     s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
@@ -785,12 +788,65 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
             }
             gen_op_addl_A0_reg_sN[scale][reg2]();
         }
-        opreg = OR_A0;
     } else {
-        fprintf(stderr, "16 bit addressing not supported\n");
-        disp = 0;
-        opreg = 0;
+        switch (mod) {
+        case 0:
+            if (rm == 6) {
+                disp = lduw(s->pc);
+                s->pc += 2;
+                gen_op_movl_A0_im(disp);
+                goto no_rm;
+            } else {
+                disp = 0;
+            }
+            break;
+        case 1:
+            disp = (int8_t)ldub(s->pc++);
+            break;
+        default:
+        case 2:
+            disp = lduw(s->pc);
+            s->pc += 2;
+            break;
+        }
+        switch(rm) {
+        case 0:
+            gen_op_movl_A0_reg[R_EBX]();
+            gen_op_addl_A0_reg_sN[0][R_ESI]();
+            break;
+        case 1:
+            gen_op_movl_A0_reg[R_EBX]();
+            gen_op_addl_A0_reg_sN[0][R_EDI]();
+            break;
+        case 2:
+            gen_op_movl_A0_reg[R_EBP]();
+            gen_op_addl_A0_reg_sN[0][R_ESI]();
+            break;
+        case 3:
+            gen_op_movl_A0_reg[R_EBP]();
+            gen_op_addl_A0_reg_sN[0][R_EDI]();
+            break;
+        case 4:
+            gen_op_movl_A0_reg[R_ESI]();
+            break;
+        case 5:
+            gen_op_movl_A0_reg[R_EDI]();
+            break;
+        case 6:
+            gen_op_movl_A0_reg[R_EBP]();
+            break;
+        default:
+        case 7:
+            gen_op_movl_A0_reg[R_EBX]();
+            break;
+        }
+        if (disp != 0)
+            gen_op_addl_A0_im(disp);
+        gen_op_andl_A0_ffff();
+    no_rm: ;
     }
+    opreg = OR_A0;
+    disp = 0;
     *reg_ptr = opreg;
     *offset_ptr = disp;
 }
@@ -870,6 +926,12 @@ static void gen_jcc(DisasContext *s, int b, int val)
     case CC_OP_ADDB:
     case CC_OP_ADDW:
     case CC_OP_ADDL:
+    case CC_OP_ADCB:
+    case CC_OP_ADCW:
+    case CC_OP_ADCL:
+    case CC_OP_SBBB:
+    case CC_OP_SBBW:
+    case CC_OP_SBBL:
     case CC_OP_LOGICB:
     case CC_OP_LOGICW:
     case CC_OP_LOGICL:
@@ -882,6 +944,9 @@ static void gen_jcc(DisasContext *s, int b, int val)
     case CC_OP_SHLB:
     case CC_OP_SHLW:
     case CC_OP_SHLL:
+    case CC_OP_SARB:
+    case CC_OP_SARW:
+    case CC_OP_SARL:
         switch(jcc_op) {
         case JCC_Z:
             func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
@@ -1284,11 +1349,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
             gen_inc(s, ot, OR_TMP0, 1);
             if (mod != 3)
                 gen_op_st_T0_A0[ot]();
+            else
+                gen_op_mov_reg_T0[ot][rm]();
             break;
         case 1: /* dec Ev */
             gen_inc(s, ot, OR_TMP0, -1);
             if (mod != 3)
                 gen_op_st_T0_A0[ot]();
+            else
+                gen_op_mov_reg_T0[ot][rm]();
             break;
         case 2: /* call Ev */
             gen_op_movl_T1_im((long)s->pc);
@@ -1359,7 +1428,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
         reg = ((modrm >> 3) & 7) + OR_EAX;
-        
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
         if (b == 0x69) {
             val = insn_get(s, ot);
@@ -1372,9 +1440,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         }
 
         if (ot == OT_LONG) {
-            op_imull_T0_T1();
+            gen_op_imull_T0_T1();
         } else {
-            op_imulw_T0_T1();
+            gen_op_imulw_T0_T1();
         }
         gen_op_mov_reg_T0[ot][reg]();
         s->cc_op = CC_OP_MUL;
@@ -1522,7 +1590,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
             offset_addr = insn_get(s, OT_LONG);
         else
             offset_addr = insn_get(s, OT_WORD);
-            
+        gen_op_movl_A0_im(offset_addr);
         if ((b & 2) == 0) {
             gen_op_ld_T0_A0[ot]();
             gen_op_mov_reg_T0[ot][R_EAX]();
@@ -1717,17 +1785,19 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
                     break;
                 }
                 break;
-#if 0
+            case 0x0d: /* fldcw mem */
+                gen_op_fldcw_A0();
+                break;
+            case 0x0f: /* fnstcw mem */
+                gen_op_fnstcw_A0();
+                break;
             case 0x2f: /* fnstsw mem */
-                gen_insn3(OP_FNSTS, OR_TMP0, OR_ZERO, OR_ZERO);
-                gen_st(OP_STW, OR_TMP0, reg_addr, offset_addr);
+                gen_op_fnstsw_A0();
                 break;
-
             case 0x3c: /* fbld */
             case 0x3e: /* fbstp */
                 error("float BCD not hanlded");
                 return -1;
-#endif
             case 0x3d: /* fildll */
                 gen_op_fpush();
                 gen_op_fildll_ST0_A0();
@@ -1737,7 +1807,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
                 gen_op_fpop();
                 break;
             default:
-                error("unhandled memory FP\n");
+                error("unhandled memory FP [op=0x%02x]\n", op);
                 return -1;
             }
         } else {
@@ -1987,11 +2057,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         else
             ot = dflag ? OT_LONG : OT_WORD;
         if (prefixes & PREFIX_REPNZ) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
             gen_op_scas[6 + ot]();
+            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
         } else if (prefixes & PREFIX_REPZ) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
             gen_op_scas[3 + ot]();
+            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
         } else {
             gen_op_scas[ot]();
+            s->cc_op = CC_OP_SUBB + ot;
         }
         break;
 
@@ -2002,11 +2079,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         else
             ot = dflag ? OT_LONG : OT_WORD;
         if (prefixes & PREFIX_REPNZ) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
             gen_op_cmps[6 + ot]();
+            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
         } else if (prefixes & PREFIX_REPZ) {
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
             gen_op_cmps[3 + ot]();
+            s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
         } else {
             gen_op_cmps[ot]();
+            s->cc_op = CC_OP_SUBB + ot;
         }
         break;
         
@@ -2187,6 +2271,74 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         break;
 
         /************************/
+        /* bit operations */
+    case 0x1ba: /* bt/bts/btr/btc Gv, im */
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub(s->pc++);
+        op = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        rm = modrm & 7;
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_ld_T0_A0[ot]();
+        } else {
+            gen_op_mov_TN_reg[ot][0][rm]();
+        }
+        /* load shift */
+        val = ldub(s->pc++);
+        gen_op_movl_T1_im(val);
+        if (op < 4)
+            return -1;
+        op -= 4;
+        gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
+        s->cc_op = CC_OP_SHLB + ot;
+        if (op != 0) {
+            if (mod != 3)
+                gen_op_st_T0_A0[ot]();
+            else
+                gen_op_mov_reg_T0[ot][rm]();
+        }
+        break;
+    case 0x1a3: /* bt Gv, Ev */
+        op = 0;
+        goto do_btx;
+    case 0x1ab: /* bts */
+        op = 1;
+        goto do_btx;
+    case 0x1b3: /* btr */
+        op = 2;
+        goto do_btx;
+    case 0x1bb: /* btc */
+        op = 3;
+    do_btx:
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub(s->pc++);
+        reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        rm = modrm & 7;
+        gen_op_mov_TN_reg[OT_LONG][1][reg]();
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            /* specific case: we need to add a displacement */
+            if (ot == OT_WORD)
+                gen_op_add_bitw_A0_T1();
+            else
+                gen_op_add_bitl_A0_T1();
+            gen_op_ld_T0_A0[ot]();
+        } else {
+            gen_op_mov_TN_reg[ot][0][rm]();
+        }
+        gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
+        s->cc_op = CC_OP_SHLB + ot;
+        if (op != 0) {
+            if (mod != 3)
+                gen_op_st_T0_A0[ot]();
+            else
+                gen_op_mov_reg_T0[ot][rm]();
+        }
+        break;
+
+        /************************/
         /* misc */
     case 0x90: /* nop */
         break;
@@ -2206,6 +2358,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start, int *is_jmp_ptr)
         gen_op_into((long)pc_start, (long)s->pc);
         *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;
+      
 #if 0
     case 0x1a2: /* cpuid */
         gen_insn0(OP_ASM);