added cmov instruction


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@32 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/TODO b/TODO
index 5602097..1a7bac5 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,3 @@
-- segment ops (minimal LDT/GDT support for wine)
 - optimize translated cache chaining (DLL PLT like system)
 - improved 16 bit support 
 - optimize inverse flags propagation (easy by generating intermediate
diff --git a/opreg_template.h b/opreg_template.h
index 6cf188f..d6453f9 100644
--- a/opreg_template.h
+++ b/opreg_template.h
@@ -60,6 +60,19 @@
     REG = A0;
 }
 
+/* mov T1 to REG if T0 is true */
+void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
+{
+    if (T0)
+        REG = (REG & 0xffff0000) | (T1 & 0xffff);
+}
+
+void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
+{
+    if (T0)
+        REG = T1;
+}
+
 /* NOTE: T0 high order bits are ignored */
 void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
 {
diff --git a/ops_template.h b/ops_template.h
index 60bdbe5..8905d90 100644
--- a/ops_template.h
+++ b/ops_template.h
@@ -385,6 +385,7 @@
 void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
 {
     int count, src;
+    /* XXX: testing */
     count = T1 & SHIFT_MASK;
     if (count) {
         CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
diff --git a/tests/test-i386.c b/tests/test-i386.c
index 907c44e..86aa949 100644
--- a/tests/test-i386.c
+++ b/tests/test-i386.c
@@ -3,6 +3,8 @@
 #include <inttypes.h>
 #include <math.h>
 
+#define TEST_CMOV 0
+
 #define xglue(x, y) x ## y
 #define glue(x, y) xglue(x, y)
 #define stringify(s)	tostring(s)
@@ -225,79 +227,99 @@
 
 #define TEST_JCC(JCC, v1, v2)\
 {\
+    int res;\
     asm("movl $1, %0\n\t"\
         "cmpl %2, %1\n\t"\
-        JCC " 1f\n\t"\
+        "j" JCC " 1f\n\t"\
         "movl $0, %0\n\t"\
         "1:\n\t"\
         : "=r" (res)\
         : "r" (v1), "r" (v2));\
-    printf("%-10s %d\n", JCC, res);\
+    printf("%-10s %d\n", "j" JCC, res);\
+\
+    asm("movl $0, %0\n\t"\
+        "cmpl %2, %1\n\t"\
+        "set" JCC " %b0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2));\
+    printf("%-10s %d\n", "set" JCC, res);\
+ if (TEST_CMOV) {\
+    asm("movl $0x12345678, %0\n\t"\
+        "cmpl %2, %1\n\t"\
+        "cmov" JCC "l %3, %0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2), "m" (1));\
+        printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\
+    asm("movl $0x12345678, %0\n\t"\
+        "cmpl %2, %1\n\t"\
+        "cmov" JCC "w %w3, %w0\n\t"\
+        : "=r" (res)\
+        : "r" (v1), "r" (v2), "r" (1));\
+        printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\
+ } \
 }
 
 /* various jump tests */
 void test_jcc(void)
 {
-    int res;
+    TEST_JCC("ne", 1, 1);
+    TEST_JCC("ne", 1, 0);
 
-    TEST_JCC("jne", 1, 1);
-    TEST_JCC("jne", 1, 0);
+    TEST_JCC("e", 1, 1);
+    TEST_JCC("e", 1, 0);
 
-    TEST_JCC("je", 1, 1);
-    TEST_JCC("je", 1, 0);
+    TEST_JCC("l", 1, 1);
+    TEST_JCC("l", 1, 0);
+    TEST_JCC("l", 1, -1);
 
-    TEST_JCC("jl", 1, 1);
-    TEST_JCC("jl", 1, 0);
-    TEST_JCC("jl", 1, -1);
+    TEST_JCC("le", 1, 1);
+    TEST_JCC("le", 1, 0);
+    TEST_JCC("le", 1, -1);
 
-    TEST_JCC("jle", 1, 1);
-    TEST_JCC("jle", 1, 0);
-    TEST_JCC("jle", 1, -1);
+    TEST_JCC("ge", 1, 1);
+    TEST_JCC("ge", 1, 0);
+    TEST_JCC("ge", -1, 1);
 
-    TEST_JCC("jge", 1, 1);
-    TEST_JCC("jge", 1, 0);
-    TEST_JCC("jge", -1, 1);
+    TEST_JCC("g", 1, 1);
+    TEST_JCC("g", 1, 0);
+    TEST_JCC("g", 1, -1);
 
-    TEST_JCC("jg", 1, 1);
-    TEST_JCC("jg", 1, 0);
-    TEST_JCC("jg", 1, -1);
+    TEST_JCC("b", 1, 1);
+    TEST_JCC("b", 1, 0);
+    TEST_JCC("b", 1, -1);
 
-    TEST_JCC("jb", 1, 1);
-    TEST_JCC("jb", 1, 0);
-    TEST_JCC("jb", 1, -1);
+    TEST_JCC("be", 1, 1);
+    TEST_JCC("be", 1, 0);
+    TEST_JCC("be", 1, -1);
 
-    TEST_JCC("jbe", 1, 1);
-    TEST_JCC("jbe", 1, 0);
-    TEST_JCC("jbe", 1, -1);
+    TEST_JCC("ae", 1, 1);
+    TEST_JCC("ae", 1, 0);
+    TEST_JCC("ae", 1, -1);
 
-    TEST_JCC("jae", 1, 1);
-    TEST_JCC("jae", 1, 0);
-    TEST_JCC("jae", 1, -1);
-
-    TEST_JCC("ja", 1, 1);
-    TEST_JCC("ja", 1, 0);
-    TEST_JCC("ja", 1, -1);
+    TEST_JCC("a", 1, 1);
+    TEST_JCC("a", 1, 0);
+    TEST_JCC("a", 1, -1);
 
 
-    TEST_JCC("jp", 1, 1);
-    TEST_JCC("jp", 1, 0);
+    TEST_JCC("p", 1, 1);
+    TEST_JCC("p", 1, 0);
 
-    TEST_JCC("jnp", 1, 1);
-    TEST_JCC("jnp", 1, 0);
+    TEST_JCC("np", 1, 1);
+    TEST_JCC("np", 1, 0);
 
-    TEST_JCC("jo", 0x7fffffff, 0);
-    TEST_JCC("jo", 0x7fffffff, -1);
+    TEST_JCC("o", 0x7fffffff, 0);
+    TEST_JCC("o", 0x7fffffff, -1);
 
-    TEST_JCC("jno", 0x7fffffff, 0);
-    TEST_JCC("jno", 0x7fffffff, -1);
+    TEST_JCC("no", 0x7fffffff, 0);
+    TEST_JCC("no", 0x7fffffff, -1);
 
-    TEST_JCC("js", 0, 1);
-    TEST_JCC("js", 0, -1);
-    TEST_JCC("js", 0, 0);
+    TEST_JCC("s", 0, 1);
+    TEST_JCC("s", 0, -1);
+    TEST_JCC("s", 0, 0);
 
-    TEST_JCC("jns", 0, 1);
-    TEST_JCC("jns", 0, -1);
-    TEST_JCC("jns", 0, 0);
+    TEST_JCC("ns", 0, 1);
+    TEST_JCC("ns", 0, -1);
+    TEST_JCC("ns", 0, 0);
 }
 
 #undef CC_MASK
diff --git a/translate-i386.c b/translate-i386.c
index 7737dc1..9bf7f56 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -44,19 +44,6 @@
 extern FILE *logfile;
 extern int loglevel;
 
-/* supress that */
-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);
-}
-
 #define PREFIX_REPZ 1
 #define PREFIX_REPNZ 2
 #define PREFIX_LOCK 4
@@ -352,6 +339,29 @@
     },
 };
 
+static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = {
+    [0] = {
+        gen_op_cmovw_EAX_T1_T0,
+        gen_op_cmovw_ECX_T1_T0,
+        gen_op_cmovw_EDX_T1_T0,
+        gen_op_cmovw_EBX_T1_T0,
+        gen_op_cmovw_ESP_T1_T0,
+        gen_op_cmovw_EBP_T1_T0,
+        gen_op_cmovw_ESI_T1_T0,
+        gen_op_cmovw_EDI_T1_T0,
+    },
+    [1] = {
+        gen_op_cmovl_EAX_T1_T0,
+        gen_op_cmovl_ECX_T1_T0,
+        gen_op_cmovl_EDX_T1_T0,
+        gen_op_cmovl_EBX_T1_T0,
+        gen_op_cmovl_ESP_T1_T0,
+        gen_op_cmovl_EBP_T1_T0,
+        gen_op_cmovl_ESI_T1_T0,
+        gen_op_cmovl_EDI_T1_T0,
+    },
+};
+
 static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
     gen_op_addl_T0_T1_cc,
     gen_op_orl_T0_T1_cc,
@@ -2586,12 +2596,27 @@
         s->is_jmp = 1;
         break;
 
-    case 0x190 ... 0x19f:
+    case 0x190 ... 0x19f: /* setcc Gv */
         modrm = ldub(s->pc++);
         gen_setcc(s, b);
         gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
         break;
-
+    case 0x140 ... 0x14f: /* cmov Gv, Ev */
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub(s->pc++);
+        reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        gen_setcc(s, b);
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_ld_T1_A0[ot]();
+        } else {
+            rm = modrm & 7;
+            gen_op_mov_TN_reg[ot][1][rm]();
+        }
+        gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
+        break;
+        
         /************************/
         /* flags */
     case 0x9c: /* pushf */
@@ -2801,7 +2826,7 @@
         gen_op_loop[s->aflag][b & 3](val, (long)s->pc);
         s->is_jmp = 1;
         break;
-    case 0x1a2: /* rdtsc */
+    case 0x131: /* rdtsc */
         gen_op_rdtsc();
         break;
 #if 0
@@ -2841,8 +2866,8 @@
     do {
         ret = disas_insn(dc, pc_ptr);
         if (ret == -1) {
-            error("unknown instruction at PC=0x%x B=%02x %02x %02x", 
-                  pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]);
+            fprintf(stderr, "unknown instruction at PC=0x%08lx B=%02x %02x %02x", 
+                    (long)pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]);
             abort();
         }
         pc_ptr = (void *)ret;