mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-22 22:05:38 +00:00
1130 lines
18 KiB
C
1130 lines
18 KiB
C
#include "model3.h"
|
|
#include "genx86.h"
|
|
|
|
static UINT8 *drc_cache_top;
|
|
static UINT8 *drc_cache;
|
|
|
|
#define DRC_CACHE_SIZE 0x800000
|
|
|
|
static UINT32 cumulative_instruction_amount;
|
|
|
|
static void emit_byte(UINT8 value)
|
|
{
|
|
if (drc_cache_top - drc_cache > DRC_CACHE_SIZE)
|
|
{
|
|
error("gen: drc cache overflow!\n");
|
|
}
|
|
|
|
*drc_cache_top++ = value;
|
|
}
|
|
|
|
static void emit_dword(UINT32 value)
|
|
{
|
|
if (drc_cache_top - drc_cache > DRC_CACHE_SIZE)
|
|
{
|
|
error("gen: drc cache overflow!\n");
|
|
}
|
|
|
|
*drc_cache_top++ = (value >> 0) & 0xff;
|
|
*drc_cache_top++ = (value >> 8) & 0xff;
|
|
*drc_cache_top++ = (value >> 16) & 0xff;
|
|
*drc_cache_top++ = (value >> 24) & 0xff;
|
|
}
|
|
|
|
void gen(GENX86_OPCODE opcode, INT32 dst_param, INT32 src_param)
|
|
{
|
|
cumulative_instruction_amount++;
|
|
|
|
switch (opcode)
|
|
{
|
|
case ADD:
|
|
{
|
|
emit_byte(0x01);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case ADDI:
|
|
{
|
|
// don't generate anything for dummy code
|
|
if (src_param == 0)
|
|
return;
|
|
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ADDIM:
|
|
{
|
|
// don't generate anything for dummy code
|
|
if (src_param == 0)
|
|
return;
|
|
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0x05);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0x05);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ADDMR:
|
|
{
|
|
emit_byte(0x03);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case ADC:
|
|
{
|
|
emit_byte(0x11);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case ADCI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xd0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xd0 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ADCMR:
|
|
{
|
|
emit_byte(0x13);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case AND:
|
|
{
|
|
emit_byte(0x21);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case ANDI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xe0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xe0 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ANDIM:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0x25);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0x25);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ANDMR:
|
|
{
|
|
emit_byte(0x23);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case BSR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xbd);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case BSWAP:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xc8 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case BTIM:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xba);
|
|
emit_byte(0x25);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
break;
|
|
}
|
|
|
|
case BTRI:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xba);
|
|
emit_byte(0xf0 | dst_param);
|
|
emit_byte(src_param);
|
|
break;
|
|
}
|
|
|
|
case CALL:
|
|
{
|
|
emit_byte(0xff);
|
|
emit_byte(0xd0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case CALLI:
|
|
{
|
|
UINT32 s = (UINT64)(drc_cache_top) + 5;
|
|
emit_byte(0xe8);
|
|
emit_dword((UINT32)(dst_param) - s);
|
|
break;
|
|
}
|
|
|
|
case CMOVAMR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x47);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CMOVBMR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x42);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CMOVGMR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x4f);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CMOVLMR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x4c);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CMOVZMR:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x44);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CMP:
|
|
{
|
|
emit_byte(0x39);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case CMPI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xf8 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xf8 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CMPIM:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0x3d);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0x3d);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case CMPMR:
|
|
{
|
|
emit_byte(0x3b);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case CVTSD2SS:
|
|
{
|
|
emit_byte(0xf2);
|
|
emit_byte(0x0f);
|
|
emit_byte(0x5a);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case CVTSS2SD:
|
|
{
|
|
emit_byte(0xf3);
|
|
emit_byte(0x0f);
|
|
emit_byte(0x5a);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case FABS:
|
|
{
|
|
emit_byte(0xd9);
|
|
emit_byte(0xe1);
|
|
break;
|
|
}
|
|
|
|
case FCHS:
|
|
{
|
|
emit_byte(0xd9);
|
|
emit_byte(0xe0);
|
|
break;
|
|
}
|
|
|
|
case FADDM64:
|
|
{
|
|
emit_byte(0xdc);
|
|
emit_byte(0x05);
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case FDIVM64:
|
|
{
|
|
emit_byte(0xdc);
|
|
emit_byte(0x35);
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case FLDM64:
|
|
{
|
|
emit_byte(0xdd);
|
|
emit_byte(0x05);
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case FSTPM64:
|
|
{
|
|
emit_byte(0xdd);
|
|
emit_byte(0x1d);
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case IDIV:
|
|
{
|
|
emit_byte(0xf7);
|
|
emit_byte(0xf8 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case IMUL:
|
|
{
|
|
emit_byte(0xf7);
|
|
emit_byte(0xe8 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case JMPI:
|
|
{
|
|
UINT32 s = (UINT64)(drc_cache_top) + 5;
|
|
emit_byte(0xe9);
|
|
emit_dword((UINT32)(dst_param) - s);
|
|
return;
|
|
}
|
|
|
|
case JMPM:
|
|
{
|
|
emit_byte(0xff);
|
|
emit_byte(0x25);
|
|
emit_dword(dst_param);
|
|
return;
|
|
}
|
|
|
|
case JMPR:
|
|
{
|
|
emit_byte(0xff);
|
|
emit_byte(0xe0 | dst_param);
|
|
return;
|
|
}
|
|
|
|
case MOV:
|
|
{
|
|
emit_byte(0x89);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case MOVI:
|
|
{
|
|
emit_byte(0xc7);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVIM:
|
|
{
|
|
emit_byte(0xc7);
|
|
emit_byte(0x05);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVMR:
|
|
{
|
|
emit_byte(0x8b);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVRM:
|
|
{
|
|
emit_byte(0x89);
|
|
emit_byte(0x05 | (src_param << 3));
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case MOVR8M8:
|
|
{
|
|
emit_byte(0x88);
|
|
emit_byte(0x05 | (src_param << 3));
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case MOVM8R8:
|
|
{
|
|
emit_byte(0x8a);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
|
|
case MOVS_R8R32:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xbe);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVS_R16R32:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xbf);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVZ_M8R32:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xb6);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVZ_R8R32:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xb6);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVZ_R16R32:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0xb7);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVDRX:
|
|
{
|
|
emit_byte(0x66);
|
|
emit_byte(0x0f);
|
|
emit_byte(0x6e);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVDXR:
|
|
{
|
|
emit_byte(0x66);
|
|
emit_byte(0x0f);
|
|
emit_byte(0x7e);
|
|
emit_byte(0xc0 | (src_param << 3) | dst_param);
|
|
break;
|
|
}
|
|
|
|
case MOVQMX:
|
|
{
|
|
emit_byte(0xf3);
|
|
emit_byte(0x0f);
|
|
emit_byte(0x7e);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case MOVQXM:
|
|
{
|
|
emit_byte(0x66);
|
|
emit_byte(0x0f);
|
|
emit_byte(0xd6);
|
|
emit_byte(0x05 | (src_param << 3));
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case MUL:
|
|
{
|
|
emit_byte(0xf7);
|
|
emit_byte(0xe0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case NEG:
|
|
{
|
|
emit_byte(0xf7);
|
|
emit_byte(0xd8 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case NOT:
|
|
{
|
|
emit_byte(0xf7);
|
|
emit_byte(0xd0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case OR:
|
|
{
|
|
emit_byte(0x09);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case ORI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xc8 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xc8 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ORIM:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0x0d);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0x0d);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ORMR:
|
|
{
|
|
emit_byte(0x0b);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case POP:
|
|
{
|
|
emit_byte(0x58 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case POPAD:
|
|
{
|
|
emit_byte(0x61);
|
|
break;
|
|
}
|
|
|
|
case PUSH:
|
|
{
|
|
emit_byte(0x50 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case PUSHI:
|
|
{
|
|
emit_byte(0x68);
|
|
emit_dword(dst_param);
|
|
break;
|
|
}
|
|
|
|
case PUSHAD:
|
|
{
|
|
emit_byte(0x60);
|
|
break;
|
|
}
|
|
|
|
case RET:
|
|
{
|
|
emit_byte(0xc3);
|
|
break;
|
|
}
|
|
|
|
case ROLCL:
|
|
{
|
|
emit_byte(0xd3);
|
|
emit_byte(0xc0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case ROLI:
|
|
{
|
|
if (src_param == 1)
|
|
{
|
|
emit_byte(0xd1);
|
|
emit_byte(0xc0 | dst_param);
|
|
}
|
|
else
|
|
{
|
|
emit_byte(0xc1);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SETCR8:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x92);
|
|
emit_byte(0xc0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case SETNCR8:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x93);
|
|
emit_byte(0xc0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case SETZR8:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x94);
|
|
emit_byte(0xc0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case SHLCL:
|
|
{
|
|
emit_byte(0xd3);
|
|
emit_byte(0xe0 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case SHLI:
|
|
{
|
|
if (src_param == 1)
|
|
{
|
|
emit_byte(0xd1);
|
|
emit_byte(0xe0 | dst_param);
|
|
}
|
|
else
|
|
{
|
|
emit_byte(0xc1);
|
|
emit_byte(0xe0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SHRCL:
|
|
{
|
|
emit_byte(0xd3);
|
|
emit_byte(0xe8 | dst_param);
|
|
break;
|
|
}
|
|
|
|
case SHRI:
|
|
{
|
|
if (src_param == 1)
|
|
{
|
|
emit_byte(0xd1);
|
|
emit_byte(0xe8 | dst_param);
|
|
}
|
|
else
|
|
{
|
|
emit_byte(0xc1);
|
|
emit_byte(0xe8 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SUB:
|
|
{
|
|
emit_byte(0x29);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case SUBI:
|
|
{
|
|
// don't generate anything for dummy code
|
|
if (src_param == 0)
|
|
return;
|
|
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xe8 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xe8 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SUBIM:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0x2d);
|
|
emit_dword(dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0x2d);
|
|
emit_dword(dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SUBMR:
|
|
{
|
|
emit_byte(0x2b);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
case TESTI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0xf6);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0xf7);
|
|
emit_byte(0xc0 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case XCHGR8R8:
|
|
{
|
|
emit_byte(0x86);
|
|
emit_byte(0xc0 | (dst_param << 3) | src_param);
|
|
break;
|
|
}
|
|
|
|
case XOR:
|
|
{
|
|
emit_byte(0x31);
|
|
emit_byte(0xc0 | (src_param << 3) | (dst_param));
|
|
break;
|
|
}
|
|
|
|
case XORI:
|
|
{
|
|
if (src_param < 128 && src_param >= -128)
|
|
{
|
|
// 8-bit sign-extended immediate
|
|
emit_byte(0x83);
|
|
emit_byte(0xf0 | dst_param);
|
|
emit_byte(src_param);
|
|
}
|
|
else
|
|
{
|
|
// 32-bit immediate
|
|
emit_byte(0x81);
|
|
emit_byte(0xf0 | dst_param);
|
|
emit_dword(src_param);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case XORMR:
|
|
{
|
|
emit_byte(0x33);
|
|
emit_byte(0x05 | (dst_param << 3));
|
|
emit_dword(src_param);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printf("DRC ERROR: gen: unknown opcode %08X\n", opcode);
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void gen_jmp_target(JUMP_TARGET *target)
|
|
{
|
|
if (target->jump_type == JUMP_TYPE_NONE)
|
|
{
|
|
// target resolved first, this is a backwards jump
|
|
target->jump_type = JUMP_TYPE_BACKWARDS;
|
|
target->pointer = drc_cache_top;
|
|
}
|
|
else if (target->jump_type == JUMP_TYPE_FORWARD)
|
|
{
|
|
// source already resolved, backpatch the source jump
|
|
UINT8 *d = (UINT8 *)(target->pointer);
|
|
UINT8 *jump_offset = d - 4;
|
|
INT32 jump_length = drc_cache_top - d;
|
|
*jump_offset++ = (jump_length >> 0) & 0xff;
|
|
*jump_offset++ = (jump_length >> 8) & 0xff;
|
|
*jump_offset++ = (jump_length >> 16) & 0xff;
|
|
*jump_offset++ = (jump_length >> 24) & 0xff;
|
|
}
|
|
else
|
|
{
|
|
printf("DRC ERROR: gen_jmp_target: something went wrong!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void gen_jmp(GENX86_OPCODE opcode, JUMP_TARGET *target)
|
|
{
|
|
int jump_size;
|
|
UINT8 *s;
|
|
|
|
cumulative_instruction_amount++;
|
|
|
|
switch (opcode)
|
|
{
|
|
case JMP:
|
|
{
|
|
// TODO: check if 8-bit displacement is possible
|
|
emit_byte(0xe9);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JA:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x87);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JAE:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x83);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JB:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x82);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JG:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x8f);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JL:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x8c);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JNS:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x89);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JNZ:
|
|
{
|
|
// TODO: check if 8-bit displacement is possible
|
|
emit_byte(0x0f);
|
|
emit_byte(0x85);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
case JZ:
|
|
{
|
|
emit_byte(0x0f);
|
|
emit_byte(0x84);
|
|
jump_size = 4;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
printf("DRC ERROR: gen_jmp: unknown opcode %08X\n", opcode);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// get the proper source location
|
|
s = drc_cache_top + jump_size;
|
|
|
|
if (target->jump_type == JUMP_TYPE_NONE)
|
|
{
|
|
// jump source resolved first, this is a forward jump
|
|
target->jump_type = JUMP_TYPE_FORWARD;
|
|
target->pointer = s;
|
|
|
|
// emit the placeholder offset
|
|
if (jump_size == 1)
|
|
{
|
|
emit_byte(0x00);
|
|
}
|
|
else if (jump_size == 4)
|
|
{
|
|
emit_dword(0x00000000);
|
|
}
|
|
}
|
|
else if (target->jump_type == JUMP_TYPE_BACKWARDS)
|
|
{
|
|
// jump destination already resolved, generate the jump
|
|
INT32 jump_length = (UINT64)(target->pointer) - (UINT64)(s);
|
|
emit_dword(jump_length);
|
|
}
|
|
else
|
|
{
|
|
printf("DRC ERROR: gen_jmp: something went wrong!\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
void gen_jmp_rpr(INT32 reg1, INT32 reg2)
|
|
{
|
|
emit_byte(0xff);
|
|
emit_byte(0x20 | 0x04);
|
|
emit_byte(reg2 << 3 | reg1);
|
|
}
|
|
|
|
void gen_mov_dpr_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg)
|
|
{
|
|
emit_byte(0x8b);
|
|
emit_byte(0x80 | (dst_reg << 3) | (disp_reg));
|
|
emit_dword(disp);
|
|
}
|
|
|
|
void gen_mov_dprs_to_reg(INT32 dst_reg, INT32 disp, INT32 disp_reg, INT32 disp_reg_scale)
|
|
{
|
|
int scale;
|
|
switch (disp_reg_scale)
|
|
{
|
|
case 2: scale = 1; break;
|
|
case 4: scale = 2; break;
|
|
case 8: scale = 3; break;
|
|
default: scale = 0; break;
|
|
}
|
|
emit_byte(0x8b);
|
|
emit_byte((dst_reg << 3) | 0x04);
|
|
emit_byte(scale << 6 | disp_reg << 3 | 0x5);
|
|
emit_dword(disp);
|
|
}
|
|
|
|
void gen_mov_reg_to_dpr(INT32 src_reg, INT32 disp, INT32 disp_reg)
|
|
{
|
|
emit_byte(0x89);
|
|
emit_byte(0x80 | (src_reg << 3) | (disp_reg));
|
|
emit_dword(disp);
|
|
}
|
|
|
|
void gen_reset_cache(void)
|
|
{
|
|
drc_cache_top = drc_cache;
|
|
|
|
memset(drc_cache, 0, DRC_CACHE_SIZE);
|
|
}
|
|
|
|
UINT8 *gen_get_cache_pos(void)
|
|
{
|
|
return drc_cache_top;
|
|
}
|
|
|
|
UINT32 gen_get_instruction_amount(void)
|
|
{
|
|
return cumulative_instruction_amount;
|
|
}
|
|
|
|
void init_jmp_target(JUMP_TARGET *target)
|
|
{
|
|
target->jump_type = JUMP_TYPE_NONE;
|
|
}
|
|
|
|
void init_genx86(void)
|
|
{
|
|
drc_cache = malloc_exec(DRC_CACHE_SIZE);
|
|
drc_cache_top = drc_cache;
|
|
}
|
|
|
|
void shutdown_genx86(void)
|
|
{
|
|
// save cache
|
|
//save_file("drccache.bin", drc_cache, 0x800000, FALSE);
|
|
|
|
free_exec(drc_cache);
|
|
}
|