Supermodel/ppc_drc/genx86.c
2006-07-17 11:17:01 +00:00

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);
}