* [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags @ 2015-08-14 14:59 Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 01/11] target-m68k: Print flags properly Richard Henderson ` (11 more replies) 0 siblings, 12 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg As promised a couple of days ago, with the addition of CC_OP_CMP, which wasn't in the text of my proposal the other day. From the looks of the generated code, I believe this is ideal. The following is based on Laurent's 8/30 Update cpu flags management. FWIW, there's something in the last patch here that breaks the coldfire kernel I've been testing (it may even be a bug in tcg; the problem only appears well into the boot process). But I'm about to go away for the weekend and still wanted to include it to show what can be done. For convenience, the complete tree pushed to git://github.com/rth7680/qemu.git tgt-m68k r~ Richard Henderson (11): target-m68k: Print flags properly target-m68k: Some fixes to SR and flags management target-m68k: Remove incorrect clearing of cc_x target-m68k: Replace helper_xflag_lt with setcond target-m68k: Reorg flags handling target-m68k: Introduce DisasCompare target-m68k: Use setcond for scc target-m68k: Optimize some comparisons target-m68k: Optimize gen_flush_flags target-m68k: Inline shifts target-m68k: Inline addx, subx, negx target-m68k/cpu.c | 2 +- target-m68k/cpu.h | 48 +-- target-m68k/helper.c | 399 +++++++++---------------- target-m68k/helper.h | 12 +- target-m68k/op_helper.c | 35 +-- target-m68k/qregs.def | 6 +- target-m68k/translate.c | 769 +++++++++++++++++++++++++++++++----------------- 7 files changed, 674 insertions(+), 597 deletions(-) -- 2.4.3 ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 01/11] target-m68k: Print flags properly 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 02/11] target-m68k: Some fixes to SR and flags management Richard Henderson ` (10 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/cpu.h | 1 + target-m68k/helper.c | 2 +- target-m68k/translate.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 6d1a140..9708615 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -123,6 +123,7 @@ int cpu_m68k_exec(CPUState *cpu); is returned if the signal was handled by the virtual CPU. */ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); +uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op); typedef enum { CC_OP_DYNAMIC, /* Use env->cc_op */ diff --git a/target-m68k/helper.c b/target-m68k/helper.c index c7bccf7..2185041 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -130,7 +130,7 @@ void m68k_cpu_init_gdb(M68kCPU *cpu) /* TODO: Add [E]MAC registers. */ } -static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) +uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) { int flags; uint32_t src; diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 80ac63a..c000d0a 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3236,8 +3236,8 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, i, u.l.upper, u.l.lower, *(double *)&u.d); } cpu_fprintf (f, "PC = %08x ", env->pc); - sr = env->sr; - cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-', + sr = env->sr | cpu_m68k_flush_flags(env, env->cc_op) | env->cc_x * CCF_X; + cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result); -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 02/11] target-m68k: Some fixes to SR and flags management 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 01/11] target-m68k: Print flags properly Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x Richard Henderson ` (9 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/cpu.h | 3 ++- target-m68k/helper.c | 17 +++++++++++++++-- target-m68k/op_helper.c | 5 +++-- target-m68k/translate.c | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 9708615..4f0d053 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -123,7 +123,8 @@ int cpu_m68k_exec(CPUState *cpu); is returned if the signal was handled by the virtual CPU. */ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); -uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op); +uint32_t cpu_m68k_get_ccr(CPUM68KState *env); +void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); typedef enum { CC_OP_DYNAMIC, /* Use env->cc_op */ diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 2185041..c7b0fbe 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -130,7 +130,7 @@ void m68k_cpu_init_gdb(M68kCPU *cpu) /* TODO: Add [E]MAC registers. */ } -uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) +static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) { int flags; uint32_t src; @@ -270,6 +270,18 @@ set_x: return flags; } +uint32_t cpu_m68k_get_ccr(CPUM68KState *env) +{ + return cpu_m68k_flush_flags(env, env->cc_op) | env->cc_x * CCF_X; +} + +void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t val) +{ + env->cc_op = CC_OP_FLAGS; + env->cc_dest = val & 0xf; + env->cc_x = (val & CCF_X ? 1 : 0); +} + void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) { M68kCPU *cpu = m68k_env_get_cpu(env); @@ -467,7 +479,8 @@ uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b) void HELPER(set_sr)(CPUM68KState *env, uint32_t val) { - env->sr = val & 0xffff; + env->sr = val & 0xffe0; + cpu_m68k_set_ccr(env, val); m68k_switch_sp(env); } diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 1af0ca6..29032c6 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -61,9 +61,9 @@ static void do_rte(CPUM68KState *env) fmt = cpu_ldl_kernel(env, sp); env->pc = cpu_ldl_kernel(env, sp + 4); sp |= (fmt >> 28) & 3; - env->sr = fmt & 0xffff; env->aregs[7] = sp + 8; - m68k_switch_sp(env); + + helper_set_sr(env, fmt); } static void do_interrupt_all(CPUM68KState *env, int is_hw) @@ -110,6 +110,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw) fmt |= 0x40000000; fmt |= vector << 16; fmt |= env->sr; + fmt |= cpu_m68k_get_ccr(env); env->sr |= SR_S; if (is_hw) { diff --git a/target-m68k/translate.c b/target-m68k/translate.c index c000d0a..2c720a2 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3236,7 +3236,7 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, i, u.l.upper, u.l.lower, *(double *)&u.d); } cpu_fprintf (f, "PC = %08x ", env->pc); - sr = env->sr | cpu_m68k_flush_flags(env, env->cc_op) | env->cc_x * CCF_X; + sr = env->sr | cpu_m68k_get_ccr(env); cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & CCF_X) ? 'X' : '-', (sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 01/11] target-m68k: Print flags properly Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 02/11] target-m68k: Some fixes to SR and flags management Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 17:04 ` Andreas Schwab 2015-08-14 14:59 ` [Qemu-devel] [PATCH 04/11] target-m68k: Replace helper_xflag_lt with setcond Richard Henderson ` (8 subsequent siblings) 11 siblings, 1 reply; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg The CF docs certainly doesnt suggest this is true. Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/helper.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index c7b0fbe..6feb4bf 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -205,19 +205,12 @@ static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) break; case CC_OP_LOGICB: SET_NZ(dest, int8_t); - goto set_x; break; case CC_OP_LOGICW: SET_NZ(dest, int16_t); - goto set_x; break; case CC_OP_LOGIC: SET_NZ(dest, int32_t); -set_x: - if (!m68k_feature(env, M68K_FEATURE_M68000)) { - /* Unlike m68k, coldfire always clears the overflow bit. */ - env->cc_x = 0; - } break; case CC_OP_ADDB: SET_FLAGS_ADD(int8_t, uint8_t); -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x 2015-08-14 14:59 ` [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x Richard Henderson @ 2015-08-14 17:04 ` Andreas Schwab 2015-08-14 23:10 ` Richard Henderson 0 siblings, 1 reply; 16+ messages in thread From: Andreas Schwab @ 2015-08-14 17:04 UTC (permalink / raw) To: Richard Henderson; +Cc: peter.maydell, gerg, qemu-devel, laurent Richard Henderson <rth@twiddle.net> writes: > The CF docs certainly doesnt suggest this is true. > > Signed-off-by: Richard Henderson <rth@twiddle.net> > --- > target-m68k/helper.c | 7 ------- > 1 file changed, 7 deletions(-) > > diff --git a/target-m68k/helper.c b/target-m68k/helper.c > index c7b0fbe..6feb4bf 100644 > --- a/target-m68k/helper.c > +++ b/target-m68k/helper.c > @@ -205,19 +205,12 @@ static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) > break; > case CC_OP_LOGICB: > SET_NZ(dest, int8_t); > - goto set_x; > break; > case CC_OP_LOGICW: > SET_NZ(dest, int16_t); > - goto set_x; > break; > case CC_OP_LOGIC: > SET_NZ(dest, int32_t); > -set_x: > - if (!m68k_feature(env, M68K_FEATURE_M68000)) { > - /* Unlike m68k, coldfire always clears the overflow bit. */ I think this refers to the muls/mulu insn, where the CF always clears V. Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x 2015-08-14 17:04 ` Andreas Schwab @ 2015-08-14 23:10 ` Richard Henderson 2015-08-15 6:25 ` Andreas Schwab 0 siblings, 1 reply; 16+ messages in thread From: Richard Henderson @ 2015-08-14 23:10 UTC (permalink / raw) To: Andreas Schwab; +Cc: qemu-devel, peter.maydell, Laurent Vivier, gerg On Aug 14, 2015 10:04, Andreas Schwab <schwab@linux-m68k.org> wrote: > > Richard Henderson <rth@twiddle.net> writes: > > > The CF docs certainly doesnt suggest this is true. > > > > Signed-off-by: Richard Henderson <rth@twiddle.net> > > --- > > target-m68k/helper.c | 7 ------- > > 1 file changed, 7 deletions(-) > > > > diff --git a/target-m68k/helper.c b/target-m68k/helper.c > > index c7b0fbe..6feb4bf 100644 > > --- a/target-m68k/helper.c > > +++ b/target-m68k/helper.c > > @@ -205,19 +205,12 @@ static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) > > break; > > case CC_OP_LOGICB: > > SET_NZ(dest, int8_t); > > - goto set_x; > > break; > > case CC_OP_LOGICW: > > SET_NZ(dest, int16_t); > > - goto set_x; > > break; > > case CC_OP_LOGIC: > > SET_NZ(dest, int32_t); > > -set_x: > > - if (!m68k_feature(env, M68K_FEATURE_M68000)) { > > - /* Unlike m68k, coldfire always clears the overflow bit. */ > > I think this refers to the muls/mulu insn, where the CF always clears V. Ah. Except placed here it also applies to and/or/move too. r~ ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x 2015-08-14 23:10 ` Richard Henderson @ 2015-08-15 6:25 ` Andreas Schwab 0 siblings, 0 replies; 16+ messages in thread From: Andreas Schwab @ 2015-08-15 6:25 UTC (permalink / raw) To: Richard Henderson; +Cc: qemu-devel, peter.maydell, Laurent Vivier, gerg Richard Henderson <rth@twiddle.net> writes: > Ah. Except placed here it also applies to and/or/move too. Well, none of those ever overflow in the first place. Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 04/11] target-m68k: Replace helper_xflag_lt with setcond 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (2 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 05/11] target-m68k: Reorg flags handling Richard Henderson ` (7 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/helper.c | 5 ----- target-m68k/helper.h | 1 - target-m68k/translate.c | 14 +++++++------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 6feb4bf..a032947 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -465,11 +465,6 @@ uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) return res; } -uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b) -{ - return a < b; -} - void HELPER(set_sr)(CPUM68KState *env, uint32_t val) { env->sr = val & 0xffe0; diff --git a/target-m68k/helper.h b/target-m68k/helper.h index 81c8e79..0f5a7cf 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -8,7 +8,6 @@ DEF_HELPER_3(subx_cc, i32, env, i32, i32) DEF_HELPER_3(shl_cc, i32, env, i32, i32) DEF_HELPER_3(shr_cc, i32, env, i32, i32) DEF_HELPER_3(sar_cc, i32, env, i32, i32) -DEF_HELPER_2(xflag_lt, i32, i32, i32) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(movec, void, env, i32, i32) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 2c720a2..cf6a54c 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1102,10 +1102,10 @@ DISAS_INSN(addsub) } if (add) { tcg_gen_add_i32(dest, tmp, src); - gen_helper_xflag_lt(QREG_CC_X, dest, src); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src); set_cc_op(s, CC_OP_ADD); } else { - gen_helper_xflag_lt(QREG_CC_X, tmp, src); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src); tcg_gen_sub_i32(dest, tmp, src); set_cc_op(s, CC_OP_SUB); } @@ -1317,7 +1317,7 @@ DISAS_INSN(arith_im) break; case 2: /* subi */ tcg_gen_mov_i32(dest, src1); - gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im)); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, tcg_const_i32(im)); tcg_gen_subi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); set_cc_op(s, CC_OP_SUB); @@ -1326,7 +1326,7 @@ DISAS_INSN(arith_im) tcg_gen_mov_i32(dest, src1); tcg_gen_addi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); - gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im)); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, tcg_const_i32(im)); set_cc_op(s, CC_OP_ADD); break; case 5: /* eori */ @@ -1456,7 +1456,7 @@ DISAS_INSN(neg) tcg_gen_neg_i32(reg, src1); set_cc_op(s, CC_OP_SUB); gen_update_cc_add(reg, src1); - gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tcg_const_i32(0), src1); set_cc_op(s, CC_OP_SUB); } @@ -1696,12 +1696,12 @@ DISAS_INSN(addsubq) } else { src2 = tcg_const_i32(val); if (insn & 0x0100) { - gen_helper_xflag_lt(QREG_CC_X, dest, src2); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); tcg_gen_subi_i32(dest, dest, val); set_cc_op(s, CC_OP_SUB); } else { tcg_gen_addi_i32(dest, dest, val); - gen_helper_xflag_lt(QREG_CC_X, dest, src2); + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); set_cc_op(s, CC_OP_ADD); } gen_update_cc_add(dest, src2); -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 05/11] target-m68k: Reorg flags handling 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (3 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 04/11] target-m68k: Replace helper_xflag_lt with setcond Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 06/11] target-m68k: Introduce DisasCompare Richard Henderson ` (6 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Separate all ccr bits. Continue to batch updates via cc_op. Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/cpu.c | 2 +- target-m68k/cpu.h | 46 +++--- target-m68k/helper.c | 400 +++++++++++++++++++++--------------------------- target-m68k/helper.h | 6 +- target-m68k/op_helper.c | 30 ++-- target-m68k/qregs.def | 6 +- target-m68k/translate.c | 376 +++++++++++++++++++-------------------------- 7 files changed, 379 insertions(+), 487 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index d4d8c12..5bdee93 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -55,7 +55,7 @@ static void m68k_cpu_reset(CPUState *s) #endif m68k_switch_sp(env); /* ??? FP regs should be initialized to NaN. */ - env->cc_op = CC_OP_FLAGS; + cpu_m68k_set_ccr(env, 0); /* TODO: We should set PC from the interrupt vector. */ env->pc = 0; tlb_flush(s, 1); diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 4f0d053..43827b1 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -68,9 +68,11 @@ typedef struct CPUM68KState { /* Condition flags. */ uint32_t cc_op; - uint32_t cc_dest; - uint32_t cc_src; - uint32_t cc_x; + uint32_t cc_x; /* always 0/1 */ + uint32_t cc_n; /* in bit 31 (i.e. negative) */ + uint32_t cc_v; /* in bit 31, unused, or computed from cc_n and cc_v */ + uint32_t cc_c; /* either 0/1, unused, or computed from cc_n and cc_v */ + uint32_t cc_z; /* == 0 or unused */ float64 fregs[8]; float64 fp_result; @@ -127,27 +129,23 @@ uint32_t cpu_m68k_get_ccr(CPUM68KState *env); void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); typedef enum { - CC_OP_DYNAMIC, /* Use env->cc_op */ - CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ - CC_OP_LOGICB, /* CC_DEST = result, CC_SRC = unused */ - CC_OP_LOGICW, /* CC_DEST = result, CC_SRC = unused */ - CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */ - CC_OP_ADDB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_ADDW, /* CC_DEST = result, CC_SRC = source */ - CC_OP_ADD, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUBB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUBW, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_ADDXB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_ADDXW, /* CC_DEST = result, CC_SRC = source */ - CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUBXB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUBXW, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */ - CC_OP_SHIFTB, /* CC_DEST = result, CC_SRC = carry */ - CC_OP_SHIFTW, /* CC_DEST = result, CC_SRC = carry */ - CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */ - CC_OP_NB, + /* Translator only -- use env->cc_op. */ + CC_OP_DYNAMIC = -1, + + /* Each flag bit computed into cc_[xcnvz]. */ + CC_OP_FLAGS, + + /* X in cc_x, C = X, N in cc_n, Z in cc_n, V via cc_n/cc_v. */ + CC_OP_ADD, + CC_OP_SUB, + + /* X in cc_x, {N,Z,C,V} via cc_n/cc_v. */ + CC_OP_CMP, + + /* X in cc_x, C = 0, V = 0, N in cc_n, Z in cc_n. */ + CC_OP_LOGIC, + + CC_OP_NB } CCOp; #define CCF_C 0x01 diff --git a/target-m68k/helper.c b/target-m68k/helper.c index a032947..ff7e481 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -130,151 +130,6 @@ void m68k_cpu_init_gdb(M68kCPU *cpu) /* TODO: Add [E]MAC registers. */ } -static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) -{ - int flags; - uint32_t src; - uint32_t dest; - uint32_t tmp; - -#define HIGHBIT(type) (1u << (sizeof(type) * 8 - 1)) - -#define SET_NZ(x, type) do { \ - if ((type)(x) == 0) { \ - flags |= CCF_Z; \ - } else if ((type)(x) < 0) { \ - flags |= CCF_N; \ - } \ - } while (0) - -#define SET_FLAGS_SUB(type, utype) do { \ - SET_NZ(dest, type); \ - tmp = dest + src; \ - if ((utype) tmp < (utype) src) { \ - flags |= CCF_C; \ - } \ - if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) { \ - flags |= CCF_V; \ - } \ - } while (0) - -#define SET_FLAGS_ADD(type, utype) do { \ - SET_NZ(dest, type); \ - if ((utype) dest < (utype) src) { \ - flags |= CCF_C; \ - } \ - tmp = dest - src; \ - if (HIGHBIT(type) & (src ^ dest) & ~(tmp ^ src)) { \ - flags |= CCF_V; \ - } \ - } while (0) - -#define SET_FLAGS_ADDX(type, utype) do { \ - SET_NZ(dest, type); \ - if ((utype) dest <= (utype) src) { \ - flags |= CCF_C; \ - } \ - tmp = dest - src - 1; \ - if (HIGHBIT(type) & (src ^ dest) & ~(tmp ^ src)) { \ - flags |= CCF_V; \ - } \ - } while (0) - -#define SET_FLAGS_SUBX(type, utype) do { \ - SET_NZ(dest, type); \ - tmp = dest + src + 1; \ - if ((utype) tmp <= (utype) src) { \ - flags |= CCF_C; \ - } \ - if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) { \ - flags |= CCF_V; \ - } \ - } while (0) - -#define SET_FLAGS_SHIFT(type) do { \ - SET_NZ(dest, type); \ - flags |= src; \ - } while (0) - - flags = 0; - src = env->cc_src; - dest = env->cc_dest; - switch (op) { - case CC_OP_FLAGS: - flags = dest; - break; - case CC_OP_LOGICB: - SET_NZ(dest, int8_t); - break; - case CC_OP_LOGICW: - SET_NZ(dest, int16_t); - break; - case CC_OP_LOGIC: - SET_NZ(dest, int32_t); - break; - case CC_OP_ADDB: - SET_FLAGS_ADD(int8_t, uint8_t); - break; - case CC_OP_ADDW: - SET_FLAGS_ADD(int16_t, uint16_t); - break; - case CC_OP_ADD: - SET_FLAGS_ADD(int32_t, uint32_t); - break; - case CC_OP_SUBB: - SET_FLAGS_SUB(int8_t, uint8_t); - break; - case CC_OP_SUBW: - SET_FLAGS_SUB(int16_t, uint16_t); - break; - case CC_OP_SUB: - SET_FLAGS_SUB(int32_t, uint32_t); - break; - case CC_OP_ADDXB: - SET_FLAGS_ADDX(int8_t, uint8_t); - break; - case CC_OP_ADDXW: - SET_FLAGS_ADDX(int16_t, uint16_t); - break; - case CC_OP_ADDX: - SET_FLAGS_ADDX(int32_t, uint32_t); - break; - case CC_OP_SUBXB: - SET_FLAGS_SUBX(int8_t, uint8_t); - break; - case CC_OP_SUBXW: - SET_FLAGS_SUBX(int16_t, uint16_t); - break; - case CC_OP_SUBX: - SET_FLAGS_SUBX(int32_t, uint32_t); - break; - case CC_OP_SHIFTB: - SET_FLAGS_SHIFT(int8_t); - break; - case CC_OP_SHIFTW: - SET_FLAGS_SHIFT(int16_t); - break; - case CC_OP_SHIFT: - SET_FLAGS_SHIFT(int32_t); - break; - default: - g_assert_not_reached(); - } - return flags; -} - -uint32_t cpu_m68k_get_ccr(CPUM68KState *env) -{ - return cpu_m68k_flush_flags(env, env->cc_op) | env->cc_x * CCF_X; -} - -void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t val) -{ - env->cc_op = CC_OP_FLAGS; - env->cc_dest = val & 0xf; - env->cc_x = (val & CCF_X ? 1 : 0); -} - void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) { M68kCPU *cpu = m68k_env_get_cpu(env); @@ -411,57 +266,52 @@ uint32_t HELPER(ff1)(uint32_t x) return n; } -uint32_t HELPER(sats)(uint32_t val, uint32_t ccr) +uint32_t HELPER(sats)(uint32_t val, uint32_t v) { /* The result has the opposite sign to the original value. */ - if (ccr & CCF_V) + if ((int32_t)v < 0) { val = (((int32_t)val) >> 31) ^ SIGNBIT; + } return val; } uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) { - uint32_t res; - uint32_t old_flags; + uint32_t res, new_x; - old_flags = env->cc_dest; if (env->cc_x) { - env->cc_x = (op1 <= op2); - env->cc_op = CC_OP_SUBX; + new_x = (op1 <= op2); res = op1 - (op2 + 1); } else { - env->cc_x = (op1 < op2); - env->cc_op = CC_OP_SUB; + new_x = (op1 < op2); res = op1 - op2; } - env->cc_dest = res; - env->cc_src = op2; - cpu_m68k_flush_flags(env, env->cc_op); - /* !Z is sticky. */ - env->cc_dest &= (old_flags | ~CCF_Z); + env->cc_x = new_x; + env->cc_c = new_x; + env->cc_n = res; + env->cc_z |= res; /* !Z is sticky */ + env->cc_v = (res ^ op1) & (op1 ^ op2); + return res; } uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) { - uint32_t res; - uint32_t old_flags; + uint32_t res, new_x; - old_flags = env->cc_dest; if (env->cc_x) { res = op1 + op2 + 1; - env->cc_x = (res <= op2); - env->cc_op = CC_OP_ADDX; + new_x = (res <= op2); } else { res = op1 + op2; - env->cc_x = (res < op2); - env->cc_op = CC_OP_ADD; - } - env->cc_dest = res; - env->cc_src = op2; - cpu_m68k_flush_flags(env, env->cc_op); - /* !Z is sticky. */ - env->cc_dest &= (old_flags | ~CCF_Z); + new_x = (res < op2); + } + env->cc_x = new_x; + env->cc_c = new_x; + env->cc_n = res; + env->cc_z |= res; /* !Z is sticky. */ + env->cc_v = (res ^ op1) & ~(op1 ^ op2); + return res; } @@ -474,73 +324,53 @@ void HELPER(set_sr)(CPUM68KState *env, uint32_t val) uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) { - uint32_t result; - uint32_t cf; + uint64_t result; shift &= 63; - if (shift == 0) { - result = val; - cf = env->cc_src & CCF_C; - } else if (shift < 32) { - result = val << shift; - cf = (val >> (32 - shift)) & 1; - } else if (shift == 32) { - result = 0; - cf = val & 1; - } else /* shift > 32 */ { - result = 0; - cf = 0; - } - env->cc_src = cf; - env->cc_x = (cf != 0); - env->cc_dest = result; + result = (uint64_t)val << shift; + + env->cc_c = (result >> 32) & 1; + env->cc_n = result; + env->cc_z = result; + env->cc_v = 0; + env->cc_x = shift ? env->cc_c : env->cc_x; + return result; } uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) { + uint64_t temp; uint32_t result; - uint32_t cf; shift &= 63; - if (shift == 0) { - result = val; - cf = env->cc_src & CCF_C; - } else if (shift < 32) { - result = val >> shift; - cf = (val >> (shift - 1)) & 1; - } else if (shift == 32) { - result = 0; - cf = val >> 31; - } else /* shift > 32 */ { - result = 0; - cf = 0; - } - env->cc_src = cf; - env->cc_x = (cf != 0); - env->cc_dest = result; + temp = (uint64_t)val << 32 >> shift; + result = temp >> 32; + + env->cc_c = (temp >> 31) & 1; + env->cc_n = result; + env->cc_z = result; + env->cc_v = 0; + env->cc_x = shift ? env->cc_c : env->cc_x; + return result; } uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) { + uint64_t temp; uint32_t result; - uint32_t cf; shift &= 63; - if (shift == 0) { - result = val; - cf = (env->cc_src & CCF_C) != 0; - } else if (shift < 32) { - result = (int32_t)val >> shift; - cf = (val >> (shift - 1)) & 1; - } else /* shift >= 32 */ { - result = (int32_t)val >> 31; - cf = val >> 31; - } - env->cc_src = cf; - env->cc_x = cf; - env->cc_dest = result; + temp = (int64_t)val << 32 >> shift; + result = temp >> 32; + + env->cc_c = (temp >> 31) & 1; + env->cc_n = result; + env->cc_z = result; + env->cc_v = result ^ val; + env->cc_x = shift ? env->cc_c : env->cc_x; + return result; } @@ -792,9 +622,133 @@ void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) } } -uint32_t HELPER(flush_flags)(CPUM68KState *env, uint32_t op) +uint32_t cpu_m68k_get_ccr(CPUM68KState *env) { - return cpu_m68k_flush_flags(env, op); + uint32_t x, c, n, z, v; + uint32_t res, src1, src2; + + x = env->cc_x; + c = env->cc_c; + n = env->cc_n; + z = env->cc_z; + v = env->cc_v; + + switch (env->cc_op) { + case CC_OP_FLAGS: + /* Everything in place. */ + break; + + case CC_OP_ADD: + res = n; + src2 = v; + src1 = res - src2; + c = x; + z = n; + v = (res ^ src1) & ~(src1 ^ src2); + break; + + case CC_OP_SUB: + res = n; + src2 = v; + src1 = res + src2; + c = x; + z = n; + v = (res ^ src1) & (src1 ^ src2); + break; + + case CC_OP_CMP: + src1 = n; + src2 = v; + res = src1 - src2; + n = res; + z = res; + c = src1 < src2; + v = (res ^ src1) & (src1 ^ src2); + break; + + case CC_OP_LOGIC: + c = v = 0; + z = n; + break; + + default: + cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", env->cc_op); + } + + n = n >> 31; + v = v >> 31; + z = (z == 0); + + return x*CCF_X + n*CCF_N + z*CCF_Z + v*CCF_V + c*CCF_C; +} + +uint32_t HELPER(get_ccr)(CPUM68KState *env) +{ + return cpu_m68k_get_ccr(env); +} + +void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t ccr) +{ + env->cc_x = (ccr & CCF_X ? 1 : 0); + env->cc_n = (ccr & CCF_N ? -1 : 0); + env->cc_z = (ccr & CCF_Z ? 0 : 1); + env->cc_v = (ccr & CCF_V ? -1 : 0); + env->cc_c = (ccr & CCF_C ? 1 : 0); + env->cc_op = CC_OP_FLAGS; +} + +void HELPER(set_ccr)(CPUM68KState *env, uint32_t ccr) +{ + cpu_m68k_set_ccr(env, ccr); +} + +void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) +{ + uint32_t res, src1, src2; + + switch (cc_op) { + case CC_OP_FLAGS: + /* Everything up to date. */ + return; + + case CC_OP_ADD: + res = env->cc_n; + src2 = env->cc_v; + src1 = res - src2; + env->cc_z = res; + env->cc_c = env->cc_x; + env->cc_v = (res ^ src1) & ~(src1 ^ src2); + break; + + case CC_OP_SUB: + res = env->cc_n; + src2 = env->cc_v; + src1 = res + src2; + env->cc_z = res; + env->cc_c = env->cc_x; + env->cc_v = (res ^ src1) & (src1 ^ src2); + break; + + case CC_OP_CMP: + src1 = env->cc_n; + src2 = env->cc_v; + res = src1 - src2; + env->cc_n = res; + env->cc_z = res; + env->cc_c = src1 < src2; + env->cc_v = (res ^ src1) & (src1 ^ src2); + break; + + case CC_OP_LOGIC: + env->cc_c = 0; + env->cc_v = 0; + env->cc_z = env->cc_n; + break; + + default: + cpu_abort(CPU(m68k_env_get_cpu(env)), "Bad CC_OP %d", cc_op); + } + env->cc_op = CC_OP_FLAGS; } uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) diff --git a/target-m68k/helper.h b/target-m68k/helper.h index 0f5a7cf..c868148 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -1,6 +1,6 @@ DEF_HELPER_1(bitrev, i32, i32) DEF_HELPER_1(ff1, i32, i32) -DEF_HELPER_2(sats, i32, i32, i32) +DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_2(divu, void, env, i32) DEF_HELPER_2(divs, void, env, i32) DEF_HELPER_3(addx_cc, i32, env, i32, i32) @@ -45,5 +45,7 @@ DEF_HELPER_3(set_mac_extf, void, env, i32, i32) DEF_HELPER_3(set_mac_exts, void, env, i32, i32) DEF_HELPER_3(set_mac_extu, void, env, i32, i32) -DEF_HELPER_2(flush_flags, i32, env, i32) +DEF_HELPER_2(flush_flags, void, env, i32) +DEF_HELPER_2(set_ccr, void, env, i32) +DEF_HELPER_FLAGS_1(get_ccr, TCG_CALL_NO_WG_SE, i32, env) DEF_HELPER_2(raise_exception, void, env, i32) diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c index 29032c6..6203ae9 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -183,7 +183,6 @@ void HELPER(divu)(CPUM68KState *env, uint32_t word) uint32_t den; uint32_t quot; uint32_t rem; - uint32_t flags; num = env->div1; den = env->div2; @@ -193,16 +192,14 @@ void HELPER(divu)(CPUM68KState *env, uint32_t word) } quot = num / den; rem = num % den; - flags = 0; - if (word && quot > 0xffff) - flags |= CCF_V; - if (quot == 0) - flags |= CCF_Z; - else if ((int32_t)quot < 0) - flags |= CCF_N; + + env->cc_v = (word && quot > 0xffff ? -1 : 0); + env->cc_z = quot; + env->cc_n = quot; + env->cc_c = 0; + env->div1 = quot; env->div2 = rem; - env->cc_dest = flags; } void HELPER(divs)(CPUM68KState *env, uint32_t word) @@ -211,7 +208,6 @@ void HELPER(divs)(CPUM68KState *env, uint32_t word) int32_t den; int32_t quot; int32_t rem; - int32_t flags; num = env->div1; den = env->div2; @@ -220,14 +216,12 @@ void HELPER(divs)(CPUM68KState *env, uint32_t word) } quot = num / den; rem = num % den; - flags = 0; - if (word && quot != (int16_t)quot) - flags |= CCF_V; - if (quot == 0) - flags |= CCF_Z; - else if (quot < 0) - flags |= CCF_N; + + env->cc_v = (word && quot != (int16_t)quot ? -1 : 0); + env->cc_z = quot; + env->cc_n = quot; + env->cc_c = 0; + env->div1 = quot; env->div2 = rem; - env->cc_dest = flags; } diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def index 204663e..156c0f5 100644 --- a/target-m68k/qregs.def +++ b/target-m68k/qregs.def @@ -2,9 +2,11 @@ DEFF64(FP_RESULT, fp_result) DEFO32(PC, pc) DEFO32(SR, sr) DEFO32(CC_OP, cc_op) -DEFO32(CC_DEST, cc_dest) -DEFO32(CC_SRC, cc_src) DEFO32(CC_X, cc_x) +DEFO32(CC_C, cc_c) +DEFO32(CC_N, cc_n) +DEFO32(CC_V, cc_v) +DEFO32(CC_Z, cc_z) DEFO32(DIV1, div1) DEFO32(DIV2, div2) DEFO32(MACSR, macsr) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index cf6a54c..b0cb39d 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -128,6 +128,7 @@ typedef struct DisasContext { target_ulong pc; int is_jmp; CCOp cc_op; /* Current CC operation */ + int cc_op_synced; int user; uint32_t fpcr; struct TranslationBlock *tb; @@ -177,49 +178,44 @@ typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); uint16_t insn) #endif -enum { - USES_CC_DST = 1, - USES_CC_SRC = 2, -}; - static const uint8_t cc_op_live[CC_OP_NB] = { - [CC_OP_DYNAMIC] = USES_CC_DST | USES_CC_SRC, - [CC_OP_FLAGS] = USES_CC_DST, - [CC_OP_LOGICB ... CC_OP_LOGIC] = USES_CC_DST, - [CC_OP_ADDB ... CC_OP_ADD] = USES_CC_DST | USES_CC_SRC, - [CC_OP_SUBB ... CC_OP_SUB] = USES_CC_DST | USES_CC_SRC, - [CC_OP_ADDXB ... CC_OP_ADDX] = USES_CC_DST | USES_CC_SRC, - [CC_OP_SUBXB ... CC_OP_SUBX] = USES_CC_DST | USES_CC_SRC, - [CC_OP_SHIFTB ... CC_OP_SHIFT] = USES_CC_DST | USES_CC_SRC, + [CC_OP_FLAGS] = CCF_C | CCF_V | CCF_Z | CCF_N | CCF_X, + [CC_OP_ADD] = CCF_X | CCF_N | CCF_V, + [CC_OP_SUB] = CCF_X | CCF_N | CCF_V, + [CC_OP_CMP] = CCF_X | CCF_N | CCF_V, + [CC_OP_LOGIC] = CCF_X | CCF_N }; static void set_cc_op(DisasContext *s, CCOp op) { + CCOp old_op = s->cc_op; int dead; - if (s->cc_op == op) { + if (old_op == op) { return; } + s->cc_op = op; + s->cc_op_synced = 0; - /* Discard CC computation that will no longer be used. */ - - dead = cc_op_live[s->cc_op] & ~cc_op_live[op]; - if (dead & USES_CC_DST) { - tcg_gen_discard_i32(QREG_CC_DEST); + /* Discard CC computation that will no longer be used. + Note that X and N are never dead. */ + dead = cc_op_live[old_op] & ~cc_op_live[op]; + if (dead & CCF_C) { + tcg_gen_discard_i32(QREG_CC_C); } - if (dead & USES_CC_SRC) { - tcg_gen_discard_i32(QREG_CC_SRC); + if (dead & CCF_Z) { + tcg_gen_discard_i32(QREG_CC_Z); } - if (s->cc_op == CC_OP_DYNAMIC) { - tcg_gen_discard_i32(QREG_CC_OP); + if (dead & CCF_V) { + tcg_gen_discard_i32(QREG_CC_V); } - s->cc_op = op; } /* Update the CPU env CC_OP state. */ -static inline void update_cc_op(DisasContext *s) +static void update_cc_op(DisasContext *s) { - if (s->cc_op != CC_OP_DYNAMIC) { + if (!s->cc_op_synced) { + s->cc_op_synced = 1; tcg_gen_movi_i32(QREG_CC_OP, s->cc_op); } } @@ -463,41 +459,69 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) /* Evaluate all the CC flags. */ -static inline void gen_flush_flags(DisasContext *s) +static void gen_flush_flags(DisasContext *s) { - if (s->cc_op == CC_OP_FLAGS) + TCGv tmp; + + switch (s->cc_op) { + case CC_OP_FLAGS: return; - if (s->cc_op == CC_OP_DYNAMIC) { - gen_helper_flush_flags(QREG_CC_DEST, cpu_env, QREG_CC_OP); - } else { - gen_helper_flush_flags(QREG_CC_DEST, cpu_env, tcg_const_i32(s->cc_op)); + case CC_OP_DYNAMIC: + gen_helper_flush_flags(cpu_env, QREG_CC_OP); + break; + default: + tmp = tcg_const_i32(s->cc_op); + gen_helper_flush_flags(cpu_env, tmp); + tcg_temp_free(tmp); + break; } - set_cc_op(s, CC_OP_FLAGS); + + /* Note that flush_flags also assigned to env->cc_op. */ + s->cc_op = CC_OP_FLAGS; + s->cc_op_synced = 1; } -#define SET_CC_OP(opsize, op) do { \ - switch (opsize) { \ - case OS_BYTE: \ - set_cc_op(s, CC_OP_##op##B); break; \ - case OS_WORD: \ - set_cc_op(s, CC_OP_##op##W); break; \ - case OS_LONG: \ - set_cc_op(s, CC_OP_##op); break; \ - default: \ - abort(); \ - } \ -} while (0) +/* Sign or zero extend a value. */ +static TCGv gen_extend(TCGv val, int opsize, int sign) +{ + TCGv tmp; + + switch (opsize) { + case OS_BYTE: + tmp = tcg_temp_new(); + if (sign) + tcg_gen_ext8s_i32(tmp, val); + else + tcg_gen_ext8u_i32(tmp, val); + break; + case OS_WORD: + tmp = tcg_temp_new(); + if (sign) + tcg_gen_ext16s_i32(tmp, val); + else + tcg_gen_ext16u_i32(tmp, val); + break; + case OS_LONG: + case OS_SINGLE: + tmp = val; + break; + default: + g_assert_not_reached(); + } + return tmp; +} static void gen_logic_cc(DisasContext *s, TCGv val, int opsize) { - tcg_gen_mov_i32(QREG_CC_DEST, val); - SET_CC_OP(opsize, LOGIC); + tcg_gen_mov_i32(QREG_CC_N, val); + gen_extend(QREG_CC_N, opsize, 1); + set_cc_op(s, CC_OP_LOGIC); } static void gen_update_cc_add(TCGv dest, TCGv src) { - tcg_gen_mov_i32(QREG_CC_DEST, dest); - tcg_gen_mov_i32(QREG_CC_SRC, src); + tcg_gen_mov_i32(QREG_CC_N, dest); + tcg_gen_mov_i32(QREG_CC_V, src); } static inline int opsize_bytes(int opsize) @@ -578,36 +602,6 @@ static void gen_partset_reg(int opsize, TCGv reg, TCGv val) } } -/* Sign or zero extend a value. */ -static inline TCGv gen_extend(TCGv val, int opsize, int sign) -{ - TCGv tmp; - - switch (opsize) { - case OS_BYTE: - tmp = tcg_temp_new(); - if (sign) - tcg_gen_ext8s_i32(tmp, val); - else - tcg_gen_ext8u_i32(tmp, val); - break; - case OS_WORD: - tmp = tcg_temp_new(); - if (sign) - tcg_gen_ext16s_i32(tmp, val); - else - tcg_gen_ext16u_i32(tmp, val); - break; - case OS_LONG: - case OS_SINGLE: - tmp = val; - break; - default: - g_assert_not_reached(); - } - return tmp; -} - /* Generate code for an "effective address". Does not adjust the base register for autoincrement addressing modes. */ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, @@ -790,7 +784,8 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, /* This generates a conditional branch, clobbering all temporaries. */ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) { - TCGv tmp; + TCGv tmp, tmp2; + TCGCond tcond; /* TODO: Optimize compare/branch pairs rather than always flushing flag state to CC_OP_FLAGS. */ @@ -798,97 +793,57 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) switch (cond) { case 0: /* T */ tcg_gen_br(l1); - break; + return; case 1: /* F */ - break; - case 2: /* HI (!C && !Z) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; + return; + case 2: /* HI (!C && !Z) -> !(C || Z)*/ case 3: /* LS (C || Z) */ tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C | CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, QREG_CC_Z, 0); + tcg_gen_or_i32(tmp, tmp, QREG_CC_C); + tcond = (cond & 1 ? TCG_COND_NE: TCG_COND_EQ); break; case 4: /* CC (!C) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 5: /* CS (C) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tmp = QREG_CC_C; + tcond = (cond & 1 ? TCG_COND_NE : TCG_COND_EQ); break; case 6: /* NE (!Z) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 7: /* EQ (Z) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tmp = QREG_CC_Z; + tcond = (cond & 1 ? TCG_COND_EQ : TCG_COND_NE); break; case 8: /* VC (!V) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 9: /* VS (V) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tmp = QREG_CC_V; + tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); break; case 10: /* PL (!N) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 11: /* MI (N) */ - tmp = tcg_temp_new(); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tmp = QREG_CC_N; + tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); break; case 12: /* GE (!(N ^ V)) */ - tmp = tcg_temp_new(); - assert(CCF_V == (CCF_N >> 2)); - tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2); - tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); - tcg_gen_andi_i32(tmp, tmp, CCF_V); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 13: /* LT (N ^ V) */ tmp = tcg_temp_new(); - assert(CCF_V == (CCF_N >> 2)); - tcg_gen_shri_i32(tmp, QREG_CC_DEST, 2); - tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); - tcg_gen_andi_i32(tmp, tmp, CCF_V); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V); + tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); break; case 14: /* GT (!(Z || (N ^ V))) */ - tmp = tcg_temp_new(); - assert(CCF_V == (CCF_N >> 2)); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); - tcg_gen_shri_i32(tmp, tmp, 2); - tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); - tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, l1); - break; case 15: /* LE (Z || (N ^ V)) */ tmp = tcg_temp_new(); - assert(CCF_V == (CCF_N >> 2)); - tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N); - tcg_gen_shri_i32(tmp, tmp, 2); - tcg_gen_xor_i32(tmp, tmp, QREG_CC_DEST); - tcg_gen_andi_i32(tmp, tmp, CCF_V | CCF_Z); - tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1); + tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, QREG_CC_Z, 0); + tcg_gen_neg_i32(tmp, tmp); + tmp2 = tcg_temp_new(); + tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V); + tcg_gen_or_i32(tmp, tmp, tmp2); + tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); break; default: /* Should ever happen. */ abort(); } + tcg_gen_brcondi_i32(tcond, tmp, 0, l1); } DISAS_INSN(scc) @@ -1046,6 +1001,7 @@ DISAS_INSN(divw) tcg_gen_ext16u_i32(tmp, QREG_DIV1); tcg_gen_shli_i32(src, QREG_DIV2, 16); tcg_gen_or_i32(reg, tmp, src); + set_cc_op(s, CC_OP_FLAGS); } @@ -1141,42 +1097,43 @@ DISAS_INSN(bitop_reg) else opsize = OS_LONG; op = (insn >> 6) & 3; + + gen_flush_flags(s); + SRC_EA(env, src1, opsize, 0, op ? &addr: NULL); src2 = DREG(insn, 9); dest = tcg_temp_new(); - gen_flush_flags(s); tmp = tcg_temp_new(); if (opsize == OS_BYTE) tcg_gen_andi_i32(tmp, src2, 7); else tcg_gen_andi_i32(tmp, src2, 31); - src2 = tmp; - tmp = tcg_temp_new(); - tcg_gen_shr_i32(tmp, src1, src2); - tcg_gen_andi_i32(tmp, tmp, 1); - tcg_gen_shli_i32(tmp, tmp, 2); - /* Clear CCF_Z if bit set. */ - tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z); - tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp); - - tcg_gen_shl_i32(tmp, tcg_const_i32(1), src2); + + src2 = tcg_const_i32(1); + tcg_gen_shl_i32(src2, src2, tmp); + tcg_temp_free(tmp); + + tcg_gen_and_i32(QREG_CC_Z, src1, src2); + switch (op) { case 1: /* bchg */ - tcg_gen_xor_i32(dest, src1, tmp); + tcg_gen_xor_i32(dest, src1, src2); break; case 2: /* bclr */ - tcg_gen_not_i32(tmp, tmp); - tcg_gen_and_i32(dest, src1, tmp); + tcg_gen_andc_i32(dest, src1, src2); break; case 3: /* bset */ - tcg_gen_or_i32(dest, src1, tmp); + tcg_gen_or_i32(dest, src1, src2); break; default: /* btst */ break; } - if (op) + tcg_temp_free(src2); + if (op) { DEST_EA(env, insn, opsize, dest, &addr); + } + tcg_temp_free(dest); } DISAS_INSN(sats) @@ -1184,7 +1141,7 @@ DISAS_INSN(sats) TCGv reg; reg = DREG(insn, 0); gen_flush_flags(s); - gen_helper_sats(reg, reg, QREG_CC_DEST); + gen_helper_sats(reg, reg, QREG_CC_V); gen_logic_cc(s, reg, OS_LONG); } @@ -1256,28 +1213,20 @@ DISAS_INSN(bitop_im) return; } + gen_flush_flags(s); + SRC_EA(env, src1, opsize, 0, op ? &addr: NULL); - gen_flush_flags(s); if (opsize == OS_BYTE) bitnum &= 7; else bitnum &= 31; mask = 1 << bitnum; - tmp = tcg_temp_new(); - assert (CCF_Z == (1 << 2)); - if (bitnum > 2) - tcg_gen_shri_i32(tmp, src1, bitnum - 2); - else if (bitnum < 2) - tcg_gen_shli_i32(tmp, src1, 2 - bitnum); - else - tcg_gen_mov_i32(tmp, src1); - tcg_gen_andi_i32(tmp, tmp, CCF_Z); - /* Clear CCF_Z if bit set. */ - tcg_gen_ori_i32(QREG_CC_DEST, QREG_CC_DEST, CCF_Z); - tcg_gen_xor_i32(QREG_CC_DEST, QREG_CC_DEST, tmp); + tcg_gen_andi_i32(QREG_CC_Z, src1, mask); + if (op) { + tmp = tcg_temp_new(); switch (op) { case 1: /* bchg */ tcg_gen_xori_i32(tmp, src1, mask); @@ -1292,8 +1241,10 @@ DISAS_INSN(bitop_im) break; } DEST_EA(env, insn, opsize, tmp, &addr); + tcg_temp_free(tmp); } } + DISAS_INSN(arith_im) { int op; @@ -1317,7 +1268,7 @@ DISAS_INSN(arith_im) break; case 2: /* subi */ tcg_gen_mov_i32(dest, src1); - tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, tcg_const_i32(im)); + tcg_gen_setcondi_i32(TCG_COND_LTU, QREG_CC_X, dest, im); tcg_gen_subi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); set_cc_op(s, CC_OP_SUB); @@ -1326,7 +1277,7 @@ DISAS_INSN(arith_im) tcg_gen_mov_i32(dest, src1); tcg_gen_addi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); - tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, tcg_const_i32(im)); + tcg_gen_setcondi_i32(TCG_COND_LTU, QREG_CC_X, dest, im); set_cc_op(s, CC_OP_ADD); break; case 5: /* eori */ @@ -1334,10 +1285,8 @@ DISAS_INSN(arith_im) gen_logic_cc(s, dest, OS_LONG); break; case 6: /* cmpi */ - tcg_gen_mov_i32(dest, src1); - tcg_gen_subi_i32(dest, dest, im); - gen_update_cc_add(dest, tcg_const_i32(im)); - set_cc_op(s, CC_OP_SUB); + gen_update_cc_add(src1, tcg_const_i32(im)); + set_cc_op(s, CC_OP_CMP); break; default: abort(); @@ -1429,9 +1378,9 @@ static TCGv gen_get_ccr(DisasContext *s) TCGv dest; gen_flush_flags(s); + dest = tcg_temp_new(); - tcg_gen_shli_i32(dest, QREG_CC_X, 4); - tcg_gen_or_i32(dest, dest, QREG_CC_DEST); + gen_helper_get_ccr(dest, cpu_env); return dest; } @@ -1454,39 +1403,40 @@ DISAS_INSN(neg) src1 = tcg_temp_new(); tcg_gen_mov_i32(src1, reg); tcg_gen_neg_i32(reg, src1); - set_cc_op(s, CC_OP_SUB); gen_update_cc_add(reg, src1); - tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tcg_const_i32(0), src1); + tcg_gen_setcondi_i32(TCG_COND_NE, QREG_CC_X, src1, 0); set_cc_op(s, CC_OP_SUB); } static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) { - tcg_gen_movi_i32(QREG_CC_DEST, val & 0xf); - tcg_gen_movi_i32(QREG_CC_X, (val & 0x10) >> 4); - if (!ccr_only) { - gen_helper_set_sr(cpu_env, tcg_const_i32(val & 0xff00)); + if (ccr_only) { + tcg_gen_movi_i32(QREG_CC_C, val & CCF_C ? 1 : 0); + tcg_gen_movi_i32(QREG_CC_V, val & CCF_V ? -1 : 0); + tcg_gen_movi_i32(QREG_CC_Z, val & CCF_Z ? 0 : 1); + tcg_gen_movi_i32(QREG_CC_N, val & CCF_N ? -1 : 0); + tcg_gen_movi_i32(QREG_CC_X, val & CCF_X ? 1 : 0); + } else { + gen_helper_set_sr(cpu_env, tcg_const_i32(val)); } set_cc_op(s, CC_OP_FLAGS); } static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) { - TCGv tmp; - tmp = tcg_temp_new(); - tcg_gen_andi_i32(QREG_CC_DEST, val, 0xf); - tcg_gen_shri_i32(tmp, val, 4); - tcg_gen_andi_i32(QREG_CC_X, tmp, 1); - if (!ccr_only) { + if (ccr_only) { + gen_helper_set_ccr(cpu_env, val); + } else { gen_helper_set_sr(cpu_env, val); } + set_cc_op(s, CC_OP_FLAGS); } static void gen_move_to_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, int ccr_only) { TCGv src; - s->cc_op = CC_OP_FLAGS; + SRC_EA(env, src, OS_WORD, 0, NULL); gen_set_sr(s, src, ccr_only); } @@ -1697,10 +1647,10 @@ DISAS_INSN(addsubq) src2 = tcg_const_i32(val); if (insn & 0x0100) { tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); - tcg_gen_subi_i32(dest, dest, val); + tcg_gen_sub_i32(dest, dest, src2); set_cc_op(s, CC_OP_SUB); } else { - tcg_gen_addi_i32(dest, dest, val); + tcg_gen_add_i32(dest, dest, src2); tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); set_cc_op(s, CC_OP_ADD); } @@ -1745,18 +1695,16 @@ DISAS_INSN(branch) /* bsr */ gen_push(s, tcg_const_i32(s->pc)); } + update_cc_op(s); if (op > 1) { /* Bcc */ l1 = gen_new_label(); gen_jmpcc(s, ((insn >> 8) & 0xf) ^ 1, l1); - update_cc_op(s); gen_jmp_tb(s, 1, base + offset); gen_set_label(l1); - update_cc_op(s); gen_jmp_tb(s, 0, s->pc); } else { /* Unconditional branch. */ - update_cc_op(s); gen_jmp_tb(s, 0, base + offset); } } @@ -1845,16 +1793,13 @@ DISAS_INSN(cmp) { TCGv src; TCGv reg; - TCGv dest; int opsize; opsize = insn_opsize(insn, 6); SRC_EA(env, src, opsize, -1, NULL); reg = DREG(insn, 9); - dest = tcg_temp_new(); - tcg_gen_sub_i32(dest, reg, src); - gen_update_cc_add(dest, src); - SET_CC_OP(opsize, SUB); + gen_update_cc_add(reg, src); + set_cc_op(s, CC_OP_CMP); } DISAS_INSN(cmpa) @@ -1862,7 +1807,6 @@ DISAS_INSN(cmpa) int opsize; TCGv src; TCGv reg; - TCGv dest; if (insn & 0x100) { opsize = OS_LONG; @@ -1871,10 +1815,8 @@ DISAS_INSN(cmpa) } SRC_EA(env, src, opsize, 1, NULL); reg = AREG(insn, 9); - dest = tcg_temp_new(); - tcg_gen_sub_i32(dest, reg, src); - gen_update_cc_add(dest, src); - SET_CC_OP(OS_LONG, SUB); + gen_update_cc_add(reg, src); + set_cc_op(s, CC_OP_CMP); } DISAS_INSN(eor) @@ -1932,7 +1874,6 @@ DISAS_INSN(addx) reg = DREG(insn, 9); src = DREG(insn, 0); gen_helper_addx_cc(reg, cpu_env, reg, src); - set_cc_op(s, CC_OP_FLAGS); } /* TODO: This could be implemented without helper functions. */ @@ -1942,6 +1883,8 @@ DISAS_INSN(shift_im) int tmp; TCGv shift; + set_cc_op(s, CC_OP_FLAGS); + reg = DREG(insn, 0); tmp = (insn >> 9) & 7; if (tmp == 0) @@ -1957,7 +1900,6 @@ DISAS_INSN(shift_im) gen_helper_sar_cc(reg, cpu_env, reg, shift); } } - set_cc_op(s, CC_OP_SHIFT); } DISAS_INSN(shift_reg) @@ -1967,8 +1909,6 @@ DISAS_INSN(shift_reg) reg = DREG(insn, 0); shift = DREG(insn, 9); - /* Shift by zero leaves C flag unmodified. */ - gen_flush_flags(s); if (insn & 0x100) { gen_helper_shl_cc(reg, cpu_env, reg, shift); } else { @@ -1978,7 +1918,7 @@ DISAS_INSN(shift_reg) gen_helper_sar_cc(reg, cpu_env, reg, shift); } } - set_cc_op(s, CC_OP_SHIFT); + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(ff1) @@ -2788,9 +2728,10 @@ DISAS_INSN(from_mext) DISAS_INSN(macsr_to_ccr) { - tcg_gen_movi_i32(QREG_CC_X, 0); - tcg_gen_andi_i32(QREG_CC_DEST, QREG_MACSR, 0xf); - set_cc_op(s, CC_OP_FLAGS); + TCGv tmp = tcg_temp_new(); + tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf); + gen_set_sr(s, tmp, 1); + tcg_temp_free(tmp); } DISAS_INSN(to_mac) @@ -3113,6 +3054,7 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb, dc->is_jmp = DISAS_NEXT; dc->pc = pc_start; dc->cc_op = CC_OP_DYNAMIC; + dc->cc_op_synced = 1; dc->singlestep_enabled = cs->singlestep_enabled; dc->fpcr = env->fpcr; dc->user = (env->sr & SR_S) == 0; -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 06/11] target-m68k: Introduce DisasCompare 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (4 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 05/11] target-m68k: Reorg flags handling Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 07/11] target-m68k: Use setcond for scc Richard Henderson ` (5 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/translate.c | 82 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index b0cb39d..ce48e2a 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -781,8 +781,15 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, return NULL_QREG; } -/* This generates a conditional branch, clobbering all temporaries. */ -static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) +typedef struct { + TCGCond tcond; + bool g1; + bool g2; + TCGv v1; + TCGv v2; +} DisasCompare; + +static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) { TCGv tmp, tmp2; TCGCond tcond; @@ -790,60 +797,91 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) /* TODO: Optimize compare/branch pairs rather than always flushing flag state to CC_OP_FLAGS. */ gen_flush_flags(s); + + c->g1 = 1; + c->g2 = 0; + c->v2 = tcg_const_i32(0); + switch (cond) { case 0: /* T */ - tcg_gen_br(l1); - return; case 1: /* F */ - return; + c->v1 = c->v2; + tcond = TCG_COND_NEVER; + break; case 2: /* HI (!C && !Z) -> !(C || Z)*/ case 3: /* LS (C || Z) */ - tmp = tcg_temp_new(); - tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, QREG_CC_Z, 0); + c->v1 = tmp = tcg_temp_new(); + c->g1 = 0; + tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2); tcg_gen_or_i32(tmp, tmp, QREG_CC_C); - tcond = (cond & 1 ? TCG_COND_NE: TCG_COND_EQ); + tcond = TCG_COND_NE; break; case 4: /* CC (!C) */ case 5: /* CS (C) */ - tmp = QREG_CC_C; - tcond = (cond & 1 ? TCG_COND_NE : TCG_COND_EQ); + c->v1 = QREG_CC_C; + tcond = TCG_COND_NE; break; case 6: /* NE (!Z) */ case 7: /* EQ (Z) */ - tmp = QREG_CC_Z; - tcond = (cond & 1 ? TCG_COND_EQ : TCG_COND_NE); + c->v1 = QREG_CC_Z; + tcond = TCG_COND_EQ; break; case 8: /* VC (!V) */ case 9: /* VS (V) */ - tmp = QREG_CC_V; - tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); + c->v1 = QREG_CC_V; + tcond = TCG_COND_LT; break; case 10: /* PL (!N) */ case 11: /* MI (N) */ - tmp = QREG_CC_N; - tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); + c->v1 = QREG_CC_N; + tcond = TCG_COND_LT; break; case 12: /* GE (!(N ^ V)) */ case 13: /* LT (N ^ V) */ - tmp = tcg_temp_new(); + c->v1 = tmp = tcg_temp_new(); + c->g1 = 0; tcg_gen_xor_i32(tmp, QREG_CC_N, QREG_CC_V); - tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); + tcond = TCG_COND_LT; break; case 14: /* GT (!(Z || (N ^ V))) */ case 15: /* LE (Z || (N ^ V)) */ - tmp = tcg_temp_new(); - tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, QREG_CC_Z, 0); + c->v1 = tmp = tcg_temp_new(); + c->g1 = 0; + tcg_gen_setcond_i32(TCG_COND_EQ, tmp, QREG_CC_Z, c->v2); tcg_gen_neg_i32(tmp, tmp); tmp2 = tcg_temp_new(); tcg_gen_xor_i32(tmp2, QREG_CC_N, QREG_CC_V); tcg_gen_or_i32(tmp, tmp, tmp2); - tcond = (cond & 1 ? TCG_COND_LT : TCG_COND_GE); + tcg_temp_free(tmp2); + tcond = TCG_COND_LT; break; default: /* Should ever happen. */ abort(); } - tcg_gen_brcondi_i32(tcond, tmp, 0, l1); + if ((cond & 1) == 0) { + tcond = tcg_invert_cond(tcond); + } + c->tcond = tcond; +} + +static void free_cond(DisasCompare *c) +{ + if (!c->g1) { + tcg_temp_free(c->v1); + } + if (!c->g2) { + tcg_temp_free(c->v2); + } +} + +static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) +{ + DisasCompare c; + + gen_cc_cond(&c, s, cond); + tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1); + free_cond(&c); } DISAS_INSN(scc) -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 07/11] target-m68k: Use setcond for scc 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (5 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 06/11] target-m68k: Introduce DisasCompare Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 08/11] target-m68k: Optimize some comparisons Richard Henderson ` (4 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/translate.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index ce48e2a..28c3e1e 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -886,19 +886,21 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1) DISAS_INSN(scc) { - TCGLabel *l1; + DisasCompare c; int cond; - TCGv reg; + TCGv reg, tmp; - l1 = gen_new_label(); cond = (insn >> 8) & 0xf; + gen_cc_cond(&c, s, cond); + + tmp = tcg_temp_new(); + tcg_gen_setcond_i32(c.tcond, tmp, c.v1, c.v2); + free_cond(&c); + reg = DREG(insn, 0); - tcg_gen_andi_i32(reg, reg, 0xffffff00); - /* This is safe because we modify the reg directly, with no other values - live. */ - gen_jmpcc(s, cond ^ 1, l1); - tcg_gen_ori_i32(reg, reg, 0xff); - gen_set_label(l1); + tcg_gen_neg_i32(tmp, tmp); + tcg_gen_deposit_i32(reg, reg, tmp, 0, 8); + tcg_temp_free(tmp); } /* Force a TB lookup after an instruction that changes the CPU state. */ -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 08/11] target-m68k: Optimize some comparisons 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (6 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 07/11] target-m68k: Use setcond for scc Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 09/11] target-m68k: Optimize gen_flush_flags Richard Henderson ` (3 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/translate.c | 108 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 6 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 28c3e1e..6f60c6f 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -793,10 +793,43 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) { TCGv tmp, tmp2; TCGCond tcond; + CCOp op = s->cc_op; - /* TODO: Optimize compare/branch pairs rather than always flushing - flag state to CC_OP_FLAGS. */ - gen_flush_flags(s); + /* The CC_OP_CMP form can handle most normal comparisons directly. */ + if (op == CC_OP_CMP) { + c->g1 = c->g2 = 1; + c->v1 = QREG_CC_N; + c->v2 = QREG_CC_V; + switch (cond) { + case 2: /* HI */ + case 3: /* LS */ + tcond = TCG_COND_LEU; + goto done; + case 4: /* CC */ + case 5: /* CS */ + tcond = TCG_COND_LTU; + goto done; + case 6: /* NE */ + case 7: /* EQ */ + tcond = TCG_COND_EQ; + goto done; + case 10: /* PL */ + case 11: /* MI */ + c->g1 = c->g2 = 0; + c->v2 = tcg_const_i32(0); + c->v1 = tmp = tcg_temp_new(); + tcg_gen_sub_i32(tmp, QREG_CC_N, QREG_CC_V); + /* fallthru */ + case 12: /* GE */ + case 13: /* LT */ + tcond = TCG_COND_LT; + goto done; + case 14: /* GT */ + case 15: /* LE */ + tcond = TCG_COND_LE; + goto done; + } + } c->g1 = 1; c->g2 = 0; @@ -807,7 +840,71 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) case 1: /* F */ c->v1 = c->v2; tcond = TCG_COND_NEVER; + goto done; + case 14: /* GT (!(Z || (N ^ V))) */ + case 15: /* LE (Z || (N ^ V)) */ + /* Logic operations clear V, which simplifies LE to (Z || N), + and since Z and N are co-located, this becomes a normal + comparison vs N. */ + if (op == CC_OP_LOGIC) { + c->v1 = QREG_CC_N; + tcond = TCG_COND_LE; + goto done; + } + break; + case 12: /* GE (!(N ^ V)) */ + case 13: /* LT (N ^ V) */ + /* Logic operations clear V, which simplifies this to N. */ + if (op != CC_OP_LOGIC) { + break; + } + /* fallthru */ + case 10: /* PL (!N) */ + case 11: /* MI (N) */ + /* Several cases represent N normally. */ + if (op == CC_OP_ADD || op == CC_OP_SUB || op == CC_OP_LOGIC) { + c->v1 = QREG_CC_N; + tcond = TCG_COND_LT; + goto done; + } + break; + case 6: /* NE (!Z) */ + case 7: /* EQ (Z) */ + /* Some cases fold Z into N. */ + if (op == CC_OP_ADD || op == CC_OP_SUB || op == CC_OP_LOGIC) { + tcond = TCG_COND_EQ; + c->v1 = QREG_CC_N; + goto done; + } break; + case 4: /* CC (!C) */ + case 5: /* CS (C) */ + /* Some cases fold C into X. */ + if (op == CC_OP_ADD || op == CC_OP_SUB) { + tcond = TCG_COND_NE; + c->v1 = QREG_CC_X; + goto done; + } + /* fallthru */ + case 8: /* VC (!V) */ + case 9: /* VS (V) */ + /* Logic operations clear V and C. */ + if (op == CC_OP_LOGIC) { + tcond = TCG_COND_NEVER; + c->v2 = c->v1; + } + break; + } + + /* Otherwise, flush flag state to CC_OP_FLAGS. */ + gen_flush_flags(s); + + switch (cond) { + case 0: /* T */ + case 1: /* F */ + default: + /* Invalid, or handled above. */ + abort(); case 2: /* HI (!C && !Z) -> !(C || Z)*/ case 3: /* LS (C || Z) */ c->v1 = tmp = tcg_temp_new(); @@ -855,10 +952,9 @@ static void gen_cc_cond(DisasCompare *c, DisasContext *s, int cond) tcg_temp_free(tmp2); tcond = TCG_COND_LT; break; - default: - /* Should ever happen. */ - abort(); } + + done: if ((cond & 1) == 0) { tcond = tcg_invert_cond(tcond); } -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 09/11] target-m68k: Optimize gen_flush_flags 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (7 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 08/11] target-m68k: Optimize some comparisons Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 10/11] target-m68k: Inline shifts Richard Henderson ` (2 subsequent siblings) 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg --- target-m68k/translate.c | 56 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 6f60c6f..19097c2 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -461,18 +461,66 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) static void gen_flush_flags(DisasContext *s) { - TCGv tmp; + TCGv t0, t1; switch (s->cc_op) { case CC_OP_FLAGS: return; + + case CC_OP_ADD: + tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + /* Compute signed overflow for addition. */ + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + tcg_gen_sub_i32(t0, QREG_CC_N, QREG_CC_V); + tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V); + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0); + tcg_temp_free(t0); + tcg_gen_andc_i32(QREG_CC_V, t1, QREG_CC_V); + tcg_temp_free(t1); + break; + + case CC_OP_SUB: + tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + /* Compute signed overflow for subtraction. */ + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V); + tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V); + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0); + tcg_temp_free(t0); + tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1); + tcg_temp_free(t1); + break; + + case CC_OP_CMP: + tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_C, QREG_CC_N, QREG_CC_V); + tcg_gen_sub_i32(QREG_CC_Z, QREG_CC_N, QREG_CC_V); + /* Compute signed overflow for subtraction. */ + t0 = tcg_temp_new(); + tcg_gen_xor_i32(t0, QREG_CC_Z, QREG_CC_N); + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, QREG_CC_N); + tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t0); + tcg_temp_free(t0); + tcg_gen_mov_i32(QREG_CC_N, QREG_CC_Z); + break; + + case CC_OP_LOGIC: + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_movi_i32(QREG_CC_C, 0); + tcg_gen_movi_i32(QREG_CC_V, 0); + break; + case CC_OP_DYNAMIC: gen_helper_flush_flags(cpu_env, QREG_CC_OP); break; + default: - tmp = tcg_const_i32(s->cc_op); - gen_helper_flush_flags(cpu_env, tmp); - tcg_temp_free(tmp); + t0 = tcg_const_i32(s->cc_op); + gen_helper_flush_flags(cpu_env, t0); + tcg_temp_free(t0); break; } -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 10/11] target-m68k: Inline shifts 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (8 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 09/11] target-m68k: Optimize gen_flush_flags Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 11/11] target-m68k: Inline addx, subx, negx Richard Henderson 2015-08-14 15:37 ` [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Laurent Vivier 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/helper.c | 52 --------------------------- target-m68k/helper.h | 3 -- target-m68k/translate.c | 94 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 72 insertions(+), 77 deletions(-) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index ff7e481..6bd80a5 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -322,58 +322,6 @@ void HELPER(set_sr)(CPUM68KState *env, uint32_t val) m68k_switch_sp(env); } -uint32_t HELPER(shl_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t result; - - shift &= 63; - result = (uint64_t)val << shift; - - env->cc_c = (result >> 32) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = 0; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - -uint32_t HELPER(shr_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t temp; - uint32_t result; - - shift &= 63; - temp = (uint64_t)val << 32 >> shift; - result = temp >> 32; - - env->cc_c = (temp >> 31) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = 0; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - -uint32_t HELPER(sar_cc)(CPUM68KState *env, uint32_t val, uint32_t shift) -{ - uint64_t temp; - uint32_t result; - - shift &= 63; - temp = (int64_t)val << 32 >> shift; - result = temp >> 32; - - env->cc_c = (temp >> 31) & 1; - env->cc_n = result; - env->cc_z = result; - env->cc_v = result ^ val; - env->cc_x = shift ? env->cc_c : env->cc_x; - - return result; -} - /* FPU helpers. */ uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val) { diff --git a/target-m68k/helper.h b/target-m68k/helper.h index c868148..9985f9b 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -5,9 +5,6 @@ DEF_HELPER_2(divu, void, env, i32) DEF_HELPER_2(divs, void, env, i32) DEF_HELPER_3(addx_cc, i32, env, i32, i32) DEF_HELPER_3(subx_cc, i32, env, i32, i32) -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(movec, void, env, i32, i32) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 19097c2..a536054 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2060,48 +2060,98 @@ DISAS_INSN(addx) gen_helper_addx_cc(reg, cpu_env, reg, src); } -/* TODO: This could be implemented without helper functions. */ DISAS_INSN(shift_im) { - TCGv reg; - int tmp; - TCGv shift; + TCGv reg = DREG(insn, 0); + int count = (insn >> 9) & 7; + int arith = insn & 8; - set_cc_op(s, CC_OP_FLAGS); + if (count == 0) { + count = 8; + } - reg = DREG(insn, 0); - tmp = (insn >> 9) & 7; - if (tmp == 0) - tmp = 8; - shift = tcg_const_i32(tmp); - /* No need to flush flags becuse we know we will set C flag. */ if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + tcg_gen_shri_i32(QREG_CC_C, reg, 31 - count); + tcg_gen_shli_i32(QREG_CC_N, reg, count); } else { - if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); + tcg_gen_shri_i32(QREG_CC_C, reg, count - 1); + if (arith) { + tcg_gen_sari_i32(QREG_CC_N, reg, count); } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); + tcg_gen_shri_i32(QREG_CC_N, reg, count); } } + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_X, QREG_CC_C); + + /* Note that ColdFire always clears V, while M68000 sets it for + a change in the sign bit. */ + if (arith && m68k_feature(s->env, M68K_FEATURE_M68000)) { + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, reg); + } else { + tcg_gen_movi_i32(QREG_CC_V, 0); + } + + tcg_gen_mov_i32(reg, QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(shift_reg) { - TCGv reg; - TCGv shift; + TCGv reg, s32; + TCGv_i64 t64, s64; + int arith = insn & 8; reg = DREG(insn, 0); - shift = DREG(insn, 9); + t64 = tcg_temp_new_i64(); + s64 = tcg_temp_new_i64(); + s32 = tcg_temp_new(); + + /* Note that m68k truncates the shift count modulo 64, not 32. + In addition, a 64-bit shift makes it easy to find "the last + bit shifted out", for the carry flag. */ + tcg_gen_andi_i32(s32, DREG(insn, 9), 63); + tcg_gen_extu_i32_i64(s64, s32); + + /* Non-arithmetic shift clears V. Use it as a source zero here. */ + tcg_gen_movi_i32(QREG_CC_V, 0); + if (insn & 0x100) { - gen_helper_shl_cc(reg, cpu_env, reg, shift); + tcg_gen_extu_i32_i64(t64, reg); + tcg_gen_shl_i64(t64, t64, s64); + tcg_temp_free_i64(s64); + tcg_gen_extr_i64_i32(QREG_CC_N, QREG_CC_C, t64); + tcg_temp_free_i64(t64); + tcg_gen_andi_i32(QREG_CC_C, QREG_CC_C, 1); } else { - if (insn & 8) { - gen_helper_shr_cc(reg, cpu_env, reg, shift); + tcg_gen_extu_i32_i64(t64, reg); + tcg_gen_shli_i64(t64, t64, 32); + if (arith) { + tcg_gen_sar_i64(t64, t64, s64); } else { - gen_helper_sar_cc(reg, cpu_env, reg, shift); + tcg_gen_shr_i64(t64, t64, s64); } + tcg_temp_free_i64(s64); + tcg_gen_extr_i64_i32(QREG_CC_C, QREG_CC_N, t64); + tcg_temp_free_i64(t64); + tcg_gen_shri_i32(QREG_CC_C, QREG_CC_C, 31); } + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + + /* Note that X = C, but only if the shift count was non-zero. */ + tcg_gen_movcond_i32(TCG_COND_NE, QREG_CC_X, s32, QREG_CC_V, + QREG_CC_C, QREG_CC_X); + tcg_temp_free(s32); + + /* Note that ColdFire always clears V (which we have done above), + while M68000 sets it for a change in the sign bit. */ + if (arith && m68k_feature(s->env, M68K_FEATURE_M68000)) { + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, reg); + } + + /* Write back the result. */ + tcg_gen_mov_i32(reg, QREG_CC_N); set_cc_op(s, CC_OP_FLAGS); } -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 11/11] target-m68k: Inline addx, subx, negx 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (9 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 10/11] target-m68k: Inline shifts Richard Henderson @ 2015-08-14 14:59 ` Richard Henderson 2015-08-14 15:37 ` [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Laurent Vivier 11 siblings, 0 replies; 16+ messages in thread From: Richard Henderson @ 2015-08-14 14:59 UTC (permalink / raw) To: qemu-devel; +Cc: peter.maydell, schwab, laurent, gerg Signed-off-by: Richard Henderson <rth@twiddle.net> --- target-m68k/helper.c | 40 ----------------------------- target-m68k/helper.h | 2 -- target-m68k/translate.c | 67 +++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 6bd80a5..519eef3 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -275,46 +275,6 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v) return val; } -uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) -{ - uint32_t res, new_x; - - if (env->cc_x) { - new_x = (op1 <= op2); - res = op1 - (op2 + 1); - } else { - new_x = (op1 < op2); - res = op1 - op2; - } - env->cc_x = new_x; - env->cc_c = new_x; - env->cc_n = res; - env->cc_z |= res; /* !Z is sticky */ - env->cc_v = (res ^ op1) & (op1 ^ op2); - - return res; -} - -uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) -{ - uint32_t res, new_x; - - if (env->cc_x) { - res = op1 + op2 + 1; - new_x = (res <= op2); - } else { - res = op1 + op2; - new_x = (res < op2); - } - env->cc_x = new_x; - env->cc_c = new_x; - env->cc_n = res; - env->cc_z |= res; /* !Z is sticky. */ - env->cc_v = (res ^ op1) & ~(op1 ^ op2); - - return res; -} - void HELPER(set_sr)(CPUM68KState *env, uint32_t val) { env->sr = val & 0xffe0; diff --git a/target-m68k/helper.h b/target-m68k/helper.h index 9985f9b..aae01f9 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -3,8 +3,6 @@ DEF_HELPER_1(ff1, i32, i32) DEF_HELPER_FLAGS_2(sats, TCG_CALL_NO_RWG_SE, i32, i32, i32) DEF_HELPER_2(divu, void, env, i32) DEF_HELPER_2(divs, void, env, i32) -DEF_HELPER_3(addx_cc, i32, env, i32, i32) -DEF_HELPER_3(subx_cc, i32, env, i32, i32) DEF_HELPER_2(set_sr, void, env, i32) DEF_HELPER_3(movec, void, env, i32, i32) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index a536054..33d6747 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1527,11 +1527,27 @@ DISAS_INSN(move) DISAS_INSN(negx) { - TCGv reg; + TCGv reg, z; - gen_flush_flags(s); reg = DREG(insn, 0); - gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg); + + /* Perform subtraction with borrow. */ + z = tcg_const_i32(0); + tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, reg, z, QREG_CC_X, z); + tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, z, z, QREG_CC_N, QREG_CC_X); + tcg_temp_free(z); + tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1); + + /* Compute signed-overflow for negation. The normal formula for + subtraction is (res ^ src1) & (src1 ^ src2), but with src1==0 + this simplies to res & src2. */ + tcg_gen_and_i32(QREG_CC_V, QREG_CC_N, reg); + + /* Copy the rest of the results into place. */ + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); + tcg_gen_mov_i32(reg, QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(lea) @@ -1951,13 +1967,28 @@ DISAS_INSN(suba) DISAS_INSN(subx) { - TCGv reg; - TCGv src; + TCGv reg, src, z; - gen_flush_flags(s); reg = DREG(insn, 9); src = DREG(insn, 0); - gen_helper_subx_cc(reg, cpu_env, reg, src); + + /* Perform subtract with borrow. */ + z = tcg_const_i32(0); + tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, src, z, QREG_CC_X, z); + tcg_gen_sub2_i32(QREG_CC_N, QREG_CC_X, reg, z, QREG_CC_N, QREG_CC_X); + tcg_temp_free(z); + tcg_gen_andi_i32(QREG_CC_X, QREG_CC_X, 1); + + /* Compute signed-overflow for subtraction. */ + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, reg); + tcg_gen_xor_i32(QREG_CC_Z, reg, src); + tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, QREG_CC_Z); + + /* Copy the rest of the results into place. */ + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); + tcg_gen_mov_i32(reg, QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(mov3q) @@ -2051,13 +2082,27 @@ DISAS_INSN(adda) DISAS_INSN(addx) { - TCGv reg; - TCGv src; + TCGv reg, src, z; - gen_flush_flags(s); reg = DREG(insn, 9); src = DREG(insn, 0); - gen_helper_addx_cc(reg, cpu_env, reg, src); + + /* Perform addition with carry. */ + z = tcg_const_i32(0); + tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_X, z, reg, z); + tcg_gen_add2_i32(QREG_CC_N, QREG_CC_X, QREG_CC_N, QREG_CC_X, src, z); + tcg_temp_free(z); + + /* Compute signed-overflow for addition. */ + tcg_gen_xor_i32(QREG_CC_V, QREG_CC_N, reg); + tcg_gen_xor_i32(QREG_CC_Z, reg, src); + tcg_gen_andc_i32(QREG_CC_V, QREG_CC_V, QREG_CC_Z); + + /* Copy the rest of the results into place. */ + tcg_gen_mov_i32(QREG_CC_Z, QREG_CC_N); + tcg_gen_mov_i32(QREG_CC_C, QREG_CC_X); + tcg_gen_mov_i32(reg, QREG_CC_N); + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(shift_im) -- 2.4.3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson ` (10 preceding siblings ...) 2015-08-14 14:59 ` [Qemu-devel] [PATCH 11/11] target-m68k: Inline addx, subx, negx Richard Henderson @ 2015-08-14 15:37 ` Laurent Vivier 11 siblings, 0 replies; 16+ messages in thread From: Laurent Vivier @ 2015-08-14 15:37 UTC (permalink / raw) To: Richard Henderson, qemu-devel; +Cc: peter.maydell, schwab, gerg Le 14/08/2015 16:59, Richard Henderson a écrit : > As promised a couple of days ago, with the addition of CC_OP_CMP, > which wasn't in the text of my proposal the other day. From the > looks of the generated code, I believe this is ideal. > > The following is based on Laurent's 8/30 Update cpu flags management. > > FWIW, there's something in the last patch here that breaks the > coldfire kernel I've been testing (it may even be a bug in tcg; > the problem only appears well into the boot process). But I'm > about to go away for the weekend and still wanted to include it > to show what can be done. > > For convenience, the complete tree pushed to > > git://github.com/rth7680/qemu.git tgt-m68k > Thanks, I'll try to review and test this this week-end. Laurent ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2015-08-15 6:25 UTC | newest] Thread overview: 16+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-08-14 14:59 [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 01/11] target-m68k: Print flags properly Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 02/11] target-m68k: Some fixes to SR and flags management Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 03/11] target-m68k: Remove incorrect clearing of cc_x Richard Henderson 2015-08-14 17:04 ` Andreas Schwab 2015-08-14 23:10 ` Richard Henderson 2015-08-15 6:25 ` Andreas Schwab 2015-08-14 14:59 ` [Qemu-devel] [PATCH 04/11] target-m68k: Replace helper_xflag_lt with setcond Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 05/11] target-m68k: Reorg flags handling Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 06/11] target-m68k: Introduce DisasCompare Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 07/11] target-m68k: Use setcond for scc Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 08/11] target-m68k: Optimize some comparisons Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 09/11] target-m68k: Optimize gen_flush_flags Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 10/11] target-m68k: Inline shifts Richard Henderson 2015-08-14 14:59 ` [Qemu-devel] [PATCH 11/11] target-m68k: Inline addx, subx, negx Richard Henderson 2015-08-14 15:37 ` [Qemu-devel] [PATCH 00/11] Proposed format for m68k flags Laurent Vivier
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).