comparison gen_x86.c @ 18:3e7bfde7606e

M68K to x86 translation works for a limited subset of instructions and addressing modes
author Mike Pavone <pavone@retrodev.com>
date Tue, 04 Dec 2012 19:13:12 -0800
parents c0f339564819
children d2e43d64e999
comparison
equal deleted inserted replaced
17:de0085d4ea40 18:3e7bfde7606e
29 #define OP_MOV_I8R 0xB0 29 #define OP_MOV_I8R 0xB0
30 #define OP_MOV_IR 0xB8 30 #define OP_MOV_IR 0xB8
31 #define OP_RETN 0xC3 31 #define OP_RETN 0xC3
32 #define OP_MOV_IEA 0xC6 32 #define OP_MOV_IEA 0xC6
33 #define OP_CALL 0xE8 33 #define OP_CALL 0xE8
34 #define OP_JMP 0xE9
35 #define OP_JMP_BYTE 0xEB
34 #define OP_CALL_EA 0xFF 36 #define OP_CALL_EA 0xFF
35 37
36 #define OP2_JCC 0x80 38 #define OP2_JCC 0x80
37 #define OP2_SETCC 0x90 39 #define OP2_SETCC 0x90
38 40
47 49
48 #define BIT_IMMED_RAX 0x4 50 #define BIT_IMMED_RAX 0x4
49 #define BIT_DIR 0x2 51 #define BIT_DIR 0x2
50 #define BIT_SIZE 0x1 52 #define BIT_SIZE 0x1
51 53
52 #define M68K_N_REG RBX
53 #define M68K_V_REG BH
54 #define M68K_Z_REG RDX
55 #define M68K_C_REG DH
56
57 #define M68K_SCRATCH RCX
58 54
59 enum { 55 enum {
60 X86_RAX = 0, 56 X86_RAX = 0,
61 X86_RCX, 57 X86_RCX,
62 X86_RDX, 58 X86_RDX,
77 X86_R13, 73 X86_R13,
78 X86_R14, 74 X86_R14,
79 X86_R15 75 X86_R15
80 } x86_regs_enc; 76 } x86_regs_enc;
81 77
82 enum {
83 MODE_REG_INDIRECT = 0,
84 MODE_REG_DISPLACE8 = 0x40,
85 MODE_REG_DIPSLACE32 = 0x80,
86 MODE_REG_DIRECT = 0xC0
87 } x86_modes;
88
89 uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size) 78 uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size)
90 { 79 {
91 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix 80 //TODO: Deal with the fact that AH, BH, CH and DH can only be in the R/M param when there's a REX prefix
92 uint8_t tmp; 81 uint8_t tmp;
93 if (size == SZ_W) { 82 if (size == SZ_W) {
158 } else { 147 } else {
159 opcode |= BIT_SIZE; 148 opcode |= BIT_SIZE;
160 } 149 }
161 *(out++) = opcode | dir; 150 *(out++) = opcode | dir;
162 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); 151 *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3);
152 if (base == RSP) {
153 //add SIB byte, with no index and RSP as base
154 *(out++) = (RSP << 3) | RSP;
155 }
163 *(out++) = disp; 156 *(out++) = disp;
164 return out; 157 return out;
165 } 158 }
166 159
167 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir) 160 uint8_t * x86_rrind_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, uint8_t size, uint8_t dir)
193 } else { 186 } else {
194 opcode |= BIT_SIZE; 187 opcode |= BIT_SIZE;
195 } 188 }
196 *(out++) = opcode | dir; 189 *(out++) = opcode | dir;
197 *(out++) = MODE_REG_INDIRECT | base | (reg << 3); 190 *(out++) = MODE_REG_INDIRECT | base | (reg << 3);
191 if (base == RSP) {
192 //add SIB byte, with no index and RSP as base
193 *(out++) = (RSP << 3) | RSP;
194 }
198 return out; 195 return out;
199 } 196 }
200 197
201 uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size) 198 uint8_t * x86_ir(uint8_t * out, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, int32_t val, uint8_t dst, uint8_t size)
202 { 199 {
249 } 246 }
250 } 247 }
251 return out; 248 return out;
252 } 249 }
253 250
251 uint8_t * x86_irdisp8(uint8_t * out, uint8_t opcode, uint8_t op_ex, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
252 {
253 uint8_t sign_extend = 0;
254 if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) {
255 sign_extend = 1;
256 opcode |= BIT_DIR;
257 }
258 if (size == SZ_W) {
259 *(out++) = PRE_SIZE;
260 }
261
262 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
263 *out = PRE_REX;
264 if (size == SZ_Q) {
265 *out |= REX_QUAD;
266 }
267 if (dst >= R8) {
268 *out |= REX_RM_FIELD;
269 dst -= (R8 - X86_R8);
270 }
271 out++;
272 }
273 if (dst >= AH && dst <= BH) {
274 dst -= (AH-X86_AH);
275 }
276 if (size != SZ_B) {
277 opcode |= BIT_SIZE;
278 }
279 *(out++) = opcode;
280 *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3);
281 *(out++) = disp;
282 *(out++) = val;
283 if (size != SZ_B && !sign_extend) {
284 val >>= 8;
285 *(out++) = val;
286 if (size != SZ_W) {
287 val >>= 8;
288 *(out++) = val;
289 val >>= 8;
290 *(out++) = val;
291 }
292 }
293 return out;
294 }
295
254 296
255 uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 297 uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
256 { 298 {
257 return x86_rr_sizedir(out, OP_ADD, src, dst, size); 299 return x86_rr_sizedir(out, OP_ADD, src, dst, size);
258 } 300 }
260 uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 302 uint8_t * add_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
261 { 303 {
262 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); 304 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size);
263 } 305 }
264 306
307 uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
308 {
309 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size);
310 }
311
312 uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
313 {
314 return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0);
315 }
316
317 uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
318 {
319 return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR);
320 }
321
265 uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 322 uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
266 { 323 {
267 return x86_rr_sizedir(out, OP_OR, src, dst, size); 324 return x86_rr_sizedir(out, OP_OR, src, dst, size);
268 } 325 }
269 uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 326 uint8_t * or_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
270 { 327 {
271 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); 328 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size);
272 } 329 }
273 330
331 uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
332 {
333 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size);
334 }
335
336 uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
337 {
338 return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0);
339 }
340
341 uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
342 {
343 return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR);
344 }
345
274 uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 346 uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
275 { 347 {
276 return x86_rr_sizedir(out, OP_AND, src, dst, size); 348 return x86_rr_sizedir(out, OP_AND, src, dst, size);
277 } 349 }
278 350
279 uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 351 uint8_t * and_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
280 { 352 {
281 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); 353 return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size);
282 } 354 }
283 355
356 uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
357 {
358 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size);
359 }
360
361 uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
362 {
363 return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0);
364 }
365
366 uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
367 {
368 return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR);
369 }
370
284 uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 371 uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
285 { 372 {
286 return x86_rr_sizedir(out, OP_XOR, src, dst, size); 373 return x86_rr_sizedir(out, OP_XOR, src, dst, size);
287 } 374 }
288 375
289 uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 376 uint8_t * xor_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
290 { 377 {
291 return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); 378 return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size);
292 } 379 }
293 380
381 uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
382 {
383 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size);
384 }
385
386 uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
387 {
388 return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0);
389 }
390
391 uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
392 {
393 return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR);
394 }
395
294 uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 396 uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
295 { 397 {
296 return x86_rr_sizedir(out, OP_SUB, src, dst, size); 398 return x86_rr_sizedir(out, OP_SUB, src, dst, size);
297 } 399 }
298 400
299 uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 401 uint8_t * sub_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
300 { 402 {
301 return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); 403 return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size);
302 } 404 }
303 405
406 uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
407 {
408 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size);
409 }
410
411 uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
412 {
413 return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0);
414 }
415
416 uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
417 {
418 return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR);
419 }
420
304 uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 421 uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
305 { 422 {
306 return x86_rr_sizedir(out, OP_CMP, src, dst, size); 423 return x86_rr_sizedir(out, OP_CMP, src, dst, size);
307 } 424 }
308 425
309 uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size) 426 uint8_t * cmp_ir(uint8_t * out, int32_t val, uint8_t dst, uint8_t size)
310 { 427 {
311 return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); 428 return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size);
429 }
430
431 uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size)
432 {
433 return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size);
434 }
435
436 uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size)
437 {
438 return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0);
439 }
440
441 uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size)
442 {
443 return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR);
312 } 444 }
313 445
314 uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) 446 uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size)
315 { 447 {
316 return x86_rr_sizedir(out, OP_MOV, src, dst, size); 448 return x86_rr_sizedir(out, OP_MOV, src, dst, size);
358 } 490 }
359 if (dst >= AH && dst <= BH) { 491 if (dst >= AH && dst <= BH) {
360 dst -= (AH-X86_AH); 492 dst -= (AH-X86_AH);
361 } 493 }
362 if (size == SZ_B) { 494 if (size == SZ_B) {
363 *(out++) = OP_MOV_I8R; 495 *(out++) = OP_MOV_I8R | dst;
364 } else if (size == SZ_Q && sign_extend) { 496 } else if (size == SZ_Q && sign_extend) {
365 *(out++) = OP_MOV_IEA | BIT_SIZE; 497 *(out++) = OP_MOV_IEA | BIT_SIZE;
366 *(out++) = MODE_REG_DIRECT | dst; 498 *(out++) = MODE_REG_DIRECT | dst;
367 } else { 499 } else {
368 *(out++) = OP_MOV_IR; 500 *(out++) = OP_MOV_IR | dst;
369 } 501 }
370 *(out++) = val; 502 *(out++) = val;
371 if (size != SZ_B) { 503 if (size != SZ_B) {
372 val >>= 8; 504 val >>= 8;
373 *(out++) = val; 505 *(out++) = val;
389 } 521 }
390 } 522 }
391 return out; 523 return out;
392 } 524 }
393 525
526 uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size)
527 {
528 if (size == SZ_W) {
529 *(out++) = PRE_SIZE;
530 }
531 if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) {
532 *out = PRE_REX;
533 if (size == SZ_Q) {
534 *out |= REX_QUAD;
535 }
536 if (dst >= R8) {
537 *out |= REX_RM_FIELD;
538 dst -= (R8 - X86_R8);
539 }
540 out++;
541 }
542 if (dst >= AH && dst <= BH) {
543 dst -= (AH-X86_AH);
544 }
545 *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE);
546 *(out++) = MODE_REG_DISPLACE8 | dst;
547 *(out++) = disp;
548
549 *(out++) = val;
550 if (size != SZ_B) {
551 val >>= 8;
552 *(out++) = val;
553 if (size != SZ_W) {
554 val >>= 8;
555 *(out++) = val;
556 val >>= 8;
557 *(out++) = val;
558 }
559 }
560 return out;
561 }
562
394 uint8_t * pushf(uint8_t * out) 563 uint8_t * pushf(uint8_t * out)
395 { 564 {
396 *(out++) = OP_PUSHF; 565 *(out++) = OP_PUSHF;
397 return out; 566 return out;
398 } 567 }
449 *(out++) = OP2_SETCC | cc; 618 *(out++) = OP2_SETCC | cc;
450 *(out++) = MODE_REG_INDIRECT | dst; 619 *(out++) = MODE_REG_INDIRECT | dst;
451 return out; 620 return out;
452 } 621 }
453 622
454 uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp) 623 uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest)
455 { 624 {
625 ptrdiff_t disp = dest-(out+2);
456 if (disp <= 0x7F && disp >= -0x80) { 626 if (disp <= 0x7F && disp >= -0x80) {
457 *(out++) = OP_JCC | cc; 627 *(out++) = OP_JCC | cc;
458 *(out++) = disp; 628 *(out++) = disp;
459 } else { 629 } else {
460 *(out++) = PRE_2BYTE; 630 disp = dest-(out+6);
461 *(out++) = OP2_JCC | cc; 631 if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
632 *(out++) = PRE_2BYTE;
633 *(out++) = OP2_JCC | cc;
634 *(out++) = disp;
635 disp >>= 8;
636 *(out++) = disp;
637 disp >>= 8;
638 *(out++) = disp;
639 disp >>= 8;
640 *(out++) = disp;
641 } else {
642 printf("%p - %p = %lX\n", dest, out + 6, disp);
643 return NULL;
644 }
645 }
646 return out;
647 }
648
649 uint8_t * jmp(uint8_t * out, uint8_t * dest)
650 {
651 ptrdiff_t disp = dest-(out+2);
652 if (disp <= 0x7F && disp >= -0x80) {
653 *(out++) = OP_JMP_BYTE;
462 *(out++) = disp; 654 *(out++) = disp;
463 disp >>= 8; 655 } else {
464 *(out++) = disp; 656 disp = dest-(out+5);
465 disp >>= 8; 657 if (disp <= 0x7FFFFFFF && disp >= -2147483648) {
466 *(out++) = disp; 658 *(out++) = OP_JMP;
467 disp >>= 8; 659 *(out++) = disp;
468 *(out++) = disp; 660 disp >>= 8;
661 *(out++) = disp;
662 disp >>= 8;
663 *(out++) = disp;
664 disp >>= 8;
665 *(out++) = disp;
666 } else {
667 printf("%p - %p = %lX\n", dest, out + 6, disp);
668 return NULL;
669 }
469 } 670 }
470 return out; 671 return out;
471 } 672 }
472 673
473 uint8_t * call(uint8_t * out, uint8_t * fun) 674 uint8_t * call(uint8_t * out, uint8_t * fun)
481 disp >>= 8; 682 disp >>= 8;
482 *(out++) = disp; 683 *(out++) = disp;
483 disp >>= 8; 684 disp >>= 8;
484 *(out++) = disp; 685 *(out++) = disp;
485 } else { 686 } else {
486 //TODO: Implement far call 687 //TODO: Implement far call???
487 printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648); 688 printf("%p - %p = %lX\n", fun, out + 5, disp);
488 return NULL; 689 return NULL;
489 } 690 }
490 return out; 691 return out;
491 } 692 }
492 693