Implemented effective address compilation.
This commit is contained in:
parent
ee3f9210dc
commit
94fea237b4
13 changed files with 978 additions and 133 deletions
|
|
@ -23,64 +23,6 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
|
|||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (cpu_rm == 4)
|
||||
{
|
||||
uint8_t sib = rmdat >> 8;
|
||||
|
||||
switch (cpu_mod)
|
||||
{
|
||||
case 0:
|
||||
cpu_state.eaaddr = cpu_state.regs[sib & 7].l;
|
||||
cpu_state.pc++;
|
||||
break;
|
||||
case 1:
|
||||
cpu_state.pc++;
|
||||
cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l;
|
||||
// cpu_state.pc++;
|
||||
break;
|
||||
case 2:
|
||||
cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l;
|
||||
cpu_state.pc += 5;
|
||||
break;
|
||||
}
|
||||
/*SIB byte present*/
|
||||
if ((sib & 7) == 5 && !cpu_mod)
|
||||
cpu_state.eaaddr = getlong();
|
||||
else if ((sib & 6) == 4 && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
}
|
||||
if (((sib >> 3) & 7) != 4)
|
||||
cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_state.eaaddr = cpu_state.regs[cpu_rm].l;
|
||||
if (cpu_mod)
|
||||
{
|
||||
if (cpu_rm == 5 && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
}
|
||||
if (cpu_mod == 1)
|
||||
{
|
||||
cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8));
|
||||
cpu_state.pc++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpu_state.eaaddr += getlong();
|
||||
}
|
||||
}
|
||||
else if (cpu_rm == 5)
|
||||
{
|
||||
cpu_state.eaaddr = getlong();
|
||||
}
|
||||
}
|
||||
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
|
||||
{
|
||||
uint32_t addr = easeg + cpu_state.eaaddr;
|
||||
|
|
@ -96,33 +38,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
|
|||
eal_r = eal_w = NULL;
|
||||
easeg = cpu_state.ea_seg->base;
|
||||
ea_rseg = cpu_state.ea_seg->seg;
|
||||
if (!cpu_mod && cpu_rm == 6)
|
||||
{
|
||||
cpu_state.eaaddr = getword();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cpu_mod)
|
||||
{
|
||||
case 0:
|
||||
cpu_state.eaaddr = 0;
|
||||
break;
|
||||
case 1:
|
||||
cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++;
|
||||
break;
|
||||
case 2:
|
||||
cpu_state.eaaddr = getword();
|
||||
break;
|
||||
}
|
||||
cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]);
|
||||
if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs)
|
||||
{
|
||||
easeg = ss;
|
||||
ea_rseg = SS;
|
||||
cpu_state.ea_seg = &_ss;
|
||||
}
|
||||
cpu_state.eaaddr &= 0xFFFF;
|
||||
}
|
||||
if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
|
||||
{
|
||||
uint32_t addr = easeg + cpu_state.eaaddr;
|
||||
|
|
@ -133,8 +48,8 @@ static inline void fetch_ea_16_long(uint32_t rmdat)
|
|||
}
|
||||
}
|
||||
|
||||
#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; }
|
||||
#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1
|
||||
#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat);
|
||||
#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat);
|
||||
|
||||
|
||||
#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32)
|
||||
|
|
|
|||
245
src/codegen.c
245
src/codegen.c
|
|
@ -9,6 +9,8 @@
|
|||
#include "codegen_backend.h"
|
||||
#include "codegen_ir.h"
|
||||
|
||||
int has_ea;
|
||||
|
||||
codeblock_t *codeblock;
|
||||
codeblock_t **codeblock_hash;
|
||||
|
||||
|
|
@ -38,8 +40,211 @@ void codegen_generate_reset()
|
|||
last_op_ssegs = -1;
|
||||
last_op_ea_seg = NULL;
|
||||
last_op_32 = -1;
|
||||
has_ea = 0;
|
||||
}
|
||||
|
||||
static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc)
|
||||
{
|
||||
// pclog("codegen - mod=%i rm=%i reg=%i fetchdat=%08x\n", cpu_mod, cpu_rm, cpu_reg, fetchdat);
|
||||
if (!cpu_mod && cpu_rm == 6)
|
||||
{
|
||||
uint16_t addr = (fetchdat >> 8) & 0xffff;
|
||||
uop_MOV_IMM(ir, IREG_eaaddr, addr);
|
||||
(*op_pc) += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int base_reg, index_reg, offset;
|
||||
|
||||
switch (cpu_rm)
|
||||
{
|
||||
case 0: case 1: case 7:
|
||||
base_reg = IREG_EBX;
|
||||
break;
|
||||
case 2: case 3: case 6:
|
||||
base_reg = IREG_EBP;
|
||||
break;
|
||||
case 4:
|
||||
base_reg = IREG_ESI;
|
||||
break;
|
||||
case 5:
|
||||
base_reg = IREG_EDI;
|
||||
break;
|
||||
}
|
||||
uop_MOV(ir, IREG_eaaddr, base_reg);
|
||||
|
||||
if (!(cpu_rm & 4))
|
||||
{
|
||||
if (!(cpu_rm & 1))
|
||||
index_reg = IREG_ESI;
|
||||
else
|
||||
index_reg = IREG_EDI;
|
||||
|
||||
uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, index_reg);
|
||||
}
|
||||
|
||||
switch (cpu_mod)
|
||||
{
|
||||
case 1:
|
||||
offset = (int)(int8_t)((fetchdat >> 8) & 0xff);
|
||||
uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset);
|
||||
(*op_pc)++;
|
||||
break;
|
||||
case 2:
|
||||
offset = (fetchdat >> 8) & 0xffff;
|
||||
uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset);
|
||||
(*op_pc) += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff);
|
||||
|
||||
if (mod1seg[cpu_rm] == &ss && !op_ssegs)
|
||||
{
|
||||
op_ea_seg = &_ss;
|
||||
}
|
||||
}
|
||||
|
||||
return op_ea_seg;
|
||||
}
|
||||
|
||||
static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc)
|
||||
{
|
||||
uint32_t new_eaaddr;
|
||||
|
||||
if (cpu_rm == 4)
|
||||
{
|
||||
uint8_t sib = fetchdat >> 8;
|
||||
(*op_pc)++;
|
||||
|
||||
switch (cpu_mod)
|
||||
{
|
||||
case 0:
|
||||
if ((sib & 7) == 5)
|
||||
{
|
||||
new_eaaddr = fastreadl(cs + (*op_pc) + 1);
|
||||
uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr);
|
||||
(*op_pc) += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
uop_MOV(ir, IREG_eaaddr, sib & 7);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff);
|
||||
uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr);
|
||||
uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7);
|
||||
(*op_pc)++;
|
||||
break;
|
||||
case 2:
|
||||
new_eaaddr = fastreadl(cs + (*op_pc) + 1);
|
||||
uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr);
|
||||
uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7);
|
||||
(*op_pc) += 4;
|
||||
break;
|
||||
}
|
||||
// if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/
|
||||
// {
|
||||
// addbyte(0x05);
|
||||
// addlong(stack_offset);
|
||||
// }
|
||||
if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs)
|
||||
op_ea_seg = &_ss;
|
||||
if (((sib >> 3) & 7) != 4)
|
||||
{
|
||||
switch (sib >> 6)
|
||||
{
|
||||
case 0:
|
||||
uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7);
|
||||
break;
|
||||
case 1:
|
||||
uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 1);
|
||||
break;
|
||||
case 2:
|
||||
uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 2);
|
||||
break;
|
||||
case 3:
|
||||
uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!cpu_mod && cpu_rm == 5)
|
||||
{
|
||||
new_eaaddr = fastreadl(cs + (*op_pc) + 1);
|
||||
uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr);
|
||||
(*op_pc) += 4;
|
||||
return op_ea_seg;
|
||||
}
|
||||
uop_MOV(ir, IREG_eaaddr, cpu_rm);
|
||||
if (cpu_mod)
|
||||
{
|
||||
if (cpu_rm == 5 && !op_ssegs)
|
||||
op_ea_seg = &_ss;
|
||||
if (cpu_mod == 1)
|
||||
{
|
||||
uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, (uint32_t)(int8_t)(fetchdat >> 8));
|
||||
(*op_pc)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_eaaddr = fastreadl(cs + (*op_pc) + 1);
|
||||
uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, new_eaaddr);
|
||||
(*op_pc) += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return op_ea_seg;
|
||||
}
|
||||
|
||||
static uint8_t opcode_modrm[256] =
|
||||
{
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/
|
||||
|
||||
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/
|
||||
};
|
||||
static uint8_t opcode_0f_modrm[256] =
|
||||
{
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/
|
||||
1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/
|
||||
0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/
|
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /*a0*/
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/
|
||||
|
||||
1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/
|
||||
0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/
|
||||
0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/
|
||||
0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/
|
||||
};
|
||||
|
||||
void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc)
|
||||
{
|
||||
codeblock_t *block = &codeblock[block_current];
|
||||
|
|
@ -52,6 +257,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t
|
|||
x86seg *op_ea_seg = &_ds;
|
||||
int op_ssegs = 0;
|
||||
int over = 0;
|
||||
int test_modrm = 1;
|
||||
|
||||
op_ea_seg = &_ds;
|
||||
|
||||
|
|
@ -127,14 +333,44 @@ generate_call:
|
|||
//pclog("%04x:%08x : %02x\n", CS, new_pc, opcode);
|
||||
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask];
|
||||
|
||||
if (!test_modrm ||
|
||||
(op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) ||
|
||||
(op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))
|
||||
{
|
||||
//int stack_offset = 0;
|
||||
|
||||
// if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/
|
||||
// stack_offset = (op_32 & 0x100) ? 4 : 2;
|
||||
|
||||
cpu_mod = (fetchdat >> 6) & 3;
|
||||
cpu_reg = (fetchdat >> 3) & 7;
|
||||
cpu_rm = fetchdat & 7;
|
||||
|
||||
uop_MOV_IMM(ir, IREG_rm_mod_reg, cpu_rm | (cpu_mod << 8) | (cpu_reg << 16));
|
||||
|
||||
// op_pc += pc_off;
|
||||
if (cpu_mod != 3 && !(op_32 & 0x200))
|
||||
{
|
||||
op_ea_seg = codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc);
|
||||
// has_ea = 1;
|
||||
}
|
||||
if (cpu_mod != 3 && (op_32 & 0x200))
|
||||
{
|
||||
op_ea_seg = codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc);
|
||||
// has_ea = 1;
|
||||
}
|
||||
// op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset);
|
||||
// op_pc -= pc_off;
|
||||
}
|
||||
|
||||
|
||||
uop_MOV_IMM(ir, IREG_pc, op_pc);
|
||||
uop_MOV_IMM(ir, IREG_oldpc, old_pc);
|
||||
if (op_32 != last_op_32)
|
||||
uop_MOV_IMM(ir, IREG_op32, op_32);
|
||||
/*Lazy ea_seg/ssegs updating isn't safe until EA calculation is implemented*/
|
||||
// if (op_ea_seg != last_op_ea_seg)
|
||||
if (op_ea_seg != last_op_ea_seg)
|
||||
uop_MOV_PTR(ir, IREG_ea_seg, (void *)op_ea_seg);
|
||||
// if (op_ssegs != last_op_ssegs)
|
||||
if (op_ssegs != last_op_ssegs)
|
||||
uop_MOV_IMM(ir, IREG_ssegs, op_ssegs);
|
||||
uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat);
|
||||
uop_CALL_INSTRUCTION_FUNC(ir, op);
|
||||
|
|
@ -150,4 +386,7 @@ generate_call:
|
|||
CPU_BLOCK_END();
|
||||
|
||||
codegen_endpc = (cs + cpu_state.pc) + 8;
|
||||
|
||||
// if (has_ea)
|
||||
// fatal("Has EA\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] =
|
|||
REG_R4,
|
||||
REG_R5,
|
||||
REG_R6,
|
||||
// REG_X22,
|
||||
// REG_X23
|
||||
};
|
||||
|
||||
void codegen_backend_init()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#define REG_W28 28
|
||||
#define REG_W29 29
|
||||
#define REG_W30 30
|
||||
#define REG_WZR 31
|
||||
|
||||
#define REG_X0 0
|
||||
#define REG_X1 1
|
||||
|
|
@ -61,6 +62,7 @@
|
|||
#define REG_X28 28
|
||||
#define REG_X29 29
|
||||
#define REG_X30 30
|
||||
#define REG_XZR 31
|
||||
|
||||
#define REG_SP 31
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
||||
{
|
||||
*(uint32_t *)&block->data[block_pos] = val;
|
||||
*(uint32_t *)&block->data[block_pos] = val;
|
||||
block_pos += 4;
|
||||
if (block_pos >= BLOCK_MAX)
|
||||
{
|
||||
|
|
@ -21,6 +21,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
|||
#define Rd(x) (x)
|
||||
#define Rn(x) ((x) << 5)
|
||||
#define Rt2(x) ((x) << 10)
|
||||
#define Rm(x) ((x) << 16)
|
||||
|
||||
#define shift_imm6(x) ((x) << 10)
|
||||
|
||||
#define DATA_OFFSET_UP (1 << 23)
|
||||
#define DATA_OFFSET_DOWN (0 << 23)
|
||||
|
|
@ -30,6 +33,8 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
|||
#define COND_AL (0xe << COND_SHIFT)
|
||||
|
||||
#define OPCODE_SHIFT 24
|
||||
#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT)
|
||||
#define OPCODE_AND_IMM (0x11 << OPCODE_SHIFT)
|
||||
#define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT)
|
||||
#define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT)
|
||||
#define OPCODE_LDR_LITERAL_X (0x58 << OPCODE_SHIFT)
|
||||
|
|
@ -37,20 +42,28 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
|||
#define OPCODE_MOVK_W (0x0e5 << 23)
|
||||
#define OPCODE_MOVZ_W (0x0a5 << 23)
|
||||
|
||||
#define OPCODE_LDR_IMM_W (0x2e5 << 22)
|
||||
#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22)
|
||||
#define OPCODE_STP_PREIDX_X (0x2a6 << 22)
|
||||
#define OPCODE_STR_IMM_W (0x2e4 << 22)
|
||||
#define OPCODE_STR_IMM_Q (0x3e4 << 22)
|
||||
#define OPCODE_STRB_IMM (0x0e4 << 22)
|
||||
|
||||
#define OPCODE_ADD_LSL (0x058 << 21)
|
||||
#define OPCODE_AND_LSL (0x050 << 21)
|
||||
#define OPCODE_ORR_LSL (0x150 << 21)
|
||||
|
||||
#define OPCODE_BLR (0xd63f0000)
|
||||
#define OPCODE_NOP (0xd503201f)
|
||||
#define OPCODE_RET (0xd65f0000)
|
||||
|
||||
#define DATPROC_SHIFT(sh) (sh << 10)
|
||||
#define DATPROC_IMM_SHIFT(sh) (sh << 22)
|
||||
#define MOV_WIDE_HW(hw) (hw << 21)
|
||||
|
||||
#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15)
|
||||
#define IMM16(imm_data) (imm_data << 5)
|
||||
#define IMM12(imm_data) ((imm_data) << 10)
|
||||
#define IMM16(imm_data) ((imm_data) << 5)
|
||||
|
||||
#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0)
|
||||
|
||||
|
|
@ -112,7 +125,39 @@ static inline int imm_is_imm16(uint32_t imm_data)
|
|||
return 1;
|
||||
return 0;
|
||||
}
|
||||
static inline int imm_is_imm12(uint32_t imm_data)
|
||||
{
|
||||
if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data)
|
||||
{
|
||||
if (!(imm_data & 0xff000000))
|
||||
{
|
||||
if (imm_data & 0xfff)
|
||||
codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0));
|
||||
if (imm_data & 0xfff000)
|
||||
codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff);
|
||||
host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000);
|
||||
codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0));
|
||||
}
|
||||
}
|
||||
void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift)
|
||||
{
|
||||
codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift));
|
||||
}
|
||||
|
||||
void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data)
|
||||
{
|
||||
host_arm64_mov_imm(block, REG_W16, imm_data);
|
||||
codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0));
|
||||
}
|
||||
|
||||
void host_arm64_BLR(codeblock_t *block, int addr_reg)
|
||||
{
|
||||
|
|
@ -134,6 +179,13 @@ void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, in
|
|||
codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2));
|
||||
}
|
||||
|
||||
void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset)
|
||||
{
|
||||
if (!in_range12_w(offset))
|
||||
fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset);
|
||||
codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg));
|
||||
}
|
||||
|
||||
void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset)
|
||||
{
|
||||
int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos;
|
||||
|
|
@ -153,6 +205,11 @@ void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offs
|
|||
codegen_addlong(block, OPCODE_LDR_LITERAL_X | OFFSET19(offset) | Rt(dest_reg));
|
||||
}
|
||||
|
||||
void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift)
|
||||
{
|
||||
codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift));
|
||||
}
|
||||
|
||||
void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data)
|
||||
{
|
||||
int hw;
|
||||
|
|
@ -237,6 +294,30 @@ void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data)
|
|||
}
|
||||
|
||||
|
||||
static int codegen_ADD(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_AND_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_call(block, uop->p);
|
||||
|
|
@ -270,6 +351,12 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_MOV(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_MOV_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm64_mov_imm(block, uop->dest_reg_a_real, uop->imm_data);
|
||||
|
|
@ -319,10 +406,24 @@ const uOpFn uop_handlers[UOP_MAX] =
|
|||
[UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM,
|
||||
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8,
|
||||
|
||||
[UOP_MOV & UOP_MASK] = codegen_MOV,
|
||||
[UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR,
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM,
|
||||
|
||||
[UOP_ADD & UOP_MASK] = codegen_ADD,
|
||||
[UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM,
|
||||
[UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT,
|
||||
[UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM
|
||||
};
|
||||
|
||||
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p)
|
||||
{
|
||||
if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state))
|
||||
host_arm64_LDR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state);
|
||||
else
|
||||
fatal("codegen_direct_read_32 - not in range\n");
|
||||
}
|
||||
|
||||
void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
|
||||
{
|
||||
if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state))
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#define REG_CPUSTATE REG_R10
|
||||
#define REG_LITERAL REG_R11
|
||||
|
||||
#define REG_TEMP REG_R3
|
||||
|
||||
#define REG_MASK_R0 (1 << REG_R0)
|
||||
#define REG_MASK_R1 (1 << REG_R1)
|
||||
#define REG_MASK_R2 (1 << REG_R2)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
|||
|
||||
#define OPCODE_SHIFT 20
|
||||
#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT)
|
||||
#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT)
|
||||
#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT)
|
||||
#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT)
|
||||
#define OPCODE_B (0xa0 << OPCODE_SHIFT)
|
||||
#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT)
|
||||
#define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT)
|
||||
|
|
@ -45,6 +48,18 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
|
|||
|
||||
#define B_OFFSET(x) (((x) >> 2) & 0xffffff)
|
||||
|
||||
#define SHIFT_TYPE_SHIFT 5
|
||||
#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT)
|
||||
#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT)
|
||||
#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT)
|
||||
#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT)
|
||||
|
||||
#define SHIFT_TYPE_IMM (0 << 4)
|
||||
#define SHIFT_TYPE_REG (1 << 4)
|
||||
|
||||
#define SHIFT_IMM_SHIFT 7
|
||||
#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT))
|
||||
|
||||
static int literal_offset = 0;
|
||||
void codegen_reset_literal_pool(codeblock_t *block)
|
||||
{
|
||||
|
|
@ -114,14 +129,49 @@ static inline int in_range(void *addr, void *base)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift);
|
||||
void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift);
|
||||
|
||||
void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm)
|
||||
{
|
||||
uint32_t arm_imm;
|
||||
|
||||
if (!get_arm_imm(imm, &arm_imm))
|
||||
fatal("host_arm_ADD_IMM !check_arm_imm %08x\n", imm);
|
||||
if (get_arm_imm(imm, &arm_imm))
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = add_literal(block, imm);
|
||||
host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset);
|
||||
host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0);
|
||||
}
|
||||
}
|
||||
|
||||
codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm);
|
||||
void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift)
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift));
|
||||
}
|
||||
|
||||
void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm)
|
||||
{
|
||||
uint32_t arm_imm;
|
||||
|
||||
if (get_arm_imm(imm, &arm_imm))
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = add_literal(block, imm);
|
||||
host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset);
|
||||
host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift)
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift));
|
||||
}
|
||||
|
||||
void host_arm_BLX(codeblock_t *block, int addr_reg)
|
||||
|
|
@ -153,15 +203,20 @@ void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm)
|
|||
{
|
||||
uint32_t arm_imm;
|
||||
|
||||
if (!get_arm_imm(imm, &arm_imm))
|
||||
fatal("host_arm_MOV_IMM !check_arm_imm %08x\n", imm);
|
||||
|
||||
codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm);
|
||||
if (get_arm_imm(imm, &arm_imm))
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm);
|
||||
}
|
||||
else
|
||||
{
|
||||
int offset = add_literal(block, imm);
|
||||
host_arm_LDR_IMM(block, dst_reg, REG_LITERAL, offset);
|
||||
}
|
||||
}
|
||||
|
||||
void host_arm_MOV_REG(codeblock_t *block, int dst_reg, int src_reg)
|
||||
void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift)
|
||||
{
|
||||
codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg));
|
||||
codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift));
|
||||
}
|
||||
|
||||
void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask)
|
||||
|
|
@ -204,7 +259,31 @@ void host_arm_call(codeblock_t *block, void *dst_addr)
|
|||
|
||||
void host_arm_nop(codeblock_t *block)
|
||||
{
|
||||
host_arm_MOV_REG(block, REG_R0, REG_R0);
|
||||
host_arm_MOV_REG_LSL(block, REG_R0, REG_R0, 0);
|
||||
}
|
||||
|
||||
static int codegen_ADD(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm_AND_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
|
||||
|
|
@ -269,6 +348,13 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_MOV(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_arm_MOV_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
uint32_t arm_imm;
|
||||
|
|
@ -332,10 +418,24 @@ const uOpFn uop_handlers[UOP_MAX] =
|
|||
[UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM,
|
||||
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8,
|
||||
|
||||
[UOP_MOV & UOP_MASK] = codegen_MOV,
|
||||
[UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR,
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM,
|
||||
|
||||
[UOP_ADD & UOP_MASK] = codegen_ADD,
|
||||
[UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM,
|
||||
[UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT,
|
||||
[UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM
|
||||
};
|
||||
|
||||
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p)
|
||||
{
|
||||
if (in_range(p, &cpu_state))
|
||||
host_arm_LDR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state);
|
||||
else
|
||||
fatal("codegen_direct_read_32 - not in range\n");
|
||||
}
|
||||
|
||||
void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
|
||||
{
|
||||
if (in_range(p, &cpu_state))
|
||||
|
|
|
|||
|
|
@ -87,6 +87,13 @@ static inline void codegen_addquad(codeblock_t *block, uint64_t val)
|
|||
}
|
||||
}
|
||||
|
||||
static int is_imm8(uint32_t imm_data)
|
||||
{
|
||||
if (imm_data <= 0x7f || imm_data >= 0xffffff80)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void call(codeblock_t *block, uintptr_t func)
|
||||
{
|
||||
uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5];
|
||||
|
|
@ -104,6 +111,62 @@ static inline void call(codeblock_t *block, uintptr_t func)
|
|||
}
|
||||
}
|
||||
|
||||
static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data)
|
||||
{
|
||||
if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8))
|
||||
fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n");
|
||||
|
||||
if (is_imm8(imm_data))
|
||||
{
|
||||
codegen_addbyte3(block, 0x83, 0xc0 | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst_reg == REG_EAX)
|
||||
{
|
||||
codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_addbyte2(block, 0x81, 0xc0 | (dst_reg & 7)); /*ADD dst_reg, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data)
|
||||
{
|
||||
if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8))
|
||||
fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n");
|
||||
|
||||
if (is_imm8(imm_data))
|
||||
{
|
||||
codegen_addbyte3(block, 0x83, 0xe0 | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst_reg == REG_EAX)
|
||||
{
|
||||
codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_addbyte2(block, 0x81, 0xe0 | (dst_reg & 7)); /*AND dst_reg, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b)
|
||||
{
|
||||
if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8))
|
||||
fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n");
|
||||
|
||||
codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | (src_reg_b & 7)); /*ADD dst_reg, src_reg_b*/
|
||||
}
|
||||
|
||||
static void host_x86_CALL(codeblock_t *block, void *p)
|
||||
{
|
||||
call(block, (uintptr_t)p);
|
||||
|
|
@ -115,13 +178,22 @@ static void host_x86_JNZ(codeblock_t *block, void *p)
|
|||
codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]);
|
||||
}
|
||||
|
||||
static void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift)
|
||||
{
|
||||
if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8))
|
||||
fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n");
|
||||
|
||||
codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/
|
||||
(shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7));
|
||||
}
|
||||
|
||||
static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
|
||||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/
|
||||
codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/
|
||||
codegen_addbyte(block, imm_data);
|
||||
}
|
||||
else
|
||||
|
|
@ -139,7 +211,7 @@ static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_dat
|
|||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/
|
||||
codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
else
|
||||
|
|
@ -156,16 +228,19 @@ static void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg)
|
|||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (src_reg & 8)
|
||||
fatal("host_x86_MOV8_ABS_REG - bad reg\n");
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/
|
||||
codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)p >> 32)
|
||||
fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p);
|
||||
codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/
|
||||
codegen_addbyte(block, 0x05 | (src_reg << 3));
|
||||
codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3));
|
||||
codegen_addlong(block, (uint32_t)(uintptr_t)p);
|
||||
}
|
||||
}
|
||||
|
|
@ -173,16 +248,19 @@ static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg)
|
|||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (src_reg & 8)
|
||||
fatal("host_x86_MOV32_ABS_REG - bad reg\n");
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/
|
||||
codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)p >> 32)
|
||||
fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p);
|
||||
codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/
|
||||
codegen_addbyte(block, 0x05 | (src_reg << 3));
|
||||
codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3));
|
||||
codegen_addlong(block, (uint32_t)(uintptr_t)p);
|
||||
}
|
||||
}
|
||||
|
|
@ -190,26 +268,47 @@ static void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg)
|
|||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (src_reg & 8)
|
||||
fatal("host_x86_MOV64_ABS_REG - bad reg\n");
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte4(block, 0x48, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/
|
||||
codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((uintptr_t)p >> 32)
|
||||
fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p);
|
||||
codegen_addbyte4(block, 0x48, 0x89, 0x04 | (src_reg << 3), 0x25); /*MOV [p], src_reg*/
|
||||
codegen_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/
|
||||
codegen_addlong(block, (uint32_t)(uintptr_t)p);
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p)
|
||||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (dst_reg & 8)
|
||||
fatal("host_x86_MOV32_REG_ABS reg & 8\n");
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal("host_x86_MOV32_REG_ABS - out of range\n");
|
||||
codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/
|
||||
codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3));
|
||||
codegen_addlong(block, (uint32_t)(uintptr_t)p);
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data)
|
||||
{
|
||||
if (reg & 8)
|
||||
fatal("host_x86_MOV32_REG_IMM reg & 8\n");
|
||||
codegen_addbyte(block, 0xb8 | reg); /*MOV reg, imm_data*/
|
||||
codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
|
||||
|
|
@ -217,10 +316,17 @@ static void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_dat
|
|||
{
|
||||
if (reg & 8)
|
||||
fatal("host_x86_MOV64_REG_IMM reg & 8\n");
|
||||
codegen_addbyte2(block, 0x48, 0xb8 | reg); /*MOVQ reg, imm_data*/
|
||||
codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/
|
||||
codegen_addquad(block, imm_data);
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg)
|
||||
{
|
||||
if ((dst_reg & 8) || (src_reg & 8))
|
||||
fatal("host_x86_MOV32_REG_REG - bad reg\n");
|
||||
|
||||
codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3));
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data)
|
||||
{
|
||||
|
|
@ -244,9 +350,42 @@ static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_
|
|||
|
||||
#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3))
|
||||
|
||||
static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg)
|
||||
static void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg)
|
||||
{
|
||||
codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/
|
||||
if ((dst_reg & 8) || (src_reg & 8))
|
||||
fatal("host_x86_TEST32_REG - bad reg\n");
|
||||
codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/
|
||||
}
|
||||
|
||||
|
||||
static int codegen_ADD(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_ADD32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
if (!uop->imm_data)
|
||||
host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);
|
||||
else if (uop->imm_data < 4)
|
||||
host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data);
|
||||
else
|
||||
fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_AND32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
|
||||
|
|
@ -287,6 +426,11 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_MOV(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_MOV32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real);
|
||||
return 0;
|
||||
}
|
||||
static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, uop->imm_data);
|
||||
|
|
@ -325,10 +469,21 @@ const uOpFn uop_handlers[UOP_MAX] =
|
|||
[UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM,
|
||||
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8,
|
||||
|
||||
[UOP_MOV & UOP_MASK] = codegen_MOV,
|
||||
[UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR,
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM,
|
||||
|
||||
[UOP_ADD & UOP_MASK] = codegen_ADD,
|
||||
[UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM,
|
||||
[UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT,
|
||||
[UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM
|
||||
};
|
||||
|
||||
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p)
|
||||
{
|
||||
host_x86_MOV32_REG_ABS(block, host_reg, p);
|
||||
}
|
||||
|
||||
void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
|
||||
{
|
||||
host_x86_MOV8_ABS_REG(block, p, host_reg);
|
||||
|
|
|
|||
|
|
@ -86,6 +86,70 @@ static inline void codegen_addquad(codeblock_t *block, uint64_t val)
|
|||
CPU_BLOCK_END();
|
||||
}
|
||||
}
|
||||
|
||||
static int is_imm8(uint32_t imm_data)
|
||||
{
|
||||
if (imm_data <= 0x7f || imm_data >= 0xffffff80)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data)
|
||||
{
|
||||
if (dst_reg != src_reg)
|
||||
fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n");
|
||||
|
||||
if (is_imm8(imm_data))
|
||||
{
|
||||
codegen_addbyte3(block, 0x83, 0xc0 | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst_reg == REG_EAX)
|
||||
{
|
||||
codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_addbyte2(block, 0x81, 0xc0 | dst_reg); /*ADD dst_reg, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data)
|
||||
{
|
||||
if (dst_reg != src_reg)
|
||||
fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n");
|
||||
|
||||
if (is_imm8(imm_data))
|
||||
{
|
||||
codegen_addbyte3(block, 0x83, 0xe0 | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dst_reg == REG_EAX)
|
||||
{
|
||||
codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_addbyte2(block, 0x81, 0xe0 | dst_reg); /*AND dst_reg, imm_data*/
|
||||
codegen_addlong(block, imm_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b)
|
||||
{
|
||||
if (dst_reg != src_reg_a)
|
||||
fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n");
|
||||
|
||||
codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | src_reg_b); /*ADD dst_reg, src_reg_b*/
|
||||
}
|
||||
|
||||
static void host_x86_CALL(codeblock_t *block, void *p)
|
||||
{
|
||||
codegen_addbyte(block, 0xe8); /*CALL*/
|
||||
|
|
@ -98,6 +162,11 @@ static void host_x86_JNZ(codeblock_t *block, void *p)
|
|||
codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]);
|
||||
}
|
||||
|
||||
static void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift)
|
||||
{
|
||||
codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/
|
||||
}
|
||||
|
||||
static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
|
||||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
|
@ -162,6 +231,21 @@ static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg)
|
|||
}
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p)
|
||||
{
|
||||
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
|
||||
|
||||
if (offset >= -128 && offset < 127)
|
||||
{
|
||||
codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/
|
||||
}
|
||||
else
|
||||
{
|
||||
codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/
|
||||
codegen_addbyte(block, 0x05 | (dst_reg << 3));
|
||||
codegen_addlong(block, (uint32_t)p);
|
||||
}
|
||||
}
|
||||
static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data)
|
||||
{
|
||||
if (!imm_data)
|
||||
|
|
@ -175,6 +259,11 @@ static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm
|
|||
}
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg)
|
||||
{
|
||||
codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3));
|
||||
}
|
||||
|
||||
static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data)
|
||||
{
|
||||
if (!offset)
|
||||
|
|
@ -207,6 +296,36 @@ static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_ho
|
|||
pclog(" %04x:%04x : %08x %08x %08x %08x\n", CS, cpu_state.pc, AX, BX, CX, DX);
|
||||
}*/
|
||||
|
||||
static int codegen_ADD(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_ADD32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
if (!uop->imm_data)
|
||||
host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real);
|
||||
else if (uop->imm_data < 4)
|
||||
host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data);
|
||||
else
|
||||
fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_AND_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_AND32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_CALL(block, uop->p);
|
||||
|
|
@ -238,6 +357,11 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int codegen_MOV(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_MOV32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real);
|
||||
return 0;
|
||||
}
|
||||
static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
|
||||
{
|
||||
host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, uop->imm_data);
|
||||
|
|
@ -272,10 +396,21 @@ const uOpFn uop_handlers[UOP_MAX] =
|
|||
[UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM,
|
||||
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8,
|
||||
|
||||
[UOP_MOV & UOP_MASK] = codegen_MOV,
|
||||
[UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR,
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM
|
||||
[UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM,
|
||||
|
||||
[UOP_ADD & UOP_MASK] = codegen_ADD,
|
||||
[UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM,
|
||||
[UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT,
|
||||
[UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM
|
||||
};
|
||||
|
||||
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p)
|
||||
{
|
||||
host_x86_MOV32_REG_ABS(block, host_reg, p);
|
||||
}
|
||||
|
||||
void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
|
||||
{
|
||||
host_x86_MOV8_ABS_REG(block, p, host_reg);
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
#include "codegen_ir.h"
|
||||
#include "codegen_reg.h"
|
||||
|
||||
extern int has_ea;
|
||||
static ir_data_t ir_block;
|
||||
|
||||
ir_data_t *codegen_ir_init()
|
||||
{
|
||||
ir_block.wr_pos = 0;
|
||||
//pclog("codegen_ir_init\n");
|
||||
// pclog("codegen_ir_init %04x:%04x\n", CS,cpu_state.pc);
|
||||
|
||||
return &ir_block;
|
||||
}
|
||||
|
|
@ -24,10 +25,19 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
|
|||
{
|
||||
uop_t *uop = &ir->uops[c];
|
||||
|
||||
//pclog("uOP %i : %08x\n", c, uop->type);
|
||||
// pclog("uOP %i : %08x\n", c, uop->type);
|
||||
|
||||
if (uop->type & UOP_TYPE_PARAMS_REGS)
|
||||
{
|
||||
codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b);
|
||||
if (uop->src_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a);
|
||||
}
|
||||
if (uop->src_reg_b.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b);
|
||||
}
|
||||
if (uop->dest_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a);
|
||||
|
|
@ -42,5 +52,6 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
|
|||
|
||||
codegen_backend_epilogue(block);
|
||||
|
||||
//fatal("IR compilation complete\n");
|
||||
// if (has_ea)
|
||||
// fatal("IR compilation complete\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,8 +32,13 @@
|
|||
#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13)
|
||||
#define UOP_MOV_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x20)
|
||||
#define UOP_MOV_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x21)
|
||||
#define UOP_MOV (UOP_TYPE_PARAMS_REGS | 0x22)
|
||||
#define UOP_ADD (UOP_TYPE_PARAMS_REGS | 0x30)
|
||||
#define UOP_ADD_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x31)
|
||||
#define UOP_AND_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x32)
|
||||
#define UOP_ADD_LSHIFT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x33)
|
||||
|
||||
#define UOP_MAX 0x22
|
||||
#define UOP_MAX 0x34
|
||||
|
||||
#define UOP_MASK 0xffff
|
||||
|
||||
|
|
@ -43,10 +48,10 @@ typedef struct uop_t
|
|||
ir_reg_t dest_reg_a;
|
||||
ir_reg_t src_reg_a;
|
||||
ir_reg_t src_reg_b;
|
||||
ir_reg_t src_reg_c;
|
||||
uint32_t imm_data;
|
||||
void *p;
|
||||
ir_host_reg_t dest_reg_a_real;
|
||||
ir_host_reg_t src_reg_a_real, src_reg_b_real;
|
||||
} uop_t;
|
||||
|
||||
#define UOP_NR_MAX 4096
|
||||
|
|
@ -69,7 +74,7 @@ static inline uop_t *uop_alloc(ir_data_t *ir)
|
|||
uop->dest_reg_a = invalid_ir_reg;
|
||||
uop->src_reg_a = invalid_ir_reg;
|
||||
uop->src_reg_b = invalid_ir_reg;
|
||||
uop->src_reg_c = invalid_ir_reg;
|
||||
// uop->src_reg_c = invalid_ir_reg;
|
||||
|
||||
return uop;
|
||||
}
|
||||
|
|
@ -100,6 +105,46 @@ static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int
|
|||
uop->p = p;
|
||||
}
|
||||
|
||||
static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg)
|
||||
{
|
||||
uop_t *uop = uop_alloc(ir);
|
||||
|
||||
uop->type = uop_type;
|
||||
uop->src_reg_a = codegen_reg_read(src_reg);
|
||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
||||
}
|
||||
|
||||
static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b)
|
||||
{
|
||||
uop_t *uop = uop_alloc(ir);
|
||||
|
||||
uop->type = uop_type;
|
||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
||||
}
|
||||
|
||||
static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm)
|
||||
{
|
||||
uop_t *uop = uop_alloc(ir);
|
||||
|
||||
uop->type = uop_type;
|
||||
uop->src_reg_a = codegen_reg_read(src_reg_a);
|
||||
uop->src_reg_b = codegen_reg_read(src_reg_b);
|
||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
||||
uop->imm_data = imm;
|
||||
}
|
||||
|
||||
static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm)
|
||||
{
|
||||
uop_t *uop = uop_alloc(ir);
|
||||
|
||||
uop->type = uop_type;
|
||||
uop->src_reg_a = codegen_reg_read(src_reg);
|
||||
uop->dest_reg_a = codegen_reg_write(dest_reg);
|
||||
uop->imm_data = imm;
|
||||
}
|
||||
|
||||
static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm)
|
||||
{
|
||||
uop_t *uop = uop_alloc(ir);
|
||||
|
|
@ -129,15 +174,23 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p
|
|||
|
||||
#define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm)
|
||||
|
||||
#define uop_ADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ADD, ir, dst_reg, src_reg_a, src_reg_b)
|
||||
#define uop_ADD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ADD_IMM, ir, dst_reg, src_reg, imm)
|
||||
#define uop_ADD_LSHIFT(ir, dst_reg, src_reg_a, src_reg_b, shift) uop_gen_reg_dst_src2_imm(UOP_ADD_LSHIFT, ir, dst_reg, src_reg_a, src_reg_b, shift)
|
||||
#define uop_AND_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_AND_IMM, ir, dst_reg, src_reg, imm)
|
||||
|
||||
#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p)
|
||||
#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p)
|
||||
|
||||
#define uop_MOV(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV, ir, dst_reg, src_reg)
|
||||
#define uop_MOV_IMM(ir, reg, imm) uop_gen_reg_dst_imm(UOP_MOV_IMM, ir, reg, imm)
|
||||
#define uop_MOV_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_PTR, ir, reg, p)
|
||||
|
||||
#define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm)
|
||||
#define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm)
|
||||
|
||||
void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p);
|
||||
|
||||
void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg);
|
||||
void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg);
|
||||
void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ uint8_t reg_version_refcount[IREG_COUNT][256];
|
|||
ir_reg_t invalid_ir_reg = {IREG_INVALID};
|
||||
|
||||
ir_reg_t host_regs[CODEGEN_HOST_REGS];
|
||||
static uint8_t host_reg_dirty[CODEGEN_HOST_REGS];
|
||||
|
||||
static uint8_t host_regs_locked;
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
@ -49,6 +52,8 @@ struct
|
|||
[IREG_op32] = {REG_DWORD, &cpu_state.op32},
|
||||
[IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs},
|
||||
|
||||
[IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data},
|
||||
|
||||
/*Temporary registers are stored on the stack, and are not guaranteed to
|
||||
be preserved across uOPs. They will not be written back if they will
|
||||
not be read again.*/
|
||||
|
|
@ -76,6 +81,21 @@ static inline int ir_reg_is_invalid(ir_reg_t ir_reg)
|
|||
return (ir_reg.reg == IREG_INVALID);
|
||||
}
|
||||
|
||||
static void codegen_reg_load(codeblock_t *block, int c, ir_reg_t ir_reg)
|
||||
{
|
||||
switch (ireg_data[ir_reg.reg].native_size)
|
||||
{
|
||||
case REG_DWORD:
|
||||
codegen_direct_read_32(block, codegen_host_reg_list[c], ireg_data[ir_reg.reg].p);
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("codegen_reg_load - native_size=%i\n", ireg_data[ir_reg.reg].native_size);
|
||||
}
|
||||
|
||||
host_regs[c] = ir_reg;
|
||||
}
|
||||
|
||||
static void codegen_reg_writeback(codeblock_t *block, int c)
|
||||
{
|
||||
int ir_reg = host_regs[c].reg;
|
||||
|
|
@ -101,27 +121,135 @@ static void codegen_reg_writeback(codeblock_t *block, int c)
|
|||
host_regs[c] = invalid_ir_reg;
|
||||
}
|
||||
|
||||
ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg)
|
||||
void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b)
|
||||
{
|
||||
int c;
|
||||
int dest_reference = 0;
|
||||
|
||||
host_regs_locked = 0;
|
||||
|
||||
/* pclog("alloc_register: dst=%i.%i src_a=%i.%i src_b=%i.%i\n", dest_reg_a.reg, dest_reg_a.version,
|
||||
src_reg_a.reg, src_reg_a.version,
|
||||
src_reg_b.reg, src_reg_b.version);*/
|
||||
|
||||
if (!ir_reg_is_invalid(dest_reg_a))
|
||||
{
|
||||
if (!ir_reg_is_invalid(src_reg_a) && src_reg_a.reg == dest_reg_a.reg && src_reg_a.version == dest_reg_a.version-1)
|
||||
dest_reference++;
|
||||
if (!ir_reg_is_invalid(src_reg_b) && src_reg_b.reg == dest_reg_a.reg && src_reg_b.version == dest_reg_a.version-1)
|
||||
dest_reference++;
|
||||
}
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (!ir_reg_is_invalid(src_reg_a) && host_regs[c].reg == src_reg_a.reg)
|
||||
{
|
||||
if (host_regs[c].version != src_reg_a.version)
|
||||
fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_a.version\n");
|
||||
host_regs_locked |= (1 << c);
|
||||
}
|
||||
if (!ir_reg_is_invalid(src_reg_b) && host_regs[c].reg == src_reg_b.reg)
|
||||
{
|
||||
if (host_regs[c].version != src_reg_b.version)
|
||||
fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_b.version\n");
|
||||
host_regs_locked |= (1 << c);
|
||||
}
|
||||
if (!ir_reg_is_invalid(dest_reg_a) && host_regs[c].reg == dest_reg_a.reg)
|
||||
{
|
||||
if (host_regs[c].version == dest_reg_a.version || (host_regs[c].version == (dest_reg_a.version-1) && reg_version_refcount[host_regs[c].reg][host_regs[c].version] == dest_reference))
|
||||
host_regs_locked |= (1 << c);
|
||||
else
|
||||
fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", host_regs[c].version, dest_reg_a.version, dest_reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg)
|
||||
{
|
||||
int c;
|
||||
|
||||
/*Search for unused registers*/
|
||||
/*Search for required register*/
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (ir_reg_is_invalid(host_regs[c]))
|
||||
if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg && host_regs[c].version == ir_reg.version)
|
||||
break;
|
||||
|
||||
if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg && reg_version_refcount[host_regs[c].reg][host_regs[c].version])
|
||||
fatal("codegen_reg_alloc_read_reg - version mismatch!\n");
|
||||
}
|
||||
|
||||
if (c == CODEGEN_HOST_REGS)
|
||||
{
|
||||
c = 0;
|
||||
codegen_reg_writeback(block, c);
|
||||
// fatal("codegen_reg_alloc_write_reg - out of registers\n");
|
||||
/*No unused registers. Search for an unlocked register*/
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (!(host_regs_locked & (1 << c)))
|
||||
break;
|
||||
}
|
||||
if (c == CODEGEN_HOST_REGS)
|
||||
fatal("codegen_reg_alloc_read_reg - out of registers\n");
|
||||
if (host_reg_dirty[c])
|
||||
codegen_reg_writeback(block, c);
|
||||
codegen_reg_load(block, c, ir_reg);
|
||||
host_regs_locked |= (1 << c);
|
||||
// fatal("codegen_reg_alloc_read_reg - read %i.%i to %i\n", ir_reg.reg,ir_reg.version, c);
|
||||
// codegen_reg_writeback(block, c);
|
||||
}
|
||||
|
||||
reg_version_refcount[host_regs[c].reg][host_regs[c].version]--;
|
||||
if (reg_version_refcount[host_regs[c].reg][host_regs[c].version] < 0)
|
||||
fatal("codegen_reg_alloc_read_reg - refcount < 0\n");
|
||||
|
||||
host_reg_dirty[c] = 0;
|
||||
// pclog(" codegen_reg_alloc_read_reg: %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]);
|
||||
return codegen_host_reg_list[c];
|
||||
}
|
||||
|
||||
ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg)
|
||||
{
|
||||
int c;
|
||||
|
||||
/*Search for previous version in host register*/
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg)
|
||||
{
|
||||
if (host_regs[c].version == ir_reg.version-1)
|
||||
{
|
||||
if (reg_version_refcount[host_regs[c].reg][host_regs[c].version] != 0)
|
||||
fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c == CODEGEN_HOST_REGS)
|
||||
{
|
||||
/*Search for unused registers*/
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (ir_reg_is_invalid(host_regs[c]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == CODEGEN_HOST_REGS)
|
||||
{
|
||||
/*No unused registers. Search for an unlocked register*/
|
||||
for (c = 0; c < CODEGEN_HOST_REGS; c++)
|
||||
{
|
||||
if (!(host_regs_locked & (1 << c)))
|
||||
break;
|
||||
}
|
||||
if (c == CODEGEN_HOST_REGS)
|
||||
fatal("codegen_reg_alloc_write_reg - out of registers\n");
|
||||
if (host_reg_dirty[c])
|
||||
codegen_reg_writeback(block, c);
|
||||
}
|
||||
}
|
||||
|
||||
host_regs[c].reg = ir_reg.reg;
|
||||
host_regs[c].version = ir_reg.version;
|
||||
|
||||
host_reg_dirty[c] = 1;
|
||||
// pclog(" codegen_reg_alloc_write_reg: %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]);
|
||||
return codegen_host_reg_list[c];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ enum
|
|||
IREG_op32 = 16,
|
||||
IREG_ssegs = 17,
|
||||
|
||||
IREG_rm_mod_reg = 18,
|
||||
|
||||
/*Temporary registers are stored on the stack, and are not guaranteed to
|
||||
be preserved across uOPs. They will not be written back if they will
|
||||
not be read again.*/
|
||||
|
|
@ -94,6 +96,10 @@ struct ir_data_t;
|
|||
void codegen_reg_reset();
|
||||
void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block);
|
||||
|
||||
/*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/
|
||||
void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b);
|
||||
|
||||
ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg);
|
||||
ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue