From 3c7d1b1204fe3e2e692ec7c2586725c4829c83a5 Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 6 Jan 2019 13:46:17 +0000 Subject: [PATCH] Ensure that taken jump/branch instructions do not count as 0 cycles. Fixes Windows 95 hang with K6. --- src/codegen.c | 15 +++++++++++++++ src/codegen.h | 2 ++ src/codegen_timing_486.c | 8 +++++++- src/codegen_timing_686.c | 8 +++++++- src/codegen_timing_k6.c | 10 +++++++++- src/codegen_timing_pentium.c | 8 +++++++- src/codegen_timing_winchip.c | 8 +++++++- src/codegen_timing_winchip2.c | 8 +++++++- 8 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/codegen.c b/src/codegen.c index a278cfe..653834c 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -21,6 +21,7 @@ void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); void (*codegen_timing_block_start)(); void (*codegen_timing_block_end)(); +int (*codegen_timing_jump_cycles)(); void codegen_timing_set(codegen_timing_t *timing) { @@ -29,6 +30,7 @@ void codegen_timing_set(codegen_timing_t *timing) codegen_timing_opcode = timing->opcode; codegen_timing_block_start = timing->block_start; codegen_timing_block_end = timing->block_end; + codegen_timing_jump_cycles = timing->jump_cycles; } int codegen_in_recompile; @@ -508,7 +510,20 @@ generate_call: (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))) + { + /*On some CPUs (eg K6), a jump/branch instruction may be able to pair with + subsequent instructions, so no cycles may have been deducted for it yet. + To prevent having zero cycle blocks (eg with a jump instruction pointing + to itself), apply the cycles that would be taken if this jump is taken, + then reverse it for subsequent instructions if the jump is not taken*/ + int jump_cycles = codegen_timing_jump_cycles(); + + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, -jump_cycles); codegen_accumulate_flush(ir); + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, jump_cycles); + } if (op_table == x86_dynarec_opcodes_0f && opcode == 0x0f) { diff --git a/src/codegen.h b/src/codegen.h index e82b904..e0e8760 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -320,6 +320,7 @@ extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); extern void (*codegen_timing_block_start)(); extern void (*codegen_timing_block_end)(); +extern int (*codegen_timing_jump_cycles)(); typedef struct codegen_timing_t { @@ -328,6 +329,7 @@ typedef struct codegen_timing_t void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); void (*block_start)(); void (*block_end)(); + int (*jump_cycles)(); } codegen_timing_t; extern codegen_timing_t codegen_timing_pentium; diff --git a/src/codegen_timing_486.c b/src/codegen_timing_486.c index cda0436..6f9e3af 100644 --- a/src/codegen_timing_486.c +++ b/src/codegen_timing_486.c @@ -422,11 +422,17 @@ void codegen_timing_486_block_end() { } +int codegen_timing_486_jump_cycles() +{ + return 0; +} + codegen_timing_t codegen_timing_486 = { codegen_timing_486_start, codegen_timing_486_prefix, codegen_timing_486_opcode, codegen_timing_486_block_start, - codegen_timing_486_block_end + codegen_timing_486_block_end, + codegen_timing_486_jump_cycles }; diff --git a/src/codegen_timing_686.c b/src/codegen_timing_686.c index dab2b10..cc1e119 100644 --- a/src/codegen_timing_686.c +++ b/src/codegen_timing_686.c @@ -1067,11 +1067,17 @@ void codegen_timing_686_block_end() } } +int codegen_timing_686_jump_cycles() +{ + return 0; +} + codegen_timing_t codegen_timing_686 = { codegen_timing_686_start, codegen_timing_686_prefix, codegen_timing_686_opcode, codegen_timing_686_block_start, - codegen_timing_686_block_end + codegen_timing_686_block_end, + codegen_timing_686_jump_cycles }; diff --git a/src/codegen_timing_k6.c b/src/codegen_timing_k6.c index a5d0cde..78d9678 100644 --- a/src/codegen_timing_k6.c +++ b/src/codegen_timing_k6.c @@ -2278,11 +2278,19 @@ void codegen_timing_k6_block_end() decode_flush(); } +int codegen_timing_k6_jump_cycles() +{ + if (decode_buffer.nr_uops) + return 1; + return 0; +} + codegen_timing_t codegen_timing_k6 = { codegen_timing_k6_start, codegen_timing_k6_prefix, codegen_timing_k6_opcode, codegen_timing_k6_block_start, - codegen_timing_k6_block_end + codegen_timing_k6_block_end, + codegen_timing_k6_jump_cycles }; diff --git a/src/codegen_timing_pentium.c b/src/codegen_timing_pentium.c index 24748cb..f21a70f 100644 --- a/src/codegen_timing_pentium.c +++ b/src/codegen_timing_pentium.c @@ -1328,11 +1328,17 @@ void codegen_timing_pentium_block_end() } } +int codegen_timing_pentium_jump_cycles() +{ + return 0; +} + codegen_timing_t codegen_timing_pentium = { codegen_timing_pentium_start, codegen_timing_pentium_prefix, codegen_timing_pentium_opcode, codegen_timing_pentium_block_start, - codegen_timing_pentium_block_end + codegen_timing_pentium_block_end, + codegen_timing_pentium_jump_cycles }; diff --git a/src/codegen_timing_winchip.c b/src/codegen_timing_winchip.c index 56ee3af..c23b30b 100644 --- a/src/codegen_timing_winchip.c +++ b/src/codegen_timing_winchip.c @@ -422,11 +422,17 @@ void codegen_timing_winchip_block_end() { } +int codegen_timing_winchip_jump_cycles() +{ + return 0; +} + codegen_timing_t codegen_timing_winchip = { codegen_timing_winchip_start, codegen_timing_winchip_prefix, codegen_timing_winchip_opcode, codegen_timing_winchip_block_start, - codegen_timing_winchip_block_end + codegen_timing_winchip_block_end, + codegen_timing_winchip_jump_cycles }; diff --git a/src/codegen_timing_winchip2.c b/src/codegen_timing_winchip2.c index ec47099..c85a0e9 100644 --- a/src/codegen_timing_winchip2.c +++ b/src/codegen_timing_winchip2.c @@ -743,11 +743,17 @@ static void codegen_timing_winchip2_block_end() } } +int codegen_timing_winchip2_jump_cycles() +{ + return 0; +} + codegen_timing_t codegen_timing_winchip2 = { codegen_timing_winchip2_start, codegen_timing_winchip2_prefix, codegen_timing_winchip2_opcode, codegen_timing_winchip2_block_start, - codegen_timing_winchip2_block_end + codegen_timing_winchip2_block_end, + codegen_timing_winchip2_jump_cycles };