Implemented effective address compilation.

This commit is contained in:
SarahW 2018-06-28 22:06:42 +01:00
commit 94fea237b4
13 changed files with 978 additions and 133 deletions

View file

@ -23,64 +23,6 @@ static inline void fetch_ea_32_long(uint32_t rmdat)
eal_r = eal_w = NULL; eal_r = eal_w = NULL;
easeg = cpu_state.ea_seg->base; easeg = cpu_state.ea_seg->base;
ea_rseg = cpu_state.ea_seg->seg; 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) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
{ {
uint32_t addr = easeg + cpu_state.eaaddr; 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; eal_r = eal_w = NULL;
easeg = cpu_state.ea_seg->base; easeg = cpu_state.ea_seg->base;
ea_rseg = cpu_state.ea_seg->seg; 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) if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC)
{ {
uint32_t addr = easeg + cpu_state.eaaddr; 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_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat);
#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_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) #define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32)

View file

@ -9,6 +9,8 @@
#include "codegen_backend.h" #include "codegen_backend.h"
#include "codegen_ir.h" #include "codegen_ir.h"
int has_ea;
codeblock_t *codeblock; codeblock_t *codeblock;
codeblock_t **codeblock_hash; codeblock_t **codeblock_hash;
@ -38,8 +40,211 @@ void codegen_generate_reset()
last_op_ssegs = -1; last_op_ssegs = -1;
last_op_ea_seg = NULL; last_op_ea_seg = NULL;
last_op_32 = -1; 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) 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]; 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; x86seg *op_ea_seg = &_ds;
int op_ssegs = 0; int op_ssegs = 0;
int over = 0; int over = 0;
int test_modrm = 1;
op_ea_seg = &_ds; op_ea_seg = &_ds;
@ -127,14 +333,44 @@ generate_call:
//pclog("%04x:%08x : %02x\n", CS, new_pc, opcode); //pclog("%04x:%08x : %02x\n", CS, new_pc, opcode);
op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; 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_pc, op_pc);
uop_MOV_IMM(ir, IREG_oldpc, old_pc); uop_MOV_IMM(ir, IREG_oldpc, old_pc);
if (op_32 != last_op_32) if (op_32 != last_op_32)
uop_MOV_IMM(ir, IREG_op32, 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); 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_MOV_IMM(ir, IREG_ssegs, op_ssegs);
uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat); uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat);
uop_CALL_INSTRUCTION_FUNC(ir, op); uop_CALL_INSTRUCTION_FUNC(ir, op);
@ -150,4 +386,7 @@ generate_call:
CPU_BLOCK_END(); CPU_BLOCK_END();
codegen_endpc = (cs + cpu_state.pc) + 8; codegen_endpc = (cs + cpu_state.pc) + 8;
// if (has_ea)
// fatal("Has EA\n");
} }

View file

@ -20,8 +20,6 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] =
REG_R4, REG_R4,
REG_R5, REG_R5,
REG_R6, REG_R6,
// REG_X22,
// REG_X23
}; };
void codegen_backend_init() void codegen_backend_init()

View file

@ -29,6 +29,7 @@
#define REG_W28 28 #define REG_W28 28
#define REG_W29 29 #define REG_W29 29
#define REG_W30 30 #define REG_W30 30
#define REG_WZR 31
#define REG_X0 0 #define REG_X0 0
#define REG_X1 1 #define REG_X1 1
@ -61,6 +62,7 @@
#define REG_X28 28 #define REG_X28 28
#define REG_X29 29 #define REG_X29 29
#define REG_X30 30 #define REG_X30 30
#define REG_XZR 31
#define REG_SP 31 #define REG_SP 31

View file

@ -8,7 +8,7 @@
static inline void codegen_addlong(codeblock_t *block, uint32_t val) 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; block_pos += 4;
if (block_pos >= BLOCK_MAX) 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 Rd(x) (x)
#define Rn(x) ((x) << 5) #define Rn(x) ((x) << 5)
#define Rt2(x) ((x) << 10) #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_UP (1 << 23)
#define DATA_OFFSET_DOWN (0 << 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 COND_AL (0xe << COND_SHIFT)
#define OPCODE_SHIFT 24 #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_CBNZ (0xb5 << OPCODE_SHIFT)
#define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT) #define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT)
#define OPCODE_LDR_LITERAL_X (0x58 << 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_MOVK_W (0x0e5 << 23)
#define OPCODE_MOVZ_W (0x0a5 << 23) #define OPCODE_MOVZ_W (0x0a5 << 23)
#define OPCODE_LDR_IMM_W (0x2e5 << 22)
#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) #define OPCODE_LDP_POSTIDX_X (0x2a3 << 22)
#define OPCODE_STP_PREIDX_X (0x2a6 << 22) #define OPCODE_STP_PREIDX_X (0x2a6 << 22)
#define OPCODE_STR_IMM_W (0x2e4 << 22) #define OPCODE_STR_IMM_W (0x2e4 << 22)
#define OPCODE_STR_IMM_Q (0x3e4 << 22) #define OPCODE_STR_IMM_Q (0x3e4 << 22)
#define OPCODE_STRB_IMM (0x0e4 << 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_BLR (0xd63f0000)
#define OPCODE_NOP (0xd503201f) #define OPCODE_NOP (0xd503201f)
#define OPCODE_RET (0xd65f0000) #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 MOV_WIDE_HW(hw) (hw << 21)
#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) #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) #define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0)
@ -112,7 +125,39 @@ static inline int imm_is_imm16(uint32_t imm_data)
return 1; return 1;
return 0; 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) 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)); 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) 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; 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)); 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) void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data)
{ {
int hw; 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) static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{ {
host_arm64_call(block, uop->p); 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; 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) static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
{ {
host_arm64_mov_imm(block, uop->dest_reg_a_real, uop->imm_data); 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 & UOP_MASK] = codegen_STORE_PTR_IMM,
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, [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_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) void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
{ {
if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state))

View file

@ -23,6 +23,8 @@
#define REG_CPUSTATE REG_R10 #define REG_CPUSTATE REG_R10
#define REG_LITERAL REG_R11 #define REG_LITERAL REG_R11
#define REG_TEMP REG_R3
#define REG_MASK_R0 (1 << REG_R0) #define REG_MASK_R0 (1 << REG_R0)
#define REG_MASK_R1 (1 << REG_R1) #define REG_MASK_R1 (1 << REG_R1)
#define REG_MASK_R2 (1 << REG_R2) #define REG_MASK_R2 (1 << REG_R2)

View file

@ -30,6 +30,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val)
#define OPCODE_SHIFT 20 #define OPCODE_SHIFT 20
#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) #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_B (0xa0 << OPCODE_SHIFT)
#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) #define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT)
#define OPCODE_LDR_IMM (0x51 << 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 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; static int literal_offset = 0;
void codegen_reset_literal_pool(codeblock_t *block) void codegen_reset_literal_pool(codeblock_t *block)
{ {
@ -114,14 +129,49 @@ static inline int in_range(void *addr, void *base)
return 1; 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) void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm)
{ {
uint32_t arm_imm; uint32_t arm_imm;
if (!get_arm_imm(imm, &arm_imm)) if (get_arm_imm(imm, &arm_imm))
fatal("host_arm_ADD_IMM !check_arm_imm %08x\n", 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) 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; uint32_t arm_imm;
if (!get_arm_imm(imm, &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);
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) 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) 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) 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; 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) static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop)
{ {
uint32_t arm_imm; 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 & UOP_MASK] = codegen_STORE_PTR_IMM,
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, [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_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) void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
{ {
if (in_range(p, &cpu_state)) if (in_range(p, &cpu_state))

View file

@ -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) static inline void call(codeblock_t *block, uintptr_t func)
{ {
uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; 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) static void host_x86_CALL(codeblock_t *block, void *p)
{ {
call(block, (uintptr_t)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]); 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) 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); int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
if (offset >= -128 && offset < 127) 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); codegen_addbyte(block, imm_data);
} }
else 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) 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); codegen_addlong(block, imm_data);
} }
else 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); 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) 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 else
{ {
if ((uintptr_t)p >> 32) if ((uintptr_t)p >> 32)
fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p);
codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ 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); 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); 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) 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 else
{ {
if ((uintptr_t)p >> 32) if ((uintptr_t)p >> 32)
fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p);
codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ 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); 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); 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) 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 else
{ {
if ((uintptr_t)p >> 32) if ((uintptr_t)p >> 32)
fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); 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); 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) static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data)
{ {
if (reg & 8) if (reg & 8)
fatal("host_x86_MOV32_REG_IMM reg & 8\n"); 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); 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) if (reg & 8)
fatal("host_x86_MOV64_REG_IMM reg & 8\n"); 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); 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) 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)) #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) 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; 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) 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); 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 & UOP_MASK] = codegen_STORE_PTR_IMM,
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, [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_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) void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
{ {
host_x86_MOV8_ABS_REG(block, p, host_reg); host_x86_MOV8_ABS_REG(block, p, host_reg);

View file

@ -86,6 +86,70 @@ static inline void codegen_addquad(codeblock_t *block, uint64_t val)
CPU_BLOCK_END(); 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) static void host_x86_CALL(codeblock_t *block, void *p)
{ {
codegen_addbyte(block, 0xe8); /*CALL*/ 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]); 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) 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); 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) static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data)
{ {
if (!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) static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data)
{ {
if (!offset) 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); 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) static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop)
{ {
host_x86_CALL(block, uop->p); 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; 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) 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); 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 & UOP_MASK] = codegen_STORE_PTR_IMM,
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, [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_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) void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg)
{ {
host_x86_MOV8_ABS_REG(block, p, host_reg); host_x86_MOV8_ABS_REG(block, p, host_reg);

View file

@ -4,12 +4,13 @@
#include "codegen_ir.h" #include "codegen_ir.h"
#include "codegen_reg.h" #include "codegen_reg.h"
extern int has_ea;
static ir_data_t ir_block; static ir_data_t ir_block;
ir_data_t *codegen_ir_init() ir_data_t *codegen_ir_init()
{ {
ir_block.wr_pos = 0; ir_block.wr_pos = 0;
//pclog("codegen_ir_init\n"); // pclog("codegen_ir_init %04x:%04x\n", CS,cpu_state.pc);
return &ir_block; return &ir_block;
} }
@ -24,10 +25,19 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
{ {
uop_t *uop = &ir->uops[c]; 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) 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) if (uop->dest_reg_a.reg != IREG_INVALID)
{ {
uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); 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); codegen_backend_epilogue(block);
//fatal("IR compilation complete\n"); // if (has_ea)
// fatal("IR compilation complete\n");
} }

View file

@ -32,8 +32,13 @@
#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13) #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_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_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 #define UOP_MASK 0xffff
@ -43,10 +48,10 @@ typedef struct uop_t
ir_reg_t dest_reg_a; ir_reg_t dest_reg_a;
ir_reg_t src_reg_a; ir_reg_t src_reg_a;
ir_reg_t src_reg_b; ir_reg_t src_reg_b;
ir_reg_t src_reg_c;
uint32_t imm_data; uint32_t imm_data;
void *p; void *p;
ir_host_reg_t dest_reg_a_real; ir_host_reg_t dest_reg_a_real;
ir_host_reg_t src_reg_a_real, src_reg_b_real;
} uop_t; } uop_t;
#define UOP_NR_MAX 4096 #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->dest_reg_a = invalid_ir_reg;
uop->src_reg_a = invalid_ir_reg; uop->src_reg_a = invalid_ir_reg;
uop->src_reg_b = 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; 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; 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) static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm)
{ {
uop_t *uop = uop_alloc(ir); 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_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_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_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_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_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(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) #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_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_32(codeblock_t *block, void *p, int host_reg);
void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg); void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg);

View file

@ -10,6 +10,9 @@ uint8_t reg_version_refcount[IREG_COUNT][256];
ir_reg_t invalid_ir_reg = {IREG_INVALID}; ir_reg_t invalid_ir_reg = {IREG_INVALID};
ir_reg_t host_regs[CODEGEN_HOST_REGS]; ir_reg_t host_regs[CODEGEN_HOST_REGS];
static uint8_t host_reg_dirty[CODEGEN_HOST_REGS];
static uint8_t host_regs_locked;
enum enum
{ {
@ -49,6 +52,8 @@ struct
[IREG_op32] = {REG_DWORD, &cpu_state.op32}, [IREG_op32] = {REG_DWORD, &cpu_state.op32},
[IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs}, [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 /*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 be preserved across uOPs. They will not be written back if they will
not be read again.*/ 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); 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) static void codegen_reg_writeback(codeblock_t *block, int c)
{ {
int ir_reg = host_regs[c].reg; 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; 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; int c;
/*Search for unused registers*/ /*Search for required register*/
for (c = 0; c < CODEGEN_HOST_REGS; c++) 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; 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) if (c == CODEGEN_HOST_REGS)
{ {
c = 0; /*No unused registers. Search for an unlocked register*/
codegen_reg_writeback(block, c); for (c = 0; c < CODEGEN_HOST_REGS; c++)
// fatal("codegen_reg_alloc_write_reg - out of registers\n"); {
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].reg = ir_reg.reg;
host_regs[c].version = ir_reg.version; 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]; return codegen_host_reg_list[c];
} }

View file

@ -30,6 +30,8 @@ enum
IREG_op32 = 16, IREG_op32 = 16,
IREG_ssegs = 17, IREG_ssegs = 17,
IREG_rm_mod_reg = 18,
/*Temporary registers are stored on the stack, and are not guaranteed to /*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 be preserved across uOPs. They will not be written back if they will
not be read again.*/ not be read again.*/
@ -94,6 +96,10 @@ struct ir_data_t;
void codegen_reg_reset(); void codegen_reg_reset();
void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block); 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); ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg);
#endif #endif