From bbf0011e951b1179745924f694c851d67af4edd4 Mon Sep 17 00:00:00 2001 From: TomW Date: Tue, 14 Apr 2015 20:40:40 +0100 Subject: [PATCH] Added code generation for JCXZ, LOOP, JE, JNE, JS, JNS, JB, JNB, JO, JNO, JP and JNP. --- src/codegen.h | 5 + src/codegen_ops.c | 56 +++++++++- src/codegen_ops.h | 1 + src/codegen_ops_arith.h | 30 ++++- src/codegen_ops_jump.h | 235 ++++++++++++++++++++++++++++++++++++++++ src/codegen_ops_x86.h | 101 +++++++++++++++++ src/codegen_x86.c | 87 ++++++++------- src/x86_ops_flag.h | 12 ++ 8 files changed, 485 insertions(+), 42 deletions(-) diff --git a/src/codegen.h b/src/codegen.h index 68835a0..7c886d9 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -144,4 +144,9 @@ extern uint32_t recomp_page; extern x86seg *op_ea_seg; extern int op_ssegs; extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + #endif diff --git a/src/codegen_ops.c b/src/codegen_ops.c index 22964bb..86e3fd4 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -5,6 +5,7 @@ #include "x86_ops.h" #include "x86_flags.h" #include "386_common.h" +#include "cpu.h" #include "codegen.h" #include "codegen_ops.h" #include "codegen_ops_x86.h" @@ -28,7 +29,7 @@ RecompOpFn recomp_opcodes[512] = /*40*/ ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, /*50*/ ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, /*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_b16,NULL, NULL, NULL, NULL, NULL, -/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, NULL, NULL, ropJS, ropJNS, ropJP, ropJNP, NULL, NULL, NULL, NULL, /*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_b, ropXCHG_w, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, NULL, NULL, NULL, NULL, /*90*/ NULL, ropXCHG_AX_CX, ropXCHG_AX_DX, ropXCHG_AX_BX, ropXCHG_AX_SP, ropXCHG_AX_BP, ropXCHG_AX_SI, ropXCHG_AX_DI, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -37,7 +38,7 @@ RecompOpFn recomp_opcodes[512] = /*c0*/ NULL, NULL, ropRET_imm_16, ropRET_16, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ @@ -50,7 +51,7 @@ RecompOpFn recomp_opcodes[512] = /*40*/ ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, /*50*/ ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, /*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_b32,NULL, NULL, NULL, NULL, NULL, -/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, NULL, NULL, ropJS, ropJNS, ropJP, ropJNP, NULL, NULL, NULL, NULL, /*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_b, ropXCHG_l, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, NULL, NULL, NULL, NULL, /*90*/ NULL, ropXCHG_EAX_ECX,ropXCHG_EAX_EDX,ropXCHG_EAX_EBX,ropXCHG_EAX_ESP,ropXCHG_EAX_EBP,ropXCHG_EAX_ESI,ropXCHG_EAX_EDI,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -59,7 +60,54 @@ RecompOpFn recomp_opcodes[512] = /*c0*/ NULL, NULL, ropRET_imm_32, ropRET_32, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_0f[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropJO_w, ropJNO_w, ropJB_w, ropJNB_w, ropJE_w, ropJNE_w, NULL, NULL, ropJS_w, ropJNS_w, ropJP_w, ropJNP_w, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropJO_l, ropJNO_l, ropJB_l, ropJNB_l, ropJE_l, ropJNE_l, NULL, NULL, ropJS_l, ropJNS_l, ropJP_l, ropJNP_l, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; diff --git a/src/codegen_ops.h b/src/codegen_ops.h index 7f4182a..b087a91 100644 --- a/src/codegen_ops.h +++ b/src/codegen_ops.h @@ -1,6 +1,7 @@ typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); extern RecompOpFn recomp_opcodes[512]; +extern RecompOpFn recomp_opcodes_0f[512]; #define REG_EAX 0 #define REG_ECX 1 diff --git a/src/codegen_ops_arith.h b/src/codegen_ops_arith.h index 69fa4d8..314645d 100644 --- a/src/codegen_ops_arith.h +++ b/src/codegen_ops_arith.h @@ -13,6 +13,8 @@ static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_IMM_ADDR_L((uint32_t)&flags_op, FLAGS_INC16); STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; return op_pc; } @@ -31,6 +33,8 @@ static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); + codegen_flags_changed = 1; + return op_pc; } static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -49,6 +53,8 @@ static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); + codegen_flags_changed = 1; + return op_pc; } static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -66,6 +72,8 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); + codegen_flags_changed = 1; + return op_pc; } @@ -88,6 +96,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } \ static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ @@ -108,6 +117,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } \ static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ @@ -128,6 +138,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } \ static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ @@ -156,6 +167,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } \ static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ @@ -184,6 +196,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } \ static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ @@ -212,6 +225,7 @@ static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin else RELEASE_REG(dst_reg); \ RELEASE_REG(src_reg); \ \ + codegen_flags_changed = 1; \ return op_pc + 1; \ } @@ -229,7 +243,8 @@ static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_IMM_ADDR_L((uint32_t)&flags_op, FLAGS_ADD8); STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); - + + codegen_flags_changed = 1; return op_pc + 1; } static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -243,6 +258,7 @@ static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -257,6 +273,7 @@ static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); + codegen_flags_changed = 1; return op_pc + 4; } @@ -271,6 +288,7 @@ static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 1; } static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -284,6 +302,7 @@ static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -298,6 +317,7 @@ static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 4; } @@ -312,6 +332,7 @@ static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_B_RELEASE(host_reg); + codegen_flags_changed = 1; return op_pc + 1; } static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -325,6 +346,7 @@ static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_W_RELEASE(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -339,6 +361,7 @@ static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 STORE_HOST_REG_ADDR((uint32_t)&flags_res, host_reg); STORE_REG_L_RELEASE(host_reg); + codegen_flags_changed = 1; return op_pc + 4; } @@ -393,6 +416,7 @@ static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_ else RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } @@ -447,6 +471,7 @@ static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 else RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 3; } static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -501,6 +526,7 @@ static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 else RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 5; } @@ -557,6 +583,7 @@ static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 else RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) @@ -612,5 +639,6 @@ static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint3 else RELEASE_REG(host_reg); + codegen_flags_changed = 1; return op_pc + 2; } diff --git a/src/codegen_ops_jump.h b/src/codegen_ops_jump.h index ee89d3d..cab6e4e 100644 --- a/src/codegen_ops_jump.h +++ b/src/codegen_ops_jump.h @@ -27,3 +27,238 @@ static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui 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 ? 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(&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 ? 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(&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(&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(&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) diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h index 5ec6839..51793f0 100644 --- a/src/codegen_ops_x86.h +++ b/src/codegen_ops_x86.h @@ -108,6 +108,18 @@ static int LOAD_REG_L(int reg) return host_reg; } +static int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} + static int LOAD_REG_IMM(uint32_t imm) { int host_reg = find_host_reg(); @@ -1101,3 +1113,92 @@ static void SP_MODIFY(int off) } } } + + +static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(10+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x05); + addlong((uintptr_t)&pc); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(10+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x05); + addlong((uintptr_t)&pc); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(10+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x05); + addlong((uintptr_t)&pc); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(10+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x05); + addlong((uintptr_t)&pc); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} diff --git a/src/codegen_x86.c b/src/codegen_x86.c index 2c58397..73ba977 100644 --- a/src/codegen_x86.c +++ b/src/codegen_x86.c @@ -21,6 +21,7 @@ #include #endif +int codegen_flags_changed = 0; x86seg *op_ea_seg; int op_ssegs; uint32_t op_old_pc; @@ -250,6 +251,8 @@ void codegen_block_init(uint32_t phys_addr) codegen_block_full_ins = 0; recomp_page = phys_addr & ~0xfff; + + codegen_flags_changed = 0; } void codegen_block_remove() @@ -686,6 +689,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t uint32_t op_32 = use32; uint32_t op_pc = new_pc; OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; int opcode_shift = 0; int opcode_mask = 0x3ff; int over = 0; @@ -708,6 +712,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t { case 0x0f: op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; over = 1; break; @@ -745,6 +750,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t case 0xd8: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = NULL; opcode_shift = 3; opcode_mask = 0x1f; over = 1; @@ -753,6 +759,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xd9: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -760,6 +767,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xda: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -767,6 +775,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xdb: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -774,6 +783,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xdc: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = NULL; opcode_shift = 3; opcode_mask = 0x1f; over = 1; @@ -782,6 +792,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xdd: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -789,6 +800,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xde: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -796,6 +808,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xdf: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = NULL; opcode_mask = 0xff; over = 1; pc_off = -1; @@ -822,11 +835,46 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t generate_call: codegen_timing_opcode(opcode, fetchdat, op_32); + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + addbyte(0xBD); /*MOVL EBP, &EAX*/ addlong((uint32_t)&EAX); - if (op_table == x86_dynarec_opcodes && recomp_opcodes[(opcode | op_32) & 0x1ff]) + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) { - uint32_t new_pc = recomp_opcodes[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); if (new_pc) { if (new_pc != -1) @@ -933,41 +981,6 @@ generate_call: addlong(((uint8_t *)op - (uint8_t *)(&block->data[block_pos + 4]))); codegen_block_ins++; - - if ((op_table == x86_dynarec_opcodes && - ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || - (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || - (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || - (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) - { - /*Opcode is likely to cause block to exit, update cycle count*/ - if (codegen_block_cycles) - { - addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x2d); - addlong((uint32_t)&cycles); - addlong((uint32_t)codegen_block_cycles); - codegen_block_cycles = 0; - } - if (codegen_block_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x05); - addlong((uint32_t)&cpu_recomp_ins); - addlong(codegen_block_ins); - codegen_block_ins = 0; - } -#if 0 - if (codegen_block_full_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x05); - addlong((uint32_t)&cpu_recomp_full_ins); - addlong(codegen_block_full_ins); - codegen_block_full_ins = 0; - } -#endif - } block->ins++; diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h index 235e3b4..bcdd131 100644 --- a/src/x86_ops_flag.h +++ b/src/x86_ops_flag.h @@ -70,6 +70,9 @@ static int opSAHF(uint32_t fetchdat) flags_rebuild(); flags = (flags & 0xff00) | (AH & 0xd5) | 2; CLOCK_CYCLES(3); +#ifdef DYNAREC + codegen_flags_changed = 0; +#endif return 0; } static int opLAHF(uint32_t fetchdat) @@ -127,6 +130,9 @@ static int opPOPF_286(uint32_t fetchdat) flags_extract(); CLOCK_CYCLES(5); +#ifdef DYNAREC + codegen_flags_changed = 0; +#endif return 0; } static int opPOPF(uint32_t fetchdat) @@ -147,6 +153,9 @@ static int opPOPF(uint32_t fetchdat) flags_extract(); CLOCK_CYCLES(5); +#ifdef DYNAREC + codegen_flags_changed = 0; +#endif return 0; } static int opPOPFD(uint32_t fetchdat) @@ -174,5 +183,8 @@ static int opPOPFD(uint32_t fetchdat) flags_extract(); CLOCK_CYCLES(5); +#ifdef DYNAREC + codegen_flags_changed = 0; +#endif return 0; }