Commit 5dd9488c09081a76ff86e0d74e56a9d98d666d64
1 parent
60cd49d5
added cmov instruction
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@32 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
125 additions
and
65 deletions
TODO
1 | -- segment ops (minimal LDT/GDT support for wine) | ||
2 | - optimize translated cache chaining (DLL PLT like system) | 1 | - optimize translated cache chaining (DLL PLT like system) |
3 | - improved 16 bit support | 2 | - improved 16 bit support |
4 | - optimize inverse flags propagation (easy by generating intermediate | 3 | - optimize inverse flags propagation (easy by generating intermediate |
opreg_template.h
@@ -60,6 +60,19 @@ void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) | @@ -60,6 +60,19 @@ void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void) | ||
60 | REG = A0; | 60 | REG = A0; |
61 | } | 61 | } |
62 | 62 | ||
63 | +/* mov T1 to REG if T0 is true */ | ||
64 | +void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void) | ||
65 | +{ | ||
66 | + if (T0) | ||
67 | + REG = (REG & 0xffff0000) | (T1 & 0xffff); | ||
68 | +} | ||
69 | + | ||
70 | +void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void) | ||
71 | +{ | ||
72 | + if (T0) | ||
73 | + REG = T1; | ||
74 | +} | ||
75 | + | ||
63 | /* NOTE: T0 high order bits are ignored */ | 76 | /* NOTE: T0 high order bits are ignored */ |
64 | void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) | 77 | void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void) |
65 | { | 78 | { |
ops_template.h
@@ -385,6 +385,7 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) | @@ -385,6 +385,7 @@ void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) | ||
385 | void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) | 385 | void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) |
386 | { | 386 | { |
387 | int count, src; | 387 | int count, src; |
388 | + /* XXX: testing */ | ||
388 | count = T1 & SHIFT_MASK; | 389 | count = T1 & SHIFT_MASK; |
389 | if (count) { | 390 | if (count) { |
390 | CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); | 391 | CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); |
tests/test-i386.c
@@ -3,6 +3,8 @@ | @@ -3,6 +3,8 @@ | ||
3 | #include <inttypes.h> | 3 | #include <inttypes.h> |
4 | #include <math.h> | 4 | #include <math.h> |
5 | 5 | ||
6 | +#define TEST_CMOV 0 | ||
7 | + | ||
6 | #define xglue(x, y) x ## y | 8 | #define xglue(x, y) x ## y |
7 | #define glue(x, y) xglue(x, y) | 9 | #define glue(x, y) xglue(x, y) |
8 | #define stringify(s) tostring(s) | 10 | #define stringify(s) tostring(s) |
@@ -225,79 +227,99 @@ void test_lea(void) | @@ -225,79 +227,99 @@ void test_lea(void) | ||
225 | 227 | ||
226 | #define TEST_JCC(JCC, v1, v2)\ | 228 | #define TEST_JCC(JCC, v1, v2)\ |
227 | {\ | 229 | {\ |
230 | + int res;\ | ||
228 | asm("movl $1, %0\n\t"\ | 231 | asm("movl $1, %0\n\t"\ |
229 | "cmpl %2, %1\n\t"\ | 232 | "cmpl %2, %1\n\t"\ |
230 | - JCC " 1f\n\t"\ | 233 | + "j" JCC " 1f\n\t"\ |
231 | "movl $0, %0\n\t"\ | 234 | "movl $0, %0\n\t"\ |
232 | "1:\n\t"\ | 235 | "1:\n\t"\ |
233 | : "=r" (res)\ | 236 | : "=r" (res)\ |
234 | : "r" (v1), "r" (v2));\ | 237 | : "r" (v1), "r" (v2));\ |
235 | - printf("%-10s %d\n", JCC, res);\ | 238 | + printf("%-10s %d\n", "j" JCC, res);\ |
239 | +\ | ||
240 | + asm("movl $0, %0\n\t"\ | ||
241 | + "cmpl %2, %1\n\t"\ | ||
242 | + "set" JCC " %b0\n\t"\ | ||
243 | + : "=r" (res)\ | ||
244 | + : "r" (v1), "r" (v2));\ | ||
245 | + printf("%-10s %d\n", "set" JCC, res);\ | ||
246 | + if (TEST_CMOV) {\ | ||
247 | + asm("movl $0x12345678, %0\n\t"\ | ||
248 | + "cmpl %2, %1\n\t"\ | ||
249 | + "cmov" JCC "l %3, %0\n\t"\ | ||
250 | + : "=r" (res)\ | ||
251 | + : "r" (v1), "r" (v2), "m" (1));\ | ||
252 | + printf("%-10s R=0x%08x\n", "cmov" JCC "l", res);\ | ||
253 | + asm("movl $0x12345678, %0\n\t"\ | ||
254 | + "cmpl %2, %1\n\t"\ | ||
255 | + "cmov" JCC "w %w3, %w0\n\t"\ | ||
256 | + : "=r" (res)\ | ||
257 | + : "r" (v1), "r" (v2), "r" (1));\ | ||
258 | + printf("%-10s R=0x%08x\n", "cmov" JCC "w", res);\ | ||
259 | + } \ | ||
236 | } | 260 | } |
237 | 261 | ||
238 | /* various jump tests */ | 262 | /* various jump tests */ |
239 | void test_jcc(void) | 263 | void test_jcc(void) |
240 | { | 264 | { |
241 | - int res; | ||
242 | - | ||
243 | - TEST_JCC("jne", 1, 1); | ||
244 | - TEST_JCC("jne", 1, 0); | 265 | + TEST_JCC("ne", 1, 1); |
266 | + TEST_JCC("ne", 1, 0); | ||
245 | 267 | ||
246 | - TEST_JCC("je", 1, 1); | ||
247 | - TEST_JCC("je", 1, 0); | 268 | + TEST_JCC("e", 1, 1); |
269 | + TEST_JCC("e", 1, 0); | ||
248 | 270 | ||
249 | - TEST_JCC("jl", 1, 1); | ||
250 | - TEST_JCC("jl", 1, 0); | ||
251 | - TEST_JCC("jl", 1, -1); | 271 | + TEST_JCC("l", 1, 1); |
272 | + TEST_JCC("l", 1, 0); | ||
273 | + TEST_JCC("l", 1, -1); | ||
252 | 274 | ||
253 | - TEST_JCC("jle", 1, 1); | ||
254 | - TEST_JCC("jle", 1, 0); | ||
255 | - TEST_JCC("jle", 1, -1); | 275 | + TEST_JCC("le", 1, 1); |
276 | + TEST_JCC("le", 1, 0); | ||
277 | + TEST_JCC("le", 1, -1); | ||
256 | 278 | ||
257 | - TEST_JCC("jge", 1, 1); | ||
258 | - TEST_JCC("jge", 1, 0); | ||
259 | - TEST_JCC("jge", -1, 1); | 279 | + TEST_JCC("ge", 1, 1); |
280 | + TEST_JCC("ge", 1, 0); | ||
281 | + TEST_JCC("ge", -1, 1); | ||
260 | 282 | ||
261 | - TEST_JCC("jg", 1, 1); | ||
262 | - TEST_JCC("jg", 1, 0); | ||
263 | - TEST_JCC("jg", 1, -1); | 283 | + TEST_JCC("g", 1, 1); |
284 | + TEST_JCC("g", 1, 0); | ||
285 | + TEST_JCC("g", 1, -1); | ||
264 | 286 | ||
265 | - TEST_JCC("jb", 1, 1); | ||
266 | - TEST_JCC("jb", 1, 0); | ||
267 | - TEST_JCC("jb", 1, -1); | 287 | + TEST_JCC("b", 1, 1); |
288 | + TEST_JCC("b", 1, 0); | ||
289 | + TEST_JCC("b", 1, -1); | ||
268 | 290 | ||
269 | - TEST_JCC("jbe", 1, 1); | ||
270 | - TEST_JCC("jbe", 1, 0); | ||
271 | - TEST_JCC("jbe", 1, -1); | 291 | + TEST_JCC("be", 1, 1); |
292 | + TEST_JCC("be", 1, 0); | ||
293 | + TEST_JCC("be", 1, -1); | ||
272 | 294 | ||
273 | - TEST_JCC("jae", 1, 1); | ||
274 | - TEST_JCC("jae", 1, 0); | ||
275 | - TEST_JCC("jae", 1, -1); | 295 | + TEST_JCC("ae", 1, 1); |
296 | + TEST_JCC("ae", 1, 0); | ||
297 | + TEST_JCC("ae", 1, -1); | ||
276 | 298 | ||
277 | - TEST_JCC("ja", 1, 1); | ||
278 | - TEST_JCC("ja", 1, 0); | ||
279 | - TEST_JCC("ja", 1, -1); | 299 | + TEST_JCC("a", 1, 1); |
300 | + TEST_JCC("a", 1, 0); | ||
301 | + TEST_JCC("a", 1, -1); | ||
280 | 302 | ||
281 | 303 | ||
282 | - TEST_JCC("jp", 1, 1); | ||
283 | - TEST_JCC("jp", 1, 0); | 304 | + TEST_JCC("p", 1, 1); |
305 | + TEST_JCC("p", 1, 0); | ||
284 | 306 | ||
285 | - TEST_JCC("jnp", 1, 1); | ||
286 | - TEST_JCC("jnp", 1, 0); | 307 | + TEST_JCC("np", 1, 1); |
308 | + TEST_JCC("np", 1, 0); | ||
287 | 309 | ||
288 | - TEST_JCC("jo", 0x7fffffff, 0); | ||
289 | - TEST_JCC("jo", 0x7fffffff, -1); | 310 | + TEST_JCC("o", 0x7fffffff, 0); |
311 | + TEST_JCC("o", 0x7fffffff, -1); | ||
290 | 312 | ||
291 | - TEST_JCC("jno", 0x7fffffff, 0); | ||
292 | - TEST_JCC("jno", 0x7fffffff, -1); | 313 | + TEST_JCC("no", 0x7fffffff, 0); |
314 | + TEST_JCC("no", 0x7fffffff, -1); | ||
293 | 315 | ||
294 | - TEST_JCC("js", 0, 1); | ||
295 | - TEST_JCC("js", 0, -1); | ||
296 | - TEST_JCC("js", 0, 0); | 316 | + TEST_JCC("s", 0, 1); |
317 | + TEST_JCC("s", 0, -1); | ||
318 | + TEST_JCC("s", 0, 0); | ||
297 | 319 | ||
298 | - TEST_JCC("jns", 0, 1); | ||
299 | - TEST_JCC("jns", 0, -1); | ||
300 | - TEST_JCC("jns", 0, 0); | 320 | + TEST_JCC("ns", 0, 1); |
321 | + TEST_JCC("ns", 0, -1); | ||
322 | + TEST_JCC("ns", 0, 0); | ||
301 | } | 323 | } |
302 | 324 | ||
303 | #undef CC_MASK | 325 | #undef CC_MASK |
translate-i386.c
@@ -44,19 +44,6 @@ int __op_param1, __op_param2, __op_param3; | @@ -44,19 +44,6 @@ int __op_param1, __op_param2, __op_param3; | ||
44 | extern FILE *logfile; | 44 | extern FILE *logfile; |
45 | extern int loglevel; | 45 | extern int loglevel; |
46 | 46 | ||
47 | -/* supress that */ | ||
48 | -static void error(const char *fmt, ...) | ||
49 | -{ | ||
50 | - va_list ap; | ||
51 | - | ||
52 | - va_start(ap, fmt); | ||
53 | - fprintf(stderr, "\n"); | ||
54 | - vfprintf(stderr, fmt, ap); | ||
55 | - fprintf(stderr, "\n"); | ||
56 | - va_end(ap); | ||
57 | - exit(1); | ||
58 | -} | ||
59 | - | ||
60 | #define PREFIX_REPZ 1 | 47 | #define PREFIX_REPZ 1 |
61 | #define PREFIX_REPNZ 2 | 48 | #define PREFIX_REPNZ 2 |
62 | #define PREFIX_LOCK 4 | 49 | #define PREFIX_LOCK 4 |
@@ -352,6 +339,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { | @@ -352,6 +339,29 @@ static GenOpFunc *gen_op_addl_A0_reg_sN[4][8] = { | ||
352 | }, | 339 | }, |
353 | }; | 340 | }; |
354 | 341 | ||
342 | +static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = { | ||
343 | + [0] = { | ||
344 | + gen_op_cmovw_EAX_T1_T0, | ||
345 | + gen_op_cmovw_ECX_T1_T0, | ||
346 | + gen_op_cmovw_EDX_T1_T0, | ||
347 | + gen_op_cmovw_EBX_T1_T0, | ||
348 | + gen_op_cmovw_ESP_T1_T0, | ||
349 | + gen_op_cmovw_EBP_T1_T0, | ||
350 | + gen_op_cmovw_ESI_T1_T0, | ||
351 | + gen_op_cmovw_EDI_T1_T0, | ||
352 | + }, | ||
353 | + [1] = { | ||
354 | + gen_op_cmovl_EAX_T1_T0, | ||
355 | + gen_op_cmovl_ECX_T1_T0, | ||
356 | + gen_op_cmovl_EDX_T1_T0, | ||
357 | + gen_op_cmovl_EBX_T1_T0, | ||
358 | + gen_op_cmovl_ESP_T1_T0, | ||
359 | + gen_op_cmovl_EBP_T1_T0, | ||
360 | + gen_op_cmovl_ESI_T1_T0, | ||
361 | + gen_op_cmovl_EDI_T1_T0, | ||
362 | + }, | ||
363 | +}; | ||
364 | + | ||
355 | static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { | 365 | static GenOpFunc *gen_op_arith_T0_T1_cc[8] = { |
356 | gen_op_addl_T0_T1_cc, | 366 | gen_op_addl_T0_T1_cc, |
357 | gen_op_orl_T0_T1_cc, | 367 | gen_op_orl_T0_T1_cc, |
@@ -2586,12 +2596,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2586,12 +2596,27 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2586 | s->is_jmp = 1; | 2596 | s->is_jmp = 1; |
2587 | break; | 2597 | break; |
2588 | 2598 | ||
2589 | - case 0x190 ... 0x19f: | 2599 | + case 0x190 ... 0x19f: /* setcc Gv */ |
2590 | modrm = ldub(s->pc++); | 2600 | modrm = ldub(s->pc++); |
2591 | gen_setcc(s, b); | 2601 | gen_setcc(s, b); |
2592 | gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); | 2602 | gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1); |
2593 | break; | 2603 | break; |
2594 | - | 2604 | + case 0x140 ... 0x14f: /* cmov Gv, Ev */ |
2605 | + ot = dflag ? OT_LONG : OT_WORD; | ||
2606 | + modrm = ldub(s->pc++); | ||
2607 | + reg = (modrm >> 3) & 7; | ||
2608 | + mod = (modrm >> 6) & 3; | ||
2609 | + gen_setcc(s, b); | ||
2610 | + if (mod != 3) { | ||
2611 | + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); | ||
2612 | + gen_op_ld_T1_A0[ot](); | ||
2613 | + } else { | ||
2614 | + rm = modrm & 7; | ||
2615 | + gen_op_mov_TN_reg[ot][1][rm](); | ||
2616 | + } | ||
2617 | + gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg](); | ||
2618 | + break; | ||
2619 | + | ||
2595 | /************************/ | 2620 | /************************/ |
2596 | /* flags */ | 2621 | /* flags */ |
2597 | case 0x9c: /* pushf */ | 2622 | case 0x9c: /* pushf */ |
@@ -2801,7 +2826,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | @@ -2801,7 +2826,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) | ||
2801 | gen_op_loop[s->aflag][b & 3](val, (long)s->pc); | 2826 | gen_op_loop[s->aflag][b & 3](val, (long)s->pc); |
2802 | s->is_jmp = 1; | 2827 | s->is_jmp = 1; |
2803 | break; | 2828 | break; |
2804 | - case 0x1a2: /* rdtsc */ | 2829 | + case 0x131: /* rdtsc */ |
2805 | gen_op_rdtsc(); | 2830 | gen_op_rdtsc(); |
2806 | break; | 2831 | break; |
2807 | #if 0 | 2832 | #if 0 |
@@ -2841,8 +2866,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | @@ -2841,8 +2866,8 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
2841 | do { | 2866 | do { |
2842 | ret = disas_insn(dc, pc_ptr); | 2867 | ret = disas_insn(dc, pc_ptr); |
2843 | if (ret == -1) { | 2868 | if (ret == -1) { |
2844 | - error("unknown instruction at PC=0x%x B=%02x %02x %02x", | ||
2845 | - pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); | 2869 | + fprintf(stderr, "unknown instruction at PC=0x%08lx B=%02x %02x %02x", |
2870 | + (long)pc_ptr, pc_ptr[0], pc_ptr[1], pc_ptr[2]); | ||
2846 | abort(); | 2871 | abort(); |
2847 | } | 2872 | } |
2848 | pc_ptr = (void *)ret; | 2873 | pc_ptr = (void *)ret; |