From 5dd9488c09081a76ff86e0d74e56a9d98d666d64 Mon Sep 17 00:00:00 2001 From: bellard Date: Sun, 16 Mar 2003 22:54:06 +0000 Subject: [PATCH] added cmov instruction git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@32 c046a42c-6fe2-441c-8c8c-71466251a162 --- TODO | 1 - opreg_template.h | 13 ++++++ ops_template.h | 1 + tests/test-i386.c | 114 +++++++++++++++++++++++++++------------------- translate-i386.c | 61 +++++++++++++++++-------- 5 files changed, 125 insertions(+), 65 deletions(-) diff --git a/TODO b/TODO index 5602097b8e..1a7bac5134 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 6cf188ffed..d6453f9546 100644 --- a/opreg_template.h +++ b/opreg_template.h @@ -60,6 +60,19 @@ void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) 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 60bdbe5091..8905d90846 100644 --- a/ops_template.h +++ b/ops_template.h @@ -385,6 +385,7 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) 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 907c44ec91..86aa94915a 100644 --- a/tests/test-i386.c +++ b/tests/test-i386.c @@ -3,6 +3,8 @@ #include #include +#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 @@ void test_lea(void) #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 7737dc1219..9bf7f5607e 100644 --- a/translate-i386.c +++ b/translate-i386.c @@ -44,19 +44,6 @@ int __op_param1, __op_param2, __op_param3; 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_addl_A0_reg_sN[4][8] = { }, }; +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 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) 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, ®_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 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) 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 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 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;