Mercurial > repos > blastem
diff gen_x86.c @ 151:6b593ea0ed90
Implement MULU/MULS and DIVU/DIVS
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 03 Jan 2013 22:07:40 -0800 |
parents | 5416a5c4628e |
children | 811163790e6c |
line wrap: on
line diff
--- a/gen_x86.c Tue Jan 01 09:40:17 2013 -0800 +++ b/gen_x86.c Thu Jan 03 22:07:40 2013 -0800 @@ -25,6 +25,7 @@ #define OP_JCC 0x70 #define OP_IMMED_ARITH 0x80 #define OP_MOV 0x88 +#define OP_CDQ 0x99 #define OP_PUSHF 0x9C #define OP_POPF 0x9D #define OP_MOV_I8R 0xB0 @@ -44,10 +45,12 @@ #define OP2_SETCC 0x90 #define OP2_BT 0xA3 #define OP2_BTS 0xAB +#define OP2_IMUL 0xAF #define OP2_BTR 0xB3 #define OP2_BTX_I 0xBA #define OP2_BTC 0xBB #define OP2_MOVSX 0xBE +#define OP2_MOVZX 0xB6 #define OP_EX_ADDI 0x0 #define OP_EX_ORI 0x1 @@ -75,6 +78,10 @@ #define OP_EX_TEST_I 0x0 #define OP_EX_NOT 0x2 #define OP_EX_NEG 0x3 +#define OP_EX_MUL 0x4 +#define OP_EX_IMUL 0x5 +#define OP_EX_DIV 0x6 +#define OP_EX_IDIV 0x7 #define OP_EX_INC 0x0 #define OP_EX_DEC 0x1 @@ -110,7 +117,7 @@ X86_R15 } x86_regs_enc; -uint8_t * x86_rr_sizedir(uint8_t * out, uint8_t opcode, uint8_t src, uint8_t dst, uint8_t size) +uint8_t * x86_rr_sizedir(uint8_t * out, uint16_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 uint8_t tmp; @@ -148,12 +155,17 @@ } else { opcode |= BIT_SIZE; } - *(out++) = opcode; + if (opcode >= 0x100) { + *(out++) = opcode >> 8; + *(out++) = opcode; + } else { + *(out++) = opcode; + } *(out++) = MODE_REG_DIRECT | dst | (src << 3); return out; } -uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_t base, int8_t disp, uint8_t size, uint8_t dir) +uint8_t * x86_rrdisp8_sizedir(uint8_t * out, uint16_t opcode, uint8_t reg, uint8_t base, int8_t disp, uint8_t size, uint8_t dir) { //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 uint8_t tmp; @@ -182,7 +194,13 @@ } else { opcode |= BIT_SIZE; } - *(out++) = opcode | dir; + opcode |= dir; + if (opcode >= 0x100) { + *(out++) = opcode >> 8; + *(out++) = opcode; + } else { + *(out++) = opcode; + } *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); if (base == RSP) { //add SIB byte, with no index and RSP as base @@ -828,6 +846,16 @@ return x86_rrdisp8_sizedir(out, OP_CMP, dst, src_base, disp, size, BIT_DIR); } +uint8_t * imul_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t size) +{ + return x86_rr_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src, size); +} + +uint8_t * imul_rdisp8r(uint8_t * out, uint8_t src_base, int8_t disp, uint8_t dst, uint8_t size) +{ + return x86_rrdisp8_sizedir(out, OP2_IMUL | (PRE_2BYTE << 8), dst, src_base, disp, size, 0); +} + uint8_t * not_r(uint8_t * out, uint8_t dst, uint8_t size) { return x86_r_size(out, OP_NOT_NEG, OP_EX_NOT, dst, size); @@ -848,6 +876,46 @@ return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_NEG, dst_base, disp, size); } +uint8_t * mul_r(uint8_t * out, uint8_t dst, uint8_t size) +{ + return x86_r_size(out, OP_NOT_NEG, OP_EX_MUL, dst, size); +} + +uint8_t * imul_r(uint8_t * out, uint8_t dst, uint8_t size) +{ + return x86_r_size(out, OP_NOT_NEG, OP_EX_IMUL, dst, size); +} + +uint8_t * div_r(uint8_t * out, uint8_t dst, uint8_t size) +{ + return x86_r_size(out, OP_NOT_NEG, OP_EX_DIV, dst, size); +} + +uint8_t * idiv_r(uint8_t * out, uint8_t dst, uint8_t size) +{ + return x86_r_size(out, OP_NOT_NEG, OP_EX_IDIV, dst, size); +} + +uint8_t * mul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_MUL, dst_base, disp, size); +} + +uint8_t * imul_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IMUL, dst_base, disp, size); +} + +uint8_t * div_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_DIV, dst_base, disp, size); +} + +uint8_t * idiv_rdisp8(uint8_t * out, uint8_t dst_base, int8_t disp, uint8_t size) +{ + return x86_rdisp8_size(out, OP_NOT_NEG, OP_EX_IDIV, dst_base, disp, size); +} + 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); @@ -1062,6 +1130,59 @@ return out; } +uint8_t * movzx_rr(uint8_t * out, uint8_t src, uint8_t dst, uint8_t src_size, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || dst >= R8 || src >= R8) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (src >= R8) { + *out |= REX_RM_FIELD; + src -= (R8 - X86_R8); + } + if (dst >= R8) { + *out |= REX_REG_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE); + *(out++) = MODE_REG_DIRECT | src | (dst << 3); + return out; +} + +uint8_t * movzx_rdisp8r(uint8_t * out, uint8_t src, int8_t disp, uint8_t dst, uint8_t src_size, uint8_t size) +{ + if (size == SZ_W) { + *(out++) = PRE_SIZE; + } + if (size == SZ_Q || dst >= R8 || src >= R8) { + *out = PRE_REX; + if (size == SZ_Q) { + *out |= REX_QUAD; + } + if (src >= R8) { + *out |= REX_RM_FIELD; + src -= (R8 - X86_R8); + } + if (dst >= R8) { + *out |= REX_REG_FIELD; + dst -= (R8 - X86_R8); + } + out++; + } + *(out++) = PRE_2BYTE; + *(out++) = OP2_MOVZX | (src_size == SZ_B ? 0 : BIT_SIZE); + *(out++) = MODE_REG_DISPLACE8 | src | (dst << 3); + *(out++) = disp; + return out; +} + uint8_t * pushf(uint8_t * out) { *(out++) = OP_PUSHF; @@ -1406,4 +1527,10 @@ return out; } +uint8_t * cdq(uint8_t * out) +{ + *(out++) = OP_CDQ; + return out; +} +