Mercurial > repos > blastem
diff 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 |
line wrap: on
line diff
--- a/gen_x86.c Tue Nov 27 22:54:38 2012 -0800 +++ b/gen_x86.c Tue Dec 04 19:13:12 2012 -0800 @@ -31,6 +31,8 @@ #define OP_RETN 0xC3 #define OP_MOV_IEA 0xC6 #define OP_CALL 0xE8 +#define OP_JMP 0xE9 +#define OP_JMP_BYTE 0xEB #define OP_CALL_EA 0xFF #define OP2_JCC 0x80 @@ -49,12 +51,6 @@ #define BIT_DIR 0x2 #define BIT_SIZE 0x1 -#define M68K_N_REG RBX -#define M68K_V_REG BH -#define M68K_Z_REG RDX -#define M68K_C_REG DH - -#define M68K_SCRATCH RCX enum { X86_RAX = 0, @@ -79,13 +75,6 @@ X86_R15 } x86_regs_enc; -enum { - MODE_REG_INDIRECT = 0, - MODE_REG_DISPLACE8 = 0x40, - MODE_REG_DIPSLACE32 = 0x80, - MODE_REG_DIRECT = 0xC0 -} x86_modes; - uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size) { //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 @@ -160,6 +149,10 @@ } *(out++) = opcode | dir; *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } *(out++) = disp; return out; } @@ -195,6 +188,10 @@ } *(out++) = opcode | dir; *(out++) = MODE_REG_INDIRECT | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } return out; } @@ -251,6 +248,51 @@ return out; } +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) +{ + uint8_t sign_extend = 0; + if ((size == SZ_D || size == SZ_Q) && val <= 0x7F && val >= -0x80) { + sign_extend = 1; + opcode |= BIT_DIR; + } + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + + if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (dst >= R8) { + *out |= REX_RM_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + if (dst >= AH && dst <= BH) { + dst -= (AH-X86_AH); + } + if (size != SZ_B) { + opcode |= BIT_SIZE; + } + *(out++) = opcode; + *(out++) = MODE_REG_DISPLACE8 | dst | (op_ex << 3); + *(out++) = disp; + *(out++) = val; + if (size != SZ_B && !sign_extend) { + val >>= 8; + *(out++) = val; + if (size != SZ_W) { + val >>= 8; + *(out++) = val; + val >>= 8; + *(out++) = val; + } + } + return out; +} + uint8_t * add_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { @@ -262,6 +304,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ADDI, OP_ADD, val, dst, size); } +uint8_t * add_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ADDI, val, dst_base, disp, size); +} + +uint8_t * add_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_ADD, src, dst_base, disp, size, 0); +} + +uint8_t * add_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_ADD, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * or_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_OR, src, dst, size); @@ -271,6 +328,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ORI, OP_OR, val, dst, size); } +uint8_t * or_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ORI, val, dst_base, disp, size); +} + +uint8_t * or_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_OR, src, dst_base, disp, size, 0); +} + +uint8_t * or_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_OR, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * and_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_AND, src, dst, size); @@ -281,6 +353,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_ANDI, OP_AND, val, dst, size); } +uint8_t * and_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_ANDI, val, dst_base, disp, size); +} + +uint8_t * and_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_AND, src, dst_base, disp, size, 0); +} + +uint8_t * and_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_AND, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * xor_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_XOR, src, dst, size); @@ -291,6 +378,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_XORI, OP_XOR, val, dst, size); } +uint8_t * xor_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_XORI, val, dst_base, disp, size); +} + +uint8_t * xor_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_XOR, src, dst_base, disp, size, 0); +} + +uint8_t * xor_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_XOR, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * sub_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_SUB, src, dst, size); @@ -301,6 +403,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_SUBI, OP_SUB, val, dst, size); } +uint8_t * sub_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_SUBI, val, dst_base, disp, size); +} + +uint8_t * sub_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_SUB, src, dst_base, disp, size, 0); +} + +uint8_t * sub_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_SUB, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * cmp_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_CMP, src, dst, size); @@ -311,6 +428,21 @@ return x86_ir(out, OP_IMMED_ARITH, OP_EX_CMPI, OP_CMP, val, dst, size); } +uint8_t * cmp_irdisp8(uint8_t * out, int32_t val, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_irdisp8(out, OP_IMMED_ARITH, OP_EX_CMPI, val, dst_base, disp, size); +} + +uint8_t * cmp_rrdisp8(uint8_t * out, uint8_t src, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_CMP, src, dst_base, disp, size, 0); +} + +uint8_t * cmp_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR); +} + uint8_t * mov_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) { return x86_rr_sizedir(out, OP_MOV, src, dst, size); @@ -360,12 +492,12 @@ dst -= (AH-X86_AH); } if (size == SZ_B) { - *(out++) = OP_MOV_I8R; + *(out++) = OP_MOV_I8R | dst; } else if (size == SZ_Q && sign_extend) { *(out++) = OP_MOV_IEA | BIT_SIZE; *(out++) = MODE_REG_DIRECT | dst; } else { - *(out++) = OP_MOV_IR; + *(out++) = OP_MOV_IR | dst; } *(out++) = val; if (size != SZ_B) { @@ -391,6 +523,43 @@ return out; } +uint8_t * mov_irdisp8(uint8_t * out, int32_t val, uint8_t dst, int8_t disp, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (dst >= R8) { + *out |= REX_RM_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + if (dst >= AH && dst <= BH) { + dst -= (AH-X86_AH); + } + *(out++) = OP_MOV_IEA | (size == SZ_B ? 0 : BIT_SIZE); + *(out++) = MODE_REG_DISPLACE8 | dst; + *(out++) = disp; + + *(out++) = val; + if (size != SZ_B) { + val >>= 8; + *(out++) = val; + if (size != SZ_W) { + val >>= 8; + *(out++) = val; + val >>= 8; + *(out++) = val; + } + } + return out; +} + uint8_t * pushf(uint8_t * out) { *(out++) = OP_PUSHF; @@ -451,21 +620,53 @@ return out; } -uint8_t * jcc(uint8_t * out, uint8_t cc, int32_t disp) +uint8_t * jcc(uint8_t * out, uint8_t cc, uint8_t * dest) { + ptrdiff_t disp = dest-(out+2); if (disp <= 0x7F && disp >= -0x80) { *(out++) = OP_JCC | cc; *(out++) = disp; } else { - *(out++) = PRE_2BYTE; - *(out++) = OP2_JCC | cc; - *(out++) = disp; - disp >>= 8; + disp = dest-(out+6); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = PRE_2BYTE; + *(out++) = OP2_JCC | cc; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + printf("%p - %p = %lX\n", dest, out + 6, disp); + return NULL; + } + } + return out; +} + +uint8_t * jmp(uint8_t * out, uint8_t * dest) +{ + ptrdiff_t disp = dest-(out+2); + if (disp <= 0x7F && disp >= -0x80) { + *(out++) = OP_JMP_BYTE; *(out++) = disp; - disp >>= 8; - *(out++) = disp; - disp >>= 8; - *(out++) = disp; + } else { + disp = dest-(out+5); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = OP_JMP; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + printf("%p - %p = %lX\n", dest, out + 6, disp); + return NULL; + } } return out; } @@ -483,8 +684,8 @@ disp >>= 8; *(out++) = disp; } else { - //TODO: Implement far call - printf("%p - %p = %ld, %d, %d, %d\n", fun, out + 5, disp, disp <= 0x7FFFFFFF, disp >= (-2147483648), -2147483648); + //TODO: Implement far call??? + printf("%p - %p = %lX\n", fun, out + 5, disp); return NULL; } return out;