271 lines
9.9 KiB
C
271 lines
9.9 KiB
C
static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
|
{
|
|
uint32_t offset = fetchdat & 0xff;
|
|
|
|
if (offset & 0x80)
|
|
offset |= 0xffffff00;
|
|
|
|
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
|
{
|
|
uint16_t offset = fetchdat & 0xffff;
|
|
|
|
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
|
{
|
|
uint32_t offset = fastreadl(cs + op_pc);
|
|
|
|
STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
|
{
|
|
uint32_t offset = fetchdat & 0xff;
|
|
|
|
if (offset & 0x80)
|
|
offset |= 0xffffff00;
|
|
|
|
if (op_32 & 0x200)
|
|
{
|
|
int host_reg = LOAD_REG_L(REG_ECX);
|
|
TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0);
|
|
}
|
|
else
|
|
{
|
|
int host_reg = LOAD_REG_W(REG_CX);
|
|
TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0);
|
|
}
|
|
|
|
return op_pc+1;
|
|
}
|
|
|
|
static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
|
|
{
|
|
uint32_t offset = fetchdat & 0xff;
|
|
|
|
if (offset & 0x80)
|
|
offset |= 0xffffff00;
|
|
|
|
if (op_32 & 0x200)
|
|
{
|
|
int host_reg = LOAD_REG_L(REG_ECX);
|
|
SUB_HOST_REG_IMM(host_reg, 1);
|
|
STORE_REG_L_RELEASE(host_reg);
|
|
TEST_NONZERO_JUMP_L(host_reg, op_pc+1+offset, 0);
|
|
}
|
|
else
|
|
{
|
|
int host_reg = LOAD_REG_W(REG_CX);
|
|
SUB_HOST_REG_IMM(host_reg, 1);
|
|
STORE_REG_W_RELEASE(host_reg);
|
|
TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0);
|
|
}
|
|
|
|
return op_pc+1;
|
|
}
|
|
|
|
static int BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not)
|
|
{
|
|
CALL_FUNC(CF_SET);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
}
|
|
|
|
static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not)
|
|
{
|
|
int host_reg;
|
|
|
|
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
|
{
|
|
case FLAGS_ZN8:
|
|
case FLAGS_ZN16:
|
|
case FLAGS_ZN32:
|
|
case FLAGS_ADD8:
|
|
case FLAGS_ADD16:
|
|
case FLAGS_ADD32:
|
|
case FLAGS_SUB8:
|
|
case FLAGS_SUB16:
|
|
case FLAGS_SUB32:
|
|
case FLAGS_SHL8:
|
|
case FLAGS_SHL16:
|
|
case FLAGS_SHL32:
|
|
case FLAGS_SHR8:
|
|
case FLAGS_SHR16:
|
|
case FLAGS_SHR32:
|
|
case FLAGS_SAR8:
|
|
case FLAGS_SAR16:
|
|
case FLAGS_SAR32:
|
|
case FLAGS_INC8:
|
|
case FLAGS_INC16:
|
|
case FLAGS_INC32:
|
|
case FLAGS_DEC8:
|
|
case FLAGS_DEC16:
|
|
case FLAGS_DEC32:
|
|
host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res);
|
|
if (not)
|
|
TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
|
|
case FLAGS_UNKNOWN:
|
|
CALL_FUNC(ZF_SET);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not)
|
|
{
|
|
CALL_FUNC(VF_SET);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
}
|
|
|
|
static int BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not)
|
|
{
|
|
CALL_FUNC(PF_SET);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
}
|
|
|
|
static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not)
|
|
{
|
|
int host_reg;
|
|
|
|
switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN)
|
|
{
|
|
case FLAGS_ZN8:
|
|
case FLAGS_ADD8:
|
|
case FLAGS_SUB8:
|
|
case FLAGS_SHL8:
|
|
case FLAGS_SHR8:
|
|
case FLAGS_SAR8:
|
|
case FLAGS_INC8:
|
|
case FLAGS_DEC8:
|
|
host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res);
|
|
AND_HOST_REG_IMM(host_reg, 0x80);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
|
|
case FLAGS_ZN16:
|
|
case FLAGS_ADD16:
|
|
case FLAGS_SUB16:
|
|
case FLAGS_SHL16:
|
|
case FLAGS_SHR16:
|
|
case FLAGS_SAR16:
|
|
case FLAGS_INC16:
|
|
case FLAGS_DEC16:
|
|
host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res);
|
|
AND_HOST_REG_IMM(host_reg, 0x8000);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
|
|
case FLAGS_ZN32:
|
|
case FLAGS_ADD32:
|
|
case FLAGS_SUB32:
|
|
case FLAGS_SHL32:
|
|
case FLAGS_SHR32:
|
|
case FLAGS_SAR32:
|
|
case FLAGS_INC32:
|
|
case FLAGS_DEC32:
|
|
host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res);
|
|
AND_HOST_REG_IMM(host_reg, 0x80000000);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
|
|
case FLAGS_UNKNOWN:
|
|
CALL_FUNC(NF_SET);
|
|
if (not)
|
|
TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
else
|
|
TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#define ropBRANCH(name, func, not) \
|
|
static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \
|
|
uint32_t op_32, uint32_t op_pc, \
|
|
codeblock_t *block) \
|
|
{ \
|
|
uint32_t offset = fetchdat & 0xff; \
|
|
\
|
|
if (offset & 0x80) \
|
|
offset |= 0xffffff00; \
|
|
\
|
|
func(1, op_pc, offset, not); \
|
|
\
|
|
return op_pc+1; \
|
|
} \
|
|
static uint32_t rop ## name ## _w(uint8_t opcode, \
|
|
uint32_t fetchdat, uint32_t op_32, \
|
|
uint32_t op_pc, codeblock_t *block) \
|
|
{ \
|
|
uint32_t offset = fetchdat & 0xffff; \
|
|
\
|
|
if (offset & 0x8000) \
|
|
offset |= 0xffff0000; \
|
|
\
|
|
func(2, op_pc, offset, not); \
|
|
\
|
|
return op_pc+2; \
|
|
} \
|
|
static uint32_t rop ## name ## _l(uint8_t opcode, \
|
|
uint32_t fetchdat, uint32_t op_32, \
|
|
uint32_t op_pc, codeblock_t *block) \
|
|
{ \
|
|
uint32_t offset = fastreadl(cs + op_pc); \
|
|
\
|
|
func(4, op_pc, offset, not); \
|
|
\
|
|
return op_pc+4; \
|
|
}
|
|
|
|
ropBRANCH(JB, BRANCH_COND_B, 0)
|
|
ropBRANCH(JNB, BRANCH_COND_B, 1)
|
|
ropBRANCH(JE, BRANCH_COND_E, 0)
|
|
ropBRANCH(JNE, BRANCH_COND_E, 1)
|
|
ropBRANCH(JO, BRANCH_COND_O, 0)
|
|
ropBRANCH(JNO, BRANCH_COND_O, 1)
|
|
ropBRANCH(JP, BRANCH_COND_P, 0)
|
|
ropBRANCH(JNP, BRANCH_COND_P, 1)
|
|
ropBRANCH(JS, BRANCH_COND_S, 0)
|
|
ropBRANCH(JNS, BRANCH_COND_S, 1)
|
|
ropBRANCH(JL, BRANCH_COND_L, 0)
|
|
ropBRANCH(JNL, BRANCH_COND_L, 1)
|
|
ropBRANCH(JLE, BRANCH_COND_LE, 0)
|
|
ropBRANCH(JNLE, BRANCH_COND_LE, 1)
|
|
ropBRANCH(JBE, BRANCH_COND_BE, 0)
|
|
ropBRANCH(JNBE, BRANCH_COND_BE, 1)
|