From a1ff19302007986fa081738e88905a715bd68e2e Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 6 Dec 2015 19:01:47 +0100 Subject: [PATCH 01/23] target-m68k: fix DEBUG_DISPATCH Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index ecd5e5c8fd..deb5a583a1 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -170,7 +170,7 @@ typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); uint16_t insn) \ { \ qemu_log("Dispatch " #name "\n"); \ - real_disas_##name(s, env, insn); \ + real_disas_##name(env, s, insn); \ } \ static void real_disas_##name(CPUM68KState *env, DisasContext *s, \ uint16_t insn) From b208525797b031c1be4121553e21746686318a38 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Wed, 3 Feb 2016 10:22:35 +0100 Subject: [PATCH 02/23] target-m68k: Build the opcode table only once to avoid multithreading issues Signed-off-by: John Paul Adrian Glaubitz Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index deb5a583a1..eecb32b4db 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2841,6 +2841,11 @@ register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask) Later insn override earlier ones. */ void register_m68k_insns (CPUM68KState *env) { + /* Build the opcode table only once to avoid + multithreading issues. */ + if (opcode_table[0] != NULL) { + return; + } #define INSN(name, opcode, mask, feature) do { \ if (m68k_feature(env, M68K_FEATURE_##feature)) \ register_opcode(disas_##name, 0x##opcode, 0x##mask); \ From f076803bbf6ad1618f493f543faff97f3dd0c970 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Tue, 23 Jun 2015 20:55:08 +0200 Subject: [PATCH 03/23] target-m68k: define m680x0 CPUs and features This patch defines height new features: - M68K_FEATURE_SCALED_INDEX, scaled address index register - M68K_FEATURE_LONG_MULDIV, 32bit multiply/divide - M68K_FEATURE_QUAD_MULDIV, 64bit multiply/divide - M68K_FEATURE_BCCL, long conditional branches - M68K_FEATURE_BITFIELD, bit field instructions - M68K_FEATURE_FPU, FPU instructions - M68K_FEATURE_CAS, cas instruction - M68K_FEATURE_BKPT, bkpt instruction Original patch from Andreas Schwab Signed-off-by: Laurent Vivier --- target-m68k/cpu.c | 56 +++++++++++++++++++ target-m68k/cpu.h | 11 +++- target-m68k/translate.c | 120 +++++++++++++++++++++++++--------------- 3 files changed, 142 insertions(+), 45 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 17e4be2934..800e8f0e58 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -98,6 +98,57 @@ static void m5206_cpu_initfn(Object *obj) m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); } +static void m68000_cpu_initfn(Object *obj) +{ + M68kCPU *cpu = M68K_CPU(obj); + CPUM68KState *env = &cpu->env; + + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); +} + +static void m68020_cpu_initfn(Object *obj) +{ + M68kCPU *cpu = M68K_CPU(obj); + CPUM68KState *env = &cpu->env; + + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + m68k_set_feature(env, M68K_FEATURE_QUAD_MULDIV); + m68k_set_feature(env, M68K_FEATURE_BRAL); + m68k_set_feature(env, M68K_FEATURE_BCCL); + m68k_set_feature(env, M68K_FEATURE_BITFIELD); + m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); + m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV); + m68k_set_feature(env, M68K_FEATURE_FPU); + m68k_set_feature(env, M68K_FEATURE_CAS); + m68k_set_feature(env, M68K_FEATURE_BKPT); +} +#define m68030_cpu_initfn m68020_cpu_initfn +#define m68040_cpu_initfn m68020_cpu_initfn + +static void m68060_cpu_initfn(Object *obj) +{ + M68kCPU *cpu = M68K_CPU(obj); + CPUM68KState *env = &cpu->env; + + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + m68k_set_feature(env, M68K_FEATURE_BRAL); + m68k_set_feature(env, M68K_FEATURE_BCCL); + m68k_set_feature(env, M68K_FEATURE_BITFIELD); + m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); + m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV); + m68k_set_feature(env, M68K_FEATURE_FPU); + m68k_set_feature(env, M68K_FEATURE_CAS); + m68k_set_feature(env, M68K_FEATURE_BKPT); +} + static void m5208_cpu_initfn(Object *obj) { M68kCPU *cpu = M68K_CPU(obj); @@ -148,6 +199,11 @@ typedef struct M68kCPUInfo { } M68kCPUInfo; static const M68kCPUInfo m68k_cpus[] = { + { .name = "m68000", .instance_init = m68000_cpu_initfn }, + { .name = "m68020", .instance_init = m68020_cpu_initfn }, + { .name = "m68030", .instance_init = m68030_cpu_initfn }, + { .name = "m68040", .instance_init = m68040_cpu_initfn }, + { .name = "m68060", .instance_init = m68060_cpu_initfn }, { .name = "m5206", .instance_init = m5206_cpu_initfn }, { .name = "m5208", .instance_init = m5208_cpu_initfn }, { .name = "cfv4e", .instance_init = cfv4e_cpu_initfn }, diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 471f490dc1..8333e1e3f9 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -215,6 +215,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr); ISA revisions mentioned. */ enum m68k_features { + M68K_FEATURE_M68000, M68K_FEATURE_CF_ISA_A, M68K_FEATURE_CF_ISA_B, /* (ISA B or C). */ M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */ @@ -225,7 +226,15 @@ enum m68k_features { M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate). */ M68K_FEATURE_USP, /* User Stack Pointer. (ISA A+, B or C). */ M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ - M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ + M68K_FEATURE_WORD_INDEX, /* word sized address index registers. */ + M68K_FEATURE_SCALED_INDEX, /* scaled address index registers. */ + M68K_FEATURE_LONG_MULDIV, /* 32 bit multiply/divide. */ + M68K_FEATURE_QUAD_MULDIV, /* 64 bit multiply/divide. */ + M68K_FEATURE_BCCL, /* Long conditional branches. */ + M68K_FEATURE_BITFIELD, /* Bit field insns. */ + M68K_FEATURE_FPU, + M68K_FEATURE_CAS, + M68K_FEATURE_BKPT, }; static inline int m68k_feature(CPUM68KState *env, int feature) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index eecb32b4db..3773fb41dc 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2846,90 +2846,118 @@ void register_m68k_insns (CPUM68KState *env) if (opcode_table[0] != NULL) { return; } + + /* use BASE() for instruction available + * for CF_ISA_A and M68000. + */ +#define BASE(name, opcode, mask) \ + register_opcode(disas_##name, 0x##opcode, 0x##mask) #define INSN(name, opcode, mask, feature) do { \ if (m68k_feature(env, M68K_FEATURE_##feature)) \ - register_opcode(disas_##name, 0x##opcode, 0x##mask); \ + BASE(name, opcode, mask); \ } while(0) - INSN(undef, 0000, 0000, CF_ISA_A); + BASE(undef, 0000, 0000); INSN(arith_im, 0080, fff8, CF_ISA_A); + INSN(arith_im, 0000, ff00, M68000); + INSN(undef, 00c0, ffc0, M68000); INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); - INSN(bitop_reg, 0100, f1c0, CF_ISA_A); - INSN(bitop_reg, 0140, f1c0, CF_ISA_A); - INSN(bitop_reg, 0180, f1c0, CF_ISA_A); - INSN(bitop_reg, 01c0, f1c0, CF_ISA_A); + BASE(bitop_reg, 0100, f1c0); + BASE(bitop_reg, 0140, f1c0); + BASE(bitop_reg, 0180, f1c0); + BASE(bitop_reg, 01c0, f1c0); INSN(arith_im, 0280, fff8, CF_ISA_A); + INSN(arith_im, 0200, ff00, M68000); + INSN(undef, 02c0, ffc0, M68000); INSN(byterev, 02c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0480, fff8, CF_ISA_A); + INSN(arith_im, 0400, ff00, M68000); + INSN(undef, 04c0, ffc0, M68000); + INSN(arith_im, 0600, ff00, M68000); + INSN(undef, 06c0, ffc0, M68000); INSN(ff1, 04c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0680, fff8, CF_ISA_A); - INSN(bitop_im, 0800, ffc0, CF_ISA_A); - INSN(bitop_im, 0840, ffc0, CF_ISA_A); - INSN(bitop_im, 0880, ffc0, CF_ISA_A); - INSN(bitop_im, 08c0, ffc0, CF_ISA_A); - INSN(arith_im, 0a80, fff8, CF_ISA_A); INSN(arith_im, 0c00, ff38, CF_ISA_A); - INSN(move, 1000, f000, CF_ISA_A); - INSN(move, 2000, f000, CF_ISA_A); - INSN(move, 3000, f000, CF_ISA_A); + INSN(arith_im, 0c00, ff00, M68000); + BASE(bitop_im, 0800, ffc0); + BASE(bitop_im, 0840, ffc0); + BASE(bitop_im, 0880, ffc0); + BASE(bitop_im, 08c0, ffc0); + INSN(arith_im, 0a80, fff8, CF_ISA_A); + INSN(arith_im, 0a00, ff00, M68000); + BASE(move, 1000, f000); + BASE(move, 2000, f000); + BASE(move, 3000, f000); INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); INSN(move_from_sr, 40c0, fff8, CF_ISA_A); - INSN(lea, 41c0, f1c0, CF_ISA_A); - INSN(clr, 4200, ff00, CF_ISA_A); - INSN(undef, 42c0, ffc0, CF_ISA_A); + INSN(move_from_sr, 40c0, ffc0, M68000); + BASE(lea, 41c0, f1c0); + BASE(clr, 4200, ff00); + BASE(undef, 42c0, ffc0); INSN(move_from_ccr, 42c0, fff8, CF_ISA_A); INSN(neg, 4480, fff8, CF_ISA_A); - INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A); + INSN(neg, 4400, ff00, M68000); + INSN(undef, 44c0, ffc0, M68000); + BASE(move_to_ccr, 44c0, ffc0); INSN(not, 4680, fff8, CF_ISA_A); + INSN(not, 4600, ff00, M68000); + INSN(undef, 46c0, ffc0, M68000); INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); - INSN(pea, 4840, ffc0, CF_ISA_A); - INSN(swap, 4840, fff8, CF_ISA_A); - INSN(movem, 48c0, fbc0, CF_ISA_A); - INSN(ext, 4880, fff8, CF_ISA_A); - INSN(ext, 48c0, fff8, CF_ISA_A); - INSN(ext, 49c0, fff8, CF_ISA_A); - INSN(tst, 4a00, ff00, CF_ISA_A); + BASE(pea, 4840, ffc0); + BASE(swap, 4840, fff8); + BASE(movem, 48c0, fbc0); + BASE(ext, 4880, fff8); + BASE(ext, 48c0, fff8); + BASE(ext, 49c0, fff8); + BASE(tst, 4a00, ff00); INSN(tas, 4ac0, ffc0, CF_ISA_B); + INSN(tas, 4ac0, ffc0, M68000); INSN(halt, 4ac8, ffff, CF_ISA_A); INSN(pulse, 4acc, ffff, CF_ISA_A); - INSN(illegal, 4afc, ffff, CF_ISA_A); + BASE(illegal, 4afc, ffff); INSN(mull, 4c00, ffc0, CF_ISA_A); + INSN(mull, 4c00, ffc0, LONG_MULDIV); INSN(divl, 4c40, ffc0, CF_ISA_A); + INSN(divl, 4c40, ffc0, LONG_MULDIV); INSN(sats, 4c80, fff8, CF_ISA_B); - INSN(trap, 4e40, fff0, CF_ISA_A); - INSN(link, 4e50, fff8, CF_ISA_A); - INSN(unlk, 4e58, fff8, CF_ISA_A); + BASE(trap, 4e40, fff0); + BASE(link, 4e50, fff8); + BASE(unlk, 4e58, fff8); INSN(move_to_usp, 4e60, fff8, USP); INSN(move_from_usp, 4e68, fff8, USP); - INSN(nop, 4e71, ffff, CF_ISA_A); - INSN(stop, 4e72, ffff, CF_ISA_A); - INSN(rte, 4e73, ffff, CF_ISA_A); - INSN(rts, 4e75, ffff, CF_ISA_A); + BASE(nop, 4e71, ffff); + BASE(stop, 4e72, ffff); + BASE(rte, 4e73, ffff); + BASE(rts, 4e75, ffff); INSN(movec, 4e7b, ffff, CF_ISA_A); - INSN(jump, 4e80, ffc0, CF_ISA_A); + BASE(jump, 4e80, ffc0); INSN(jump, 4ec0, ffc0, CF_ISA_A); INSN(addsubq, 5180, f1c0, CF_ISA_A); + INSN(jump, 4ec0, ffc0, M68000); + INSN(addsubq, 5000, f080, M68000); + INSN(addsubq, 5080, f0c0, M68000); INSN(scc, 50c0, f0f8, CF_ISA_A); INSN(addsubq, 5080, f1c0, CF_ISA_A); INSN(tpf, 51f8, fff8, CF_ISA_A); /* Branch instructions. */ - INSN(branch, 6000, f000, CF_ISA_A); + BASE(branch, 6000, f000); /* Disable long branch instructions, then add back the ones we want. */ - INSN(undef, 60ff, f0ff, CF_ISA_A); /* All long branches. */ + BASE(undef, 60ff, f0ff); /* All long branches. */ INSN(branch, 60ff, f0ff, CF_ISA_B); INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */ INSN(branch, 60ff, ffff, BRAL); + INSN(branch, 60ff, f0ff, BCCL); - INSN(moveq, 7000, f100, CF_ISA_A); + BASE(moveq, 7000, f100); INSN(mvzs, 7100, f100, CF_ISA_B); - INSN(or, 8000, f000, CF_ISA_A); - INSN(divw, 80c0, f0c0, CF_ISA_A); - INSN(addsub, 9000, f000, CF_ISA_A); + BASE(or, 8000, f000); + BASE(divw, 80c0, f0c0); + BASE(addsub, 9000, f000); INSN(subx, 9180, f1f8, CF_ISA_A); INSN(suba, 91c0, f1c0, CF_ISA_A); - INSN(undef_mac, a000, f000, CF_ISA_A); + BASE(undef_mac, a000, f000); INSN(mac, a000, f100, CF_EMAC); INSN(from_mac, a180, f9b0, CF_EMAC); INSN(move_mac, a110, f9fc, CF_EMAC); @@ -2948,12 +2976,16 @@ void register_m68k_insns (CPUM68KState *env) INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */ INSN(cmp, b080, f1c0, CF_ISA_A); INSN(cmpa, b1c0, f1c0, CF_ISA_A); + INSN(cmp, b000, f100, M68000); + INSN(eor, b100, f100, M68000); + INSN(cmpa, b0c0, f0c0, M68000); INSN(eor, b180, f1c0, CF_ISA_A); - INSN(and, c000, f000, CF_ISA_A); - INSN(mulw, c0c0, f0c0, CF_ISA_A); - INSN(addsub, d000, f000, CF_ISA_A); + BASE(and, c000, f000); + BASE(mulw, c0c0, f0c0); + BASE(addsub, d000, f000); INSN(addx, d180, f1f8, CF_ISA_A); INSN(adda, d1c0, f1c0, CF_ISA_A); + INSN(adda, d0c0, f0c0, M68000); INSN(shift_im, e080, f0f0, CF_ISA_A); INSN(shift_reg, e0a0, f0f0, CF_ISA_A); INSN(undef_fpu, f000, f000, CF_ISA_A); From d8633620a112296fcf6a6ae9a1cbba614c0ca502 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 24 Jun 2015 02:35:06 +0200 Subject: [PATCH 04/23] target-m68k: manage scaled index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scaled index is not supported by 68000, 68008, and 68010. EA = (bd + PC) + Xn.SIZE*SCALE + od Ignore it: M68000 FAMILY PROGRAMMER’S REFERENCE MANUAL 2.4 BRIEF EXTENSION WORD FORMAT COMPATIBILITY "If the MC68000 were to execute an instruction that encoded a scaling factor, the scaling factor would be ignored and would not access the desired memory address. The earlier microprocessors do not recognize the brief extension word formats implemented by newer processors. Although they can detect illegal instructions, they do not decode invalid encodings of the brief extension word formats as exceptions." Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 3773fb41dc..d73350ce5b 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -315,6 +315,11 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) return NULL_QREG; + if (m68k_feature(s->env, M68K_FEATURE_M68000) && + !m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) { + ext &= ~(3 << 9); + } + if (ext & 0x100) { /* full extension word format */ if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) From 28b68cd79ef01e8b1f5bd26718cd8c09a12c625f Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Wed, 24 Jun 2015 02:28:59 +0200 Subject: [PATCH 05/23] target-m68k: introduce read_imXX() functions Read a 8, 16 or 32bit immediat constant. An immediate constant is stored in the instruction opcode and can be in one or two extension words. Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 91 +++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 50 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index d73350ce5b..a8ff5de252 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -268,14 +268,27 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, } } +/* Read a 16-bit immediate constant */ +static inline uint16_t read_im16(CPUM68KState *env, DisasContext *s) +{ + uint16_t im; + im = cpu_lduw_code(env, s->pc); + s->pc += 2; + return im; +} + +/* Read an 8-bit immediate constant */ +static inline uint8_t read_im8(CPUM68KState *env, DisasContext *s) +{ + return read_im16(env, s); +} + /* Read a 32-bit immediate constant. */ static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s) { uint32_t im; - im = ((uint32_t)cpu_lduw_code(env, s->pc)) << 16; - s->pc += 2; - im |= cpu_lduw_code(env, s->pc); - s->pc += 2; + im = read_im16(env, s) << 16; + im |= 0xffff & read_im16(env, s); return im; } @@ -309,8 +322,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) uint32_t bd, od; offset = s->pc; - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) return NULL_QREG; @@ -328,8 +340,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) if ((ext & 0x30) > 0x10) { /* base displacement */ if ((ext & 0x30) == 0x20) { - bd = (int16_t)cpu_lduw_code(env, s->pc); - s->pc += 2; + bd = (int16_t)read_im16(env, s); } else { bd = read_im32(env, s); } @@ -377,8 +388,7 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) if ((ext & 3) > 1) { /* outer displacement */ if ((ext & 3) == 2) { - od = (int16_t)cpu_lduw_code(env, s->pc); - s->pc += 2; + od = (int16_t)read_im16(env, s); } else { od = read_im32(env, s); } @@ -530,8 +540,7 @@ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, case 5: /* Indirect displacement. */ reg = AREG(insn, 0); tmp = tcg_temp_new(); - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); tcg_gen_addi_i32(tmp, reg, (int16_t)ext); return tmp; case 6: /* Indirect index + displacement. */ @@ -540,16 +549,14 @@ static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, case 7: /* Other */ switch (insn & 7) { case 0: /* Absolute short. */ - offset = cpu_ldsw_code(env, s->pc); - s->pc += 2; + offset = (int16_t)read_im16(env, s); return tcg_const_i32(offset); case 1: /* Absolute long. */ offset = read_im32(env, s); return tcg_const_i32(offset); case 2: /* pc displacement */ offset = s->pc; - offset += cpu_ldsw_code(env, s->pc); - s->pc += 2; + offset += (int16_t)read_im16(env, s); return tcg_const_i32(offset); case 3: /* pc index+displacement. */ return gen_lea_indexed(env, s, NULL_QREG); @@ -656,19 +663,17 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, switch (opsize) { case OS_BYTE: if (what == EA_LOADS) { - offset = cpu_ldsb_code(env, s->pc + 1); + offset = (int8_t)read_im8(env, s); } else { - offset = cpu_ldub_code(env, s->pc + 1); + offset = read_im8(env, s); } - s->pc += 2; break; case OS_WORD: if (what == EA_LOADS) { - offset = cpu_ldsw_code(env, s->pc); + offset = (int16_t)read_im16(env, s); } else { - offset = cpu_lduw_code(env, s->pc); + offset = read_im16(env, s); } - s->pc += 2; break; case OS_LONG: offset = read_im32(env, s); @@ -961,8 +966,7 @@ DISAS_INSN(divl) TCGv reg; uint16_t ext; - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if (ext & 0x87f8) { gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); return; @@ -1113,8 +1117,7 @@ DISAS_INSN(movem) TCGv tmp; int is_load; - mask = cpu_lduw_code(env, s->pc); - s->pc += 2; + mask = read_im16(env, s); tmp = gen_lea(env, s, insn, OS_LONG); if (IS_NULL_QREG(tmp)) { gen_addr_fault(s); @@ -1157,8 +1160,7 @@ DISAS_INSN(bitop_im) opsize = OS_LONG; op = (insn >> 6) & 3; - bitnum = cpu_lduw_code(env, s->pc); - s->pc += 2; + bitnum = read_im16(env, s); if (bitnum & 0xff00) { disas_undef(env, s, insn); return; @@ -1411,8 +1413,7 @@ static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, else if ((insn & 0x3f) == 0x3c) { uint16_t val; - val = cpu_lduw_code(env, s->pc); - s->pc += 2; + val = read_im16(env, s); gen_set_sr_im(s, val, ccr_only); } else @@ -1535,8 +1536,7 @@ DISAS_INSN(mull) /* The upper 32 bits of the product are discarded, so muls.l and mulu.l are functionally equivalent. */ - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if (ext & 0x87ff) { gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); return; @@ -1677,8 +1677,7 @@ DISAS_INSN(branch) op = (insn >> 8) & 0xf; offset = (int8_t)insn; if (offset == 0) { - offset = cpu_ldsw_code(env, s->pc); - s->pc += 2; + offset = (int16_t)read_im16(env, s); } else if (offset == -1) { offset = read_im32(env, s); } @@ -1962,14 +1961,12 @@ DISAS_INSN(strldsr) uint32_t addr; addr = s->pc - 2; - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if (ext != 0x46FC) { gen_exception(s, addr, EXCP_UNSUPPORTED); return; } - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if (IS_USER(s) || (ext & SR_S) == 0) { gen_exception(s, addr, EXCP_PRIVILEGE); return; @@ -2036,8 +2033,7 @@ DISAS_INSN(stop) return; } - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); gen_set_sr_im(s, ext, 0); tcg_gen_movi_i32(cpu_halted, 1); @@ -2063,8 +2059,7 @@ DISAS_INSN(movec) return; } - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); if (ext & 0x8000) { reg = AREG(ext, 12); @@ -2130,8 +2125,7 @@ DISAS_INSN(fpu) int set_dest; int opsize; - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); opmode = ext & 0x7f; switch ((ext >> 13) & 7) { case 0: case 2: @@ -2413,8 +2407,7 @@ DISAS_INSN(fbcc) offset = cpu_ldsw_code(env, s->pc); s->pc += 2; if (insn & (1 << 6)) { - offset = (offset << 16) | cpu_lduw_code(env, s->pc); - s->pc += 2; + offset = (offset << 16) | read_im16(env, s); } l1 = gen_new_label(); @@ -2539,8 +2532,7 @@ DISAS_INSN(mac) s->done_mac = 1; } - ext = cpu_lduw_code(env, s->pc); - s->pc += 2; + ext = read_im16(env, s); acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); dual = ((insn & 0x30) != 0 && (ext & 3) != 0); @@ -3011,8 +3003,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) { uint16_t insn; - insn = cpu_lduw_code(env, s->pc); - s->pc += 2; + insn = read_im16(env, s); opcode_table[insn](env, s, insn); } From 4d558f5d580187d594c46b2d449445600d7c7953 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sat, 17 Sep 2011 21:21:07 +0200 Subject: [PATCH 06/23] target-m68k: set disassembler mode to 680x0 or coldfire Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index 800e8f0e58..f925e265b0 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -64,9 +64,14 @@ static void m68k_cpu_reset(CPUState *s) tlb_flush(s, 1); } -static void m68k_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +static void m68k_cpu_disas_set_info(CPUState *s, disassemble_info *info) { + M68kCPU *cpu = M68K_CPU(s); + CPUM68KState *env = &cpu->env; info->print_insn = print_insn_m68k; + if (m68k_feature(env, M68K_FEATURE_M68000)) { + info->mach = bfd_mach_m68040; + } } /* CPU models */ From 7ef25cdd6cee4fa468d6cb913fa064a6689faf7d Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Aug 2015 01:12:46 +0200 Subject: [PATCH 07/23] target-m68k: define operand sizes Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/cpu.h | 8 +++++++ target-m68k/translate.c | 47 +++++++++++++---------------------------- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 8333e1e3f9..133852a3a0 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -30,6 +30,14 @@ #include "cpu-qom.h" #include "fpu/softfloat.h" +#define OS_BYTE 0 +#define OS_WORD 1 +#define OS_LONG 2 +#define OS_SINGLE 3 +#define OS_DOUBLE 4 +#define OS_EXTENDED 5 +#define OS_PACKED 6 + #define MAX_QREGS 32 #define EXCP_ACCESS 2 /* Access (MMU) error. */ diff --git a/target-m68k/translate.c b/target-m68k/translate.c index a8ff5de252..639db766ee 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -154,12 +154,6 @@ typedef struct DisasContext { static void *gen_throws_exception; #define gen_last_qop NULL -#define OS_BYTE 0 -#define OS_WORD 1 -#define OS_LONG 2 -#define OS_SINGLE 4 -#define OS_DOUBLE 5 - typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); #ifdef DEBUG_DISPATCH @@ -453,6 +447,19 @@ static inline int opsize_bytes(int opsize) case OS_LONG: return 4; case OS_SINGLE: return 4; case OS_DOUBLE: return 8; + case OS_EXTENDED: return 12; + case OS_PACKED: return 12; + default: + g_assert_not_reached(); + } +} + +static inline int insn_opsize(int insn) +{ + switch ((insn >> 6) & 3) { + case 0: return OS_BYTE; + case 1: return OS_WORD; + case 2: return OS_LONG; default: g_assert_not_reached(); } @@ -1330,19 +1337,7 @@ DISAS_INSN(clr) { int opsize; - switch ((insn >> 6) & 3) { - case 0: /* clr.b */ - opsize = OS_BYTE; - break; - case 1: /* clr.w */ - opsize = OS_WORD; - break; - case 2: /* clr.l */ - opsize = OS_LONG; - break; - default: - abort(); - } + opsize = insn_opsize(insn); DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL); gen_logic_cc(s, tcg_const_i32(0)); } @@ -1486,19 +1481,7 @@ DISAS_INSN(tst) int opsize; TCGv tmp; - switch ((insn >> 6) & 3) { - case 0: /* tst.b */ - opsize = OS_BYTE; - break; - case 1: /* tst.w */ - opsize = OS_WORD; - break; - case 2: /* tst.l */ - opsize = OS_LONG; - break; - default: - abort(); - } + opsize = insn_opsize(insn); SRC_EA(env, tmp, opsize, 1, NULL); gen_logic_cc(s, tmp); } From 2b04e85a3401e13cb19b1de197e6c211eaadca4c Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 17 Jan 2016 00:08:15 +0100 Subject: [PATCH 08/23] target-m68k: set PAGE_BITS to 12 for m68k Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/cpu.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 133852a3a0..fa1d0278c0 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -255,8 +255,11 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf); void register_m68k_insns (CPUM68KState *env); #ifdef CONFIG_USER_ONLY -/* Linux uses 8k pages. */ -#define TARGET_PAGE_BITS 13 +/* Coldfire Linux uses 8k pages + * and m68k linux uses 4k pages + * use the smaller one + */ +#define TARGET_PAGE_BITS 12 #else /* Smallest TLB entry size is 1k. */ #define TARGET_PAGE_BITS 10 From bcc098b0c23b4dd902ff56987d769bd839677331 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Aug 2015 01:23:35 +0200 Subject: [PATCH 09/23] target-m68k: REG() macro cleanup Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 639db766ee..50c55a42c4 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -59,9 +59,10 @@ static TCGv cpu_aregs[8]; static TCGv_i64 cpu_fregs[8]; static TCGv_i64 cpu_macc[4]; -#define DREG(insn, pos) cpu_dregs[((insn) >> (pos)) & 7] -#define AREG(insn, pos) cpu_aregs[((insn) >> (pos)) & 7] -#define FREG(insn, pos) cpu_fregs[((insn) >> (pos)) & 7] +#define REG(insn, pos) (((insn) >> (pos)) & 7) +#define DREG(insn, pos) cpu_dregs[REG(insn, pos)] +#define AREG(insn, pos) cpu_aregs[REG(insn, pos)] +#define FREG(insn, pos) cpu_fregs[REG(insn, pos)] #define MACREG(acc) cpu_macc[acc] #define QREG_SP cpu_aregs[7] From 5dbb6784b7e2b833c036b4df58aa07067e35f476 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Aug 2015 02:41:40 +0200 Subject: [PATCH 10/23] target-m68k: allow to update flags with operation on words and bytes Signed-off-by: Laurent Vivier --- target-m68k/cpu.h | 14 +++- target-m68k/helper.c | 137 +++++++++++++++++++++++++++++----------- target-m68k/translate.c | 82 ++++++++++++------------ 3 files changed, 150 insertions(+), 83 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index fa1d0278c0..18b69307a5 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -173,13 +173,23 @@ void cpu_m68k_flush_flags(CPUM68KState *, int); 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_CMPB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_CMPW, /* 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 */ }; diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 89bbe6dfa6..4fe36b85fd 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -140,22 +140,63 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) uint32_t dest; uint32_t tmp; -#define HIGHBIT 0x80000000u +#define HIGHBIT(type) (1u << (sizeof(type) * 8 - 1)) -#define SET_NZ(x) do { \ - if ((x) == 0) \ - flags |= CCF_Z; \ - else if ((int32_t)(x) < 0) \ - flags |= CCF_N; \ +#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((type)dest); \ - tmp = dest + src; \ - if ((utype) tmp < (utype) src) \ - flags |= CCF_C; \ - if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ - flags |= CCF_V; \ + 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; @@ -165,46 +206,66 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) case CC_OP_FLAGS: flags = dest; 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); + 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); + break; + case CC_OP_ADDW: + SET_FLAGS_ADD(int16_t, uint16_t); break; case CC_OP_ADD: - SET_NZ(dest); - if (dest < src) - flags |= CCF_C; - tmp = dest - src; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + 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_CMPB: - SET_FLAGS_SUB(int8_t, uint8_t); + case CC_OP_ADDXB: + SET_FLAGS_ADDX(int8_t, uint8_t); break; - case CC_OP_CMPW: - SET_FLAGS_SUB(int16_t, uint16_t); + case CC_OP_ADDXW: + SET_FLAGS_ADDX(int16_t, uint16_t); break; case CC_OP_ADDX: - SET_NZ(dest); - if (dest <= src) - flags |= CCF_C; - tmp = dest - src - 1; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + 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_NZ(dest); - tmp = dest + src + 1; - if (tmp <= src) - flags |= CCF_C; - if (HIGHBIT & (tmp ^ dest) & (tmp ^ src)) - flags |= CCF_V; + 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_NZ(dest); - if (src) - flags |= CCF_C; + SET_FLAGS_SHIFT(int32_t); break; default: cpu_abort(CPU(cpu), "Bad CC_OP %d", cc_op); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 50c55a42c4..e2f176ecfd 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -428,10 +428,23 @@ static inline void gen_flush_flags(DisasContext *s) s->cc_op = CC_OP_FLAGS; } -static void gen_logic_cc(DisasContext *s, TCGv val) +#define SET_CC_OP(opsize, op) do { \ + switch (opsize) { \ + case OS_BYTE: \ + s->cc_op = CC_OP_##op##B; break; \ + case OS_WORD: \ + s->cc_op = CC_OP_##op##W; break; \ + case OS_LONG: \ + s->cc_op = CC_OP_##op; break; \ + default: \ + abort(); \ + } \ +} while (0) + +static void gen_logic_cc(DisasContext *s, TCGv val, int opsize) { tcg_gen_mov_i32(QREG_CC_DEST, val); - s->cc_op = CC_OP_LOGIC; + SET_CC_OP(opsize, LOGIC); } static void gen_update_cc_add(TCGv dest, TCGv src) @@ -933,8 +946,7 @@ DISAS_INSN(mulw) SRC_EA(env, src, OS_WORD, sign, NULL); tcg_gen_mul_i32(tmp, tmp, src); tcg_gen_mov_i32(reg, tmp); - /* Unlike m68k, coldfire always clears the overflow bit. */ - gen_logic_cc(s, tmp); + gen_logic_cc(s, tmp, OS_WORD); } DISAS_INSN(divw) @@ -1103,7 +1115,7 @@ DISAS_INSN(sats) reg = DREG(insn, 0); gen_flush_flags(s); gen_helper_sats(reg, reg, QREG_CC_DEST); - gen_logic_cc(s, reg); + gen_logic_cc(s, reg, OS_LONG); } static void gen_push(DisasContext *s, TCGv val) @@ -1228,11 +1240,11 @@ DISAS_INSN(arith_im) switch (op) { case 0: /* ori */ tcg_gen_ori_i32(dest, src1, im); - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); break; case 1: /* andi */ tcg_gen_andi_i32(dest, src1, im); - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); break; case 2: /* subi */ tcg_gen_mov_i32(dest, src1); @@ -1250,7 +1262,7 @@ DISAS_INSN(arith_im) break; case 5: /* eori */ tcg_gen_xori_i32(dest, src1, im); - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); break; case 6: /* cmpi */ tcg_gen_mov_i32(dest, src1); @@ -1307,7 +1319,7 @@ DISAS_INSN(move) dest_ea = ((insn >> 9) & 7) | (op << 3); DEST_EA(env, dest_ea, opsize, src, NULL); /* This will be correct because loads sign extend. */ - gen_logic_cc(s, src); + gen_logic_cc(s, src, opsize); } } @@ -1340,7 +1352,7 @@ DISAS_INSN(clr) opsize = insn_opsize(insn); DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL); - gen_logic_cc(s, tcg_const_i32(0)); + gen_logic_cc(s, tcg_const_i32(0), opsize); } static TCGv gen_get_ccr(DisasContext *s) @@ -1427,7 +1439,7 @@ DISAS_INSN(not) reg = DREG(insn, 0); tcg_gen_not_i32(reg, reg); - gen_logic_cc(s, reg); + gen_logic_cc(s, reg, OS_LONG); } DISAS_INSN(swap) @@ -1442,7 +1454,7 @@ DISAS_INSN(swap) tcg_gen_shli_i32(src1, reg, 16); tcg_gen_shri_i32(src2, reg, 16); tcg_gen_or_i32(reg, src1, src2); - gen_logic_cc(s, reg); + gen_logic_cc(s, reg, OS_LONG); } DISAS_INSN(pea) @@ -1474,7 +1486,7 @@ DISAS_INSN(ext) gen_partset_reg(OS_WORD, reg, tmp); else tcg_gen_mov_i32(reg, tmp); - gen_logic_cc(s, tmp); + gen_logic_cc(s, tmp, OS_LONG); } DISAS_INSN(tst) @@ -1484,7 +1496,7 @@ DISAS_INSN(tst) opsize = insn_opsize(insn); SRC_EA(env, tmp, opsize, 1, NULL); - gen_logic_cc(s, tmp); + gen_logic_cc(s, tmp, opsize); } DISAS_INSN(pulse) @@ -1506,7 +1518,7 @@ DISAS_INSN(tas) dest = tcg_temp_new(); SRC_EA(env, src1, OS_BYTE, 1, &addr); - gen_logic_cc(s, src1); + gen_logic_cc(s, src1, OS_BYTE); tcg_gen_ori_i32(dest, src1, 0x80); DEST_EA(env, insn, OS_BYTE, dest, &addr); } @@ -1531,7 +1543,7 @@ DISAS_INSN(mull) tcg_gen_mul_i32(dest, src1, reg); tcg_gen_mov_i32(reg, dest); /* Unlike m68k, coldfire always clears the overflow bit. */ - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); } DISAS_INSN(link) @@ -1689,7 +1701,7 @@ DISAS_INSN(moveq) val = (int8_t)insn; tcg_gen_movi_i32(DREG(insn, 9), val); - gen_logic_cc(s, tcg_const_i32(val)); + gen_logic_cc(s, tcg_const_i32(val), OS_LONG); } DISAS_INSN(mvzs) @@ -1705,7 +1717,7 @@ DISAS_INSN(mvzs) SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL); reg = DREG(insn, 9); tcg_gen_mov_i32(reg, src); - gen_logic_cc(s, src); + gen_logic_cc(s, src, opsize); } DISAS_INSN(or) @@ -1726,7 +1738,7 @@ DISAS_INSN(or) tcg_gen_or_i32(dest, src, reg); tcg_gen_mov_i32(reg, dest); } - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); } DISAS_INSN(suba) @@ -1759,40 +1771,24 @@ DISAS_INSN(mov3q) if (val == 0) val = -1; src = tcg_const_i32(val); - gen_logic_cc(s, src); + gen_logic_cc(s, src, OS_LONG); DEST_EA(env, insn, OS_LONG, src, NULL); } DISAS_INSN(cmp) { - int op; TCGv src; TCGv reg; TCGv dest; int opsize; - op = (insn >> 6) & 3; - switch (op) { - case 0: /* cmp.b */ - opsize = OS_BYTE; - s->cc_op = CC_OP_CMPB; - break; - case 1: /* cmp.w */ - opsize = OS_WORD; - s->cc_op = CC_OP_CMPW; - break; - case 2: /* cmp.l */ - opsize = OS_LONG; - s->cc_op = CC_OP_SUB; - break; - default: - abort(); - } - SRC_EA(env, src, opsize, 1, NULL); + opsize = insn_opsize(insn); + 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); } DISAS_INSN(cmpa) @@ -1812,7 +1808,7 @@ DISAS_INSN(cmpa) dest = tcg_temp_new(); tcg_gen_sub_i32(dest, reg, src); gen_update_cc_add(dest, src); - s->cc_op = CC_OP_SUB; + SET_CC_OP(OS_LONG, SUB); } DISAS_INSN(eor) @@ -1826,7 +1822,7 @@ DISAS_INSN(eor) reg = DREG(insn, 9); dest = tcg_temp_new(); tcg_gen_xor_i32(dest, src, reg); - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); DEST_EA(env, insn, OS_LONG, dest, &addr); } @@ -1848,7 +1844,7 @@ DISAS_INSN(and) tcg_gen_and_i32(dest, src, reg); tcg_gen_mov_i32(reg, dest); } - gen_logic_cc(s, dest); + gen_logic_cc(s, dest, OS_LONG); } DISAS_INSN(adda) @@ -1923,7 +1919,7 @@ DISAS_INSN(ff1) { TCGv reg; reg = DREG(insn, 0); - gen_logic_cc(s, reg); + gen_logic_cc(s, reg, OS_LONG); gen_helper_ff1(reg, reg); } From f9083519034aaa5ad5cd2c5727bd61c29bf60bc5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:19 -0700 Subject: [PATCH 11/23] target-m68k: Replace helper_xflag_lt with setcond Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- 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 4fe36b85fd..dc55a7a430 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -464,11 +464,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 & 0xffff; diff --git a/target-m68k/helper.h b/target-m68k/helper.h index f4e5fdf021..c24ace5767 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 e2f176ecfd..650c141018 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1032,10 +1032,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); s->cc_op = 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); s->cc_op = CC_OP_SUB; } @@ -1248,7 +1248,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)); s->cc_op = CC_OP_SUB; @@ -1257,7 +1257,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)); s->cc_op = CC_OP_ADD; break; case 5: /* eori */ @@ -1387,7 +1387,7 @@ DISAS_INSN(neg) tcg_gen_neg_i32(reg, src1); s->cc_op = 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); s->cc_op = CC_OP_SUB; } @@ -1633,12 +1633,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); s->cc_op = 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); s->cc_op = CC_OP_ADD; } gen_update_cc_add(dest, src2); From 20a8856eba0980fbe9d2b8ed2b33ecdb9c9fe5ad Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Aug 2015 01:44:24 +0200 Subject: [PATCH 12/23] target-m68k: remove m68k_cpu_exec_enter() and m68k_cpu_exec_exit() Update cc_op directly from tcg_gen_insn_start() and restore_state_to_opc() Copied from target-i386 Signed-off-by: Laurent Vivier --- cpu-exec.c | 6 ------ target-m68k/cpu.c | 2 -- target-m68k/cpu.h | 4 +--- target-m68k/helper.c | 20 -------------------- target-m68k/translate.c | 6 +++++- 5 files changed, 6 insertions(+), 32 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index e114fcdf29..e1bc368c7f 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -151,12 +151,6 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb) && qemu_log_in_addr_range(itb->pc)) { #if defined(TARGET_I386) log_cpu_state(cpu, CPU_DUMP_CCOP); -#elif defined(TARGET_M68K) - /* ??? Should not modify env state for dumping. */ - cpu_m68k_flush_flags(env, env->cc_op); - env->cc_op = CC_OP_FLAGS; - env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4); - log_cpu_state(cpu, 0); #else log_cpu_state(cpu, 0); #endif diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index f925e265b0..ef02d9f60e 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -281,8 +281,6 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) #else cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug; #endif - cc->cpu_exec_enter = m68k_cpu_exec_enter; - cc->cpu_exec_exit = m68k_cpu_exec_exit; cc->disas_set_info = m68k_cpu_disas_set_info; cc->gdb_num_core_regs = 18; diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 18b69307a5..f055ef68bf 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -61,6 +61,7 @@ #define EXCP_HALT_INSN 0x101 #define NB_MMU_MODES 2 +#define TARGET_INSN_START_EXTRA_WORDS 1 typedef struct CPUM68KState { uint32_t dregs[8]; @@ -149,9 +150,6 @@ hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void m68k_cpu_exec_enter(CPUState *cs); -void m68k_cpu_exec_exit(CPUState *cs); - void m68k_tcg_init(void); void m68k_cpu_init_gdb(M68kCPU *cpu); M68kCPU *cpu_m68k_init(const char *cpu_model); diff --git a/target-m68k/helper.c b/target-m68k/helper.c index dc55a7a430..92d1deda3c 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -922,23 +922,3 @@ void HELPER(set_mac_extu)(CPUM68KState *env, uint32_t val, uint32_t acc) res |= (uint64_t)(val & 0xffff0000) << 16; env->macc[acc + 1] = res; } - -void m68k_cpu_exec_enter(CPUState *cs) -{ - M68kCPU *cpu = M68K_CPU(cs); - CPUM68KState *env = &cpu->env; - - env->cc_op = CC_OP_FLAGS; - env->cc_dest = env->sr & 0xf; - env->cc_x = (env->sr >> 4) & 1; -} - -void m68k_cpu_exec_exit(CPUState *cs) -{ - M68kCPU *cpu = M68K_CPU(cs); - CPUM68KState *env = &cpu->env; - - cpu_m68k_flush_flags(env, env->cc_op); - env->cc_op = CC_OP_FLAGS; - env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4); -} diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 650c141018..681f3a8941 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3025,7 +3025,7 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb) do { pc_offset = dc->pc - pc_start; gen_throws_exception = NULL; - tcg_gen_insn_start(dc->pc); + tcg_gen_insn_start(dc->pc, dc->cc_op); num_insns++; if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) { @@ -3119,5 +3119,9 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, void restore_state_to_opc(CPUM68KState *env, TranslationBlock *tb, target_ulong *data) { + int cc_op = data[1]; env->pc = data[0]; + if (cc_op != CC_OP_DYNAMIC) { + env->cc_op = cc_op; + } } From 7c0eb318bdcc3667a861e7b0f140df0b6d9895e2 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 17 Jan 2016 18:55:13 +0100 Subject: [PATCH 13/23] target-m68k: update move to/from ccr/sr Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/translate.c | 57 +++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 681f3a8941..37faefe749 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -1368,12 +1368,10 @@ static TCGv gen_get_ccr(DisasContext *s) DISAS_INSN(move_from_ccr) { - TCGv reg; TCGv ccr; ccr = gen_get_ccr(s); - reg = DREG(insn, 0); - gen_partset_reg(OS_WORD, reg, ccr); + DEST_EA(env, insn, OS_WORD, ccr, NULL); } DISAS_INSN(neg) @@ -1400,37 +1398,31 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) } } -static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, - int ccr_only) +static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) { TCGv tmp; - TCGv reg; - - s->cc_op = CC_OP_FLAGS; - if ((insn & 0x38) == 0) - { - tmp = tcg_temp_new(); - reg = DREG(insn, 0); - tcg_gen_andi_i32(QREG_CC_DEST, reg, 0xf); - tcg_gen_shri_i32(tmp, reg, 4); - tcg_gen_andi_i32(QREG_CC_X, tmp, 1); - if (!ccr_only) { - gen_helper_set_sr(cpu_env, reg); - } - } - else if ((insn & 0x3f) == 0x3c) - { - uint16_t val; - val = read_im16(env, s); - gen_set_sr_im(s, val, ccr_only); - } - else - disas_undef(env, s, insn); + 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) { + gen_helper_set_sr(cpu_env, val); + } } +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); +} + + DISAS_INSN(move_to_ccr) { - gen_set_sr(env, s, insn, 1); + gen_move_to_sr(env, s, insn, 1); } DISAS_INSN(not) @@ -1957,16 +1949,14 @@ DISAS_INSN(strldsr) DISAS_INSN(move_from_sr) { - TCGv reg; TCGv sr; - if (IS_USER(s)) { + if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) { gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } sr = gen_get_sr(s); - reg = DREG(insn, 0); - gen_partset_reg(OS_WORD, reg, sr); + DEST_EA(env, insn, OS_WORD, sr, NULL); } DISAS_INSN(move_to_sr) @@ -1975,7 +1965,7 @@ DISAS_INSN(move_to_sr) gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } - gen_set_sr(env, s, insn, 0); + gen_move_to_sr(env, s, insn, 0); gen_lookup_tb(s); } @@ -2872,6 +2862,7 @@ void register_m68k_insns (CPUM68KState *env) BASE(clr, 4200, ff00); BASE(undef, 42c0, ffc0); INSN(move_from_ccr, 42c0, fff8, CF_ISA_A); + INSN(move_from_ccr, 42c0, ffc0, M68000); INSN(neg, 4480, fff8, CF_ISA_A); INSN(neg, 4400, ff00, M68000); INSN(undef, 44c0, ffc0, M68000); From 91f90d7191f862ab27528dbdf76cee55c77f79cf Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 17 Jan 2016 19:03:23 +0100 Subject: [PATCH 14/23] target-m68k: don't update cc_dest in helpers Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/cpu.h | 1 - target-m68k/helper.c | 28 ++++++++++++++-------------- target-m68k/helper.h | 2 +- target-m68k/translate.c | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index f055ef68bf..72a939eeaa 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -158,7 +158,6 @@ M68kCPU *cpu_m68k_init(const char *cpu_model); is returned if the signal was handled by the virtual CPU. */ int cpu_m68k_signal_handler(int host_signum, void *pinfo, void *puc); -void cpu_m68k_flush_flags(CPUM68KState *, int); /* Instead of computing the condition codes after each m68k instruction, diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 92d1deda3c..0a1ff1105d 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -132,9 +132,8 @@ void m68k_cpu_init_gdb(M68kCPU *cpu) /* TODO: Add [E]MAC registers. */ } -void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) +static uint32_t cpu_m68k_flush_flags(CPUM68KState *env, int op) { - M68kCPU *cpu = m68k_env_get_cpu(env); int flags; uint32_t src; uint32_t dest; @@ -202,7 +201,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) flags = 0; src = env->cc_src; dest = env->cc_dest; - switch (cc_op) { + switch (op) { case CC_OP_FLAGS: flags = dest; break; @@ -268,10 +267,9 @@ set_x: SET_FLAGS_SHIFT(int32_t); break; default: - cpu_abort(CPU(cpu), "Bad CC_OP %d", cc_op); + g_assert_not_reached(); } - env->cc_op = CC_OP_FLAGS; - env->cc_dest = flags; + return flags; } void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val) @@ -422,20 +420,21 @@ uint32_t HELPER(subx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) { uint32_t res; uint32_t old_flags; + int op; old_flags = env->cc_dest; if (env->cc_x) { env->cc_x = (op1 <= op2); - env->cc_op = CC_OP_SUBX; + op = CC_OP_SUBX; res = op1 - (op2 + 1); } else { env->cc_x = (op1 < op2); - env->cc_op = CC_OP_SUB; + op = CC_OP_SUB; res = op1 - op2; } env->cc_dest = res; env->cc_src = op2; - cpu_m68k_flush_flags(env, env->cc_op); + env->cc_dest = cpu_m68k_flush_flags(env, op); /* !Z is sticky. */ env->cc_dest &= (old_flags | ~CCF_Z); return res; @@ -445,20 +444,21 @@ uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) { uint32_t res; uint32_t old_flags; + int op; old_flags = env->cc_dest; if (env->cc_x) { res = op1 + op2 + 1; env->cc_x = (res <= op2); - env->cc_op = CC_OP_ADDX; + op = CC_OP_ADDX; } else { res = op1 + op2; env->cc_x = (res < op2); - env->cc_op = CC_OP_ADD; + op = CC_OP_ADD; } env->cc_dest = res; env->cc_src = op2; - cpu_m68k_flush_flags(env, env->cc_op); + env->cc_dest = cpu_m68k_flush_flags(env, op); /* !Z is sticky. */ env->cc_dest &= (old_flags | ~CCF_Z); return res; @@ -790,9 +790,9 @@ void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) } } -void HELPER(flush_flags)(CPUM68KState *env, uint32_t cc_op) +uint32_t HELPER(flush_flags)(CPUM68KState *env, uint32_t op) { - cpu_m68k_flush_flags(env, cc_op); + return cpu_m68k_flush_flags(env, op); } uint32_t HELPER(get_macf)(CPUM68KState *env, uint64_t val) diff --git a/target-m68k/helper.h b/target-m68k/helper.h index c24ace5767..0f5a7cf799 100644 --- a/target-m68k/helper.h +++ b/target-m68k/helper.h @@ -45,5 +45,5 @@ 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, void, env, i32) +DEF_HELPER_2(flush_flags, i32, env, i32) DEF_HELPER_2(raise_exception, void, env, i32) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 37faefe749..3db7918b98 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -424,7 +424,7 @@ static inline void gen_flush_flags(DisasContext *s) if (s->cc_op == CC_OP_FLAGS) return; gen_flush_cc_op(s); - gen_helper_flush_flags(cpu_env, QREG_CC_OP); + gen_helper_flush_flags(QREG_CC_DEST, cpu_env, QREG_CC_OP); s->cc_op = CC_OP_FLAGS; } @@ -719,6 +719,7 @@ 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); + gen_flush_cc_op(s); switch (cond) { case 0: /* T */ tcg_gen_br(l1); @@ -1673,7 +1674,6 @@ DISAS_INSN(branch) /* bsr */ gen_push(s, tcg_const_i32(s->pc)); } - gen_flush_cc_op(s); if (op > 1) { /* Bcc */ l1 = gen_new_label(); From 9fdb533fb129b19610941bd1e5dd93e7471a18f5 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Sun, 9 Aug 2015 01:44:24 +0200 Subject: [PATCH 15/23] target-m68k: update CPU flags management Copied from target-i386 Signed-off-by: Laurent Vivier Reviewed-by: Richard Henderson --- target-m68k/cpu.h | 5 +- target-m68k/translate.c | 121 +++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 40 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index 72a939eeaa..f0f670c2e2 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -167,7 +167,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo, * using this information. Condition codes are not generated if they * are only needed for conditional branches. */ -enum { +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 */ @@ -188,7 +188,8 @@ enum { 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, +} CCOp; #define CCF_C 0x01 #define CCF_V 0x02 diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 3db7918b98..edd8744d20 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -133,7 +133,7 @@ typedef struct DisasContext { target_ulong insn_pc; /* Start of the current instruction. */ target_ulong pc; int is_jmp; - int cc_op; + CCOp cc_op; /* Current CC operation */ int user; uint32_t fpcr; struct TranslationBlock *tb; @@ -175,6 +175,53 @@ 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, +}; + +static void set_cc_op(DisasContext *s, CCOp op) +{ + int dead; + + if (s->cc_op == op) { + return; + } + + /* 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); + } + if (dead & USES_CC_SRC) { + tcg_gen_discard_i32(QREG_CC_SRC); + } + if (s->cc_op == CC_OP_DYNAMIC) { + tcg_gen_discard_i32(QREG_CC_OP); + } + s->cc_op = op; +} + +/* Update the CPU env CC_OP state. */ +static inline void update_cc_op(DisasContext *s) +{ + if (s->cc_op != CC_OP_DYNAMIC) { + tcg_gen_movi_i32(QREG_CC_OP, s->cc_op); + } +} + /* Generate a load from the specified address. Narrow values are sign extended to full register width. */ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign) @@ -411,31 +458,28 @@ static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, TCGv base) return add; } -/* Update the CPU env CC_OP state. */ -static inline void gen_flush_cc_op(DisasContext *s) -{ - if (s->cc_op != CC_OP_DYNAMIC) - tcg_gen_movi_i32(QREG_CC_OP, s->cc_op); -} - /* Evaluate all the CC flags. */ + static inline void gen_flush_flags(DisasContext *s) { if (s->cc_op == CC_OP_FLAGS) return; - gen_flush_cc_op(s); - gen_helper_flush_flags(QREG_CC_DEST, cpu_env, QREG_CC_OP); - s->cc_op = CC_OP_FLAGS; + 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)); + } + set_cc_op(s, CC_OP_FLAGS); } #define SET_CC_OP(opsize, op) do { \ switch (opsize) { \ case OS_BYTE: \ - s->cc_op = CC_OP_##op##B; break; \ + set_cc_op(s, CC_OP_##op##B); break; \ case OS_WORD: \ - s->cc_op = CC_OP_##op##W; break; \ + set_cc_op(s, CC_OP_##op##W); break; \ case OS_LONG: \ - s->cc_op = CC_OP_##op; break; \ + set_cc_op(s, CC_OP_##op); break; \ default: \ abort(); \ } \ @@ -719,7 +763,7 @@ 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); - gen_flush_cc_op(s); + update_cc_op(s); switch (cond) { case 0: /* T */ tcg_gen_br(l1); @@ -836,7 +880,7 @@ DISAS_INSN(scc) /* Force a TB lookup after an instruction that changes the CPU state. */ static void gen_lookup_tb(DisasContext *s) { - gen_flush_cc_op(s); + update_cc_op(s); tcg_gen_movi_i32(QREG_PC, s->pc); s->is_jmp = DISAS_UPDATE; } @@ -844,7 +888,7 @@ static void gen_lookup_tb(DisasContext *s) /* Generate a jump to an immediate address. */ static void gen_jmp_im(DisasContext *s, uint32_t dest) { - gen_flush_cc_op(s); + update_cc_op(s); tcg_gen_movi_i32(QREG_PC, dest); s->is_jmp = DISAS_JUMP; } @@ -852,14 +896,14 @@ static void gen_jmp_im(DisasContext *s, uint32_t dest) /* Generate a jump to the address in qreg DEST. */ static void gen_jmp(DisasContext *s, TCGv dest) { - gen_flush_cc_op(s); + update_cc_op(s); tcg_gen_mov_i32(QREG_PC, dest); s->is_jmp = DISAS_JUMP; } static void gen_exception(DisasContext *s, uint32_t where, int nr) { - gen_flush_cc_op(s); + update_cc_op(s); gen_jmp_im(s, where); gen_helper_raise_exception(cpu_env, tcg_const_i32(nr)); } @@ -977,7 +1021,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); - s->cc_op = CC_OP_FLAGS; + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(divl) @@ -1009,7 +1053,7 @@ DISAS_INSN(divl) /* rem */ tcg_gen_mov_i32 (reg, QREG_DIV2); } - s->cc_op = CC_OP_FLAGS; + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(addsub) @@ -1034,11 +1078,11 @@ DISAS_INSN(addsub) if (add) { tcg_gen_add_i32(dest, tmp, src); tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src); - s->cc_op = CC_OP_ADD; + set_cc_op(s, CC_OP_ADD); } else { tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tmp, src); tcg_gen_sub_i32(dest, tmp, src); - s->cc_op = CC_OP_SUB; + set_cc_op(s, CC_OP_SUB); } gen_update_cc_add(dest, src); if (insn & 0x100) { @@ -1225,7 +1269,6 @@ DISAS_INSN(bitop_im) DEST_EA(env, insn, opsize, tmp, &addr); } } - DISAS_INSN(arith_im) { int op; @@ -1252,14 +1295,14 @@ DISAS_INSN(arith_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)); - s->cc_op = CC_OP_SUB; + set_cc_op(s, CC_OP_SUB); break; case 3: /* addi */ 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)); - s->cc_op = CC_OP_ADD; + set_cc_op(s, CC_OP_ADD); break; case 5: /* eori */ tcg_gen_xori_i32(dest, src1, im); @@ -1269,7 +1312,7 @@ DISAS_INSN(arith_im) tcg_gen_mov_i32(dest, src1); tcg_gen_subi_i32(dest, dest, im); gen_update_cc_add(dest, tcg_const_i32(im)); - s->cc_op = CC_OP_SUB; + set_cc_op(s, CC_OP_SUB); break; default: abort(); @@ -1384,10 +1427,9 @@ DISAS_INSN(neg) src1 = tcg_temp_new(); tcg_gen_mov_i32(src1, reg); tcg_gen_neg_i32(reg, src1); - s->cc_op = CC_OP_SUB; gen_update_cc_add(reg, src1); tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, tcg_const_i32(0), src1); - s->cc_op = CC_OP_SUB; + set_cc_op(s, CC_OP_SUB); } static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) @@ -1397,6 +1439,7 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) if (!ccr_only) { gen_helper_set_sr(cpu_env, tcg_const_i32(val & 0xff00)); } + set_cc_op(s, CC_OP_FLAGS); } static void gen_set_sr(DisasContext *s, TCGv val, int ccr_only) @@ -1628,11 +1671,11 @@ DISAS_INSN(addsubq) if (insn & 0x0100) { tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); tcg_gen_subi_i32(dest, dest, val); - s->cc_op = CC_OP_SUB; + set_cc_op(s, CC_OP_SUB); } else { tcg_gen_addi_i32(dest, dest, val); tcg_gen_setcond_i32(TCG_COND_LTU, QREG_CC_X, dest, src2); - s->cc_op = CC_OP_ADD; + set_cc_op(s, CC_OP_ADD); } gen_update_cc_add(dest, src2); } @@ -1678,11 +1721,14 @@ DISAS_INSN(branch) /* 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); } } @@ -1858,7 +1904,6 @@ DISAS_INSN(addx) reg = DREG(insn, 9); src = DREG(insn, 0); gen_helper_addx_cc(reg, cpu_env, reg, src); - s->cc_op = CC_OP_FLAGS; } /* TODO: This could be implemented without helper functions. */ @@ -1883,7 +1928,7 @@ DISAS_INSN(shift_im) gen_helper_sar_cc(reg, cpu_env, reg, shift); } } - s->cc_op = CC_OP_SHIFT; + set_cc_op(s, CC_OP_SHIFT); } DISAS_INSN(shift_reg) @@ -1904,7 +1949,7 @@ DISAS_INSN(shift_reg) gen_helper_sar_cc(reg, cpu_env, reg, shift); } } - s->cc_op = CC_OP_SHIFT; + set_cc_op(s, CC_OP_SHIFT); } DISAS_INSN(ff1) @@ -2716,7 +2761,7 @@ DISAS_INSN(macsr_to_ccr) { tcg_gen_movi_i32(QREG_CC_X, 0); tcg_gen_andi_i32(QREG_CC_DEST, QREG_MACSR, 0xf); - s->cc_op = CC_OP_FLAGS; + set_cc_op(s, CC_OP_FLAGS); } DISAS_INSN(to_mac) @@ -3047,20 +3092,20 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb) if (unlikely(cs->singlestep_enabled)) { /* Make sure the pc is updated, and raise a debug exception. */ if (!dc->is_jmp) { - gen_flush_cc_op(dc); + update_cc_op(dc); tcg_gen_movi_i32(QREG_PC, dc->pc); } gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG)); } else { switch(dc->is_jmp) { case DISAS_NEXT: - gen_flush_cc_op(dc); + update_cc_op(dc); gen_jmp_tb(dc, 0, dc->pc); break; default: case DISAS_JUMP: case DISAS_UPDATE: - gen_flush_cc_op(dc); + update_cc_op(dc); /* indicate that the hash table must be used to find the next TB */ tcg_gen_exit_tb(0); break; From 8e394ccabdb1e439aab092de6b9d2f26432e962f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:16 -0700 Subject: [PATCH 16/23] target-m68k: Print flags properly Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- target-m68k/cpu.h | 1 + target-m68k/helper.c | 2 +- target-m68k/translate.c | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h index f0f670c2e2..2f08a2cf8c 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -158,6 +158,7 @@ M68kCPU *cpu_m68k_init(const char *cpu_model); 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); /* Instead of computing the condition codes after each m68k instruction, diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 0a1ff1105d..d9ea830c67 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -132,7 +132,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 edd8744d20..cecd12c984 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3140,15 +3140,15 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, for (i = 0; i < 8; i++) { u.d = env->fregs[i]; - cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n", - i, env->dregs[i], i, env->aregs[i], - i, u.l.upper, u.l.lower, *(double *)&u.d); + cpu_fprintf(f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n", + i, env->dregs[i], i, env->aregs[i], + 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 & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-', - (sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-'); + 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); } From 99c514485b1d7922c4ca1ed767fd45525de4701f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:17 -0700 Subject: [PATCH 17/23] target-m68k: Some fixes to SR and flags management Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- 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 2f08a2cf8c..c0de97826d 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -158,7 +158,8 @@ M68kCPU *cpu_m68k_init(const char *cpu_model); 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); /* Instead of computing the condition codes after each m68k instruction, diff --git a/target-m68k/helper.c b/target-m68k/helper.c index d9ea830c67..1a54e6678b 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -132,7 +132,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; @@ -272,6 +272,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); @@ -466,7 +478,8 @@ uint32_t HELPER(addx_cc)(CPUM68KState *env, uint32_t op1, uint32_t op2) 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 e41ae46498..af361776a6 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -63,9 +63,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) @@ -112,6 +112,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 cecd12c984..73f9e9f483 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3145,7 +3145,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' : '-'); From 18dd87f26bed46f22bb1b9536329c02de500f407 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:18 -0700 Subject: [PATCH 18/23] target-m68k: Remove incorrect clearing of cc_x The CF docs certainly doesnt suggest this is true. Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- target-m68k/helper.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 1a54e6678b..a9974b1b73 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -207,19 +207,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); From 620c6cf66584bfbee90db84a7e87a6eabf230ca9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:20 -0700 Subject: [PATCH 19/23] target-m68k: Reorg flags handling Separate all ccr bits. Continue to batch updates via cc_op. Signed-off-by: Richard Henderson Fix gen_logic_cc() to really extend the size of the result. Fix gen_get_ccr(): update cc_op as it is used by the helper. Factorize flags computing and src/ccr cleanup Signed-off-by: Laurent Vivier target-m68k: sr/ccr cleanup Signed-off-by: Laurent Vivier --- target-m68k/cpu.c | 2 +- target-m68k/cpu.h | 46 +++-- target-m68k/helper.c | 359 +++++++++++++---------------------- target-m68k/helper.h | 6 +- target-m68k/op_helper.c | 30 ++- target-m68k/qregs.def | 6 +- target-m68k/translate.c | 411 ++++++++++++++++++---------------------- 7 files changed, 361 insertions(+), 499 deletions(-) diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index ef02d9f60e..ba17480098 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -58,7 +58,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 c0de97826d..48c5b811f3 100644 --- a/target-m68k/cpu.h +++ b/target-m68k/cpu.h @@ -75,9 +75,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; @@ -170,27 +172,23 @@ void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t); * are only needed for conditional branches. */ 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 a9974b1b73..094a7e59a9 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -132,151 +132,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); @@ -413,59 +268,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; - int op; + uint32_t res, new_x; - old_flags = env->cc_dest; if (env->cc_x) { - env->cc_x = (op1 <= op2); - op = CC_OP_SUBX; + new_x = (op1 <= op2); res = op1 - (op2 + 1); } else { - env->cc_x = (op1 < op2); - op = CC_OP_SUB; + new_x = (op1 < op2); res = op1 - op2; } - env->cc_dest = res; - env->cc_src = op2; - env->cc_dest = cpu_m68k_flush_flags(env, 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; - int op; + uint32_t res, new_x; - old_flags = env->cc_dest; if (env->cc_x) { res = op1 + op2 + 1; - env->cc_x = (res <= op2); - op = CC_OP_ADDX; + new_x = (res <= op2); } else { res = op1 + op2; - env->cc_x = (res < op2); - op = CC_OP_ADD; + new_x = (res < op2); } - env->cc_dest = res; - env->cc_src = op2; - env->cc_dest = cpu_m68k_flush_flags(env, 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; } @@ -478,73 +326,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; } @@ -796,9 +624,92 @@ void HELPER(mac_set_flags)(CPUM68KState *env, uint32_t acc) } } -uint32_t HELPER(flush_flags)(CPUM68KState *env, uint32_t op) + +#define COMPUTE_CCR(op, x, n, z, v, c) { \ + switch (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", op); \ + } \ +} while (0) + +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; + + COMPUTE_CCR(env->cc_op, x, n, z, v, c); + + 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; + + COMPUTE_CCR(cc_op, env->cc_x, env->cc_n, env->cc_z, env->cc_v, env->cc_c); + 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 0f5a7cf799..c8681480f0 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 af361776a6..48e02e4062 100644 --- a/target-m68k/op_helper.c +++ b/target-m68k/op_helper.c @@ -185,7 +185,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; @@ -195,16 +194,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) @@ -213,7 +210,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; @@ -222,14 +218,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 204663e1aa..156c0f558f 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 73f9e9f483..85d5c95bc3 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -134,6 +134,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; @@ -175,49 +176,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; } - - /* 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); - } - if (dead & USES_CC_SRC) { - tcg_gen_discard_i32(QREG_CC_SRC); - } - if (s->cc_op == CC_OP_DYNAMIC) { - tcg_gen_discard_i32(QREG_CC_OP); - } s->cc_op = op; + s->cc_op_synced = 0; + + /* 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 & CCF_Z) { + tcg_gen_discard_i32(QREG_CC_Z); + } + if (dead & CCF_V) { + tcg_gen_discard_i32(QREG_CC_V); + } } /* 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); } } @@ -460,41 +456,79 @@ 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 inline void gen_ext(TCGv res, TCGv val, int opsize, int sign) +{ + switch (opsize) { + case OS_BYTE: + if (sign) { + tcg_gen_ext8s_i32(res, val); + } else { + tcg_gen_ext8u_i32(res, val); + } + break; + case OS_WORD: + if (sign) { + tcg_gen_ext16s_i32(res, val); + } else { + tcg_gen_ext16u_i32(res, val); + } + break; + case OS_LONG: + tcg_gen_mov_i32(res, val); + break; + default: + g_assert_not_reached(); + } +} + +static TCGv gen_extend(TCGv val, int opsize, int sign) +{ + TCGv tmp; + + if (opsize == OS_LONG) { + tmp = val; + } else { + tmp = tcg_temp_new(); + gen_ext(tmp, val, opsize, sign); + } + + 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); + gen_ext(QREG_CC_N, val, 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) @@ -550,36 +584,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, @@ -758,7 +762,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. */ @@ -767,97 +772,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) @@ -1021,6 +986,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); } @@ -1116,42 +1082,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) @@ -1159,7 +1126,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); } @@ -1231,28 +1198,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); @@ -1267,8 +1226,10 @@ DISAS_INSN(bitop_im) break; } DEST_EA(env, insn, opsize, tmp, &addr); + tcg_temp_free(tmp); } } + DISAS_INSN(arith_im) { int op; @@ -1292,7 +1253,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); @@ -1301,7 +1262,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 */ @@ -1309,10 +1270,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(); @@ -1404,9 +1363,9 @@ static TCGv gen_get_ccr(DisasContext *s) TCGv dest; gen_flush_flags(s); + update_cc_op(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; } @@ -1428,45 +1387,47 @@ DISAS_INSN(neg) tcg_gen_mov_i32(src1, reg); tcg_gen_neg_i32(reg, src1); 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) +static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, + 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) { - gen_helper_set_sr(cpu_env, val); + if ((insn & 0x38) == 0) { + if (ccr_only) { + gen_helper_set_ccr(cpu_env, DREG(insn, 0)); + } else { + gen_helper_set_sr(cpu_env, DREG(insn, 0)); + } + set_cc_op(s, CC_OP_FLAGS); + } else if ((insn & 0x3f) == 0x3c) { + uint16_t val; + val = read_im16(env, s); + gen_set_sr_im(s, val, ccr_only); + } else { + disas_undef(env, s, insn); } } -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); -} - DISAS_INSN(move_to_ccr) { - gen_move_to_sr(env, s, insn, 1); + gen_set_sr(env, s, insn, 1); } DISAS_INSN(not) @@ -1670,10 +1631,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); } @@ -1717,18 +1678,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); } } @@ -1817,16 +1776,13 @@ DISAS_INSN(cmp) { TCGv src; TCGv reg; - TCGv dest; int opsize; opsize = insn_opsize(insn); 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) @@ -1834,7 +1790,6 @@ DISAS_INSN(cmpa) int opsize; TCGv src; TCGv reg; - TCGv dest; if (insn & 0x100) { opsize = OS_LONG; @@ -1843,10 +1798,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) @@ -1913,6 +1866,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) @@ -1928,7 +1883,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) @@ -1938,8 +1892,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 { @@ -1949,7 +1901,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) @@ -2010,7 +1962,7 @@ DISAS_INSN(move_to_sr) gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); return; } - gen_move_to_sr(env, s, insn, 0); + gen_set_sr(env, s, insn, 0); gen_lookup_tb(s); } @@ -2759,8 +2711,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); + TCGv tmp = tcg_temp_new(); + tcg_gen_andi_i32(tmp, QREG_MACSR, 0xf); + gen_helper_set_sr(cpu_env, tmp); + tcg_temp_free(tmp); set_cc_op(s, CC_OP_FLAGS); } @@ -3044,6 +2998,7 @@ void gen_intermediate_code(CPUM68KState *env, 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; From 6a432295d73df91890dc70c4a94dcc4ba88ad1c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:21 -0700 Subject: [PATCH 20/23] target-m68k: Introduce DisasCompare Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- target-m68k/translate.c | 85 +++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 85d5c95bc3..4a650e1f0e 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -759,8 +759,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; @@ -768,61 +775,92 @@ 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); - update_cc_op(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); + update_cc_op(s); + tcg_gen_brcond_i32(c.tcond, c.v1, c.v2, l1); + free_cond(&c); } DISAS_INSN(scc) @@ -1678,7 +1716,6 @@ DISAS_INSN(branch) /* bsr */ gen_push(s, tcg_const_i32(s->pc)); } - update_cc_op(s); if (op > 1) { /* Bcc */ l1 = gen_new_label(); From b459e3eccfae7fe83e30187c391de00bccf4f51d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:22 -0700 Subject: [PATCH 21/23] target-m68k: Use setcond for scc Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- 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 4a650e1f0e..5cc5e14bb6 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -865,19 +865,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. */ From 9d896621c1820fd8f437fac26fd7d2e0921091c3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:23 -0700 Subject: [PATCH 22/23] target-m68k: Optimize some comparisons Signed-off-by: Richard Henderson [laurent: fixed VC and VS: assign v1, not v2] Signed-off-by: Laurent Vivier --- target-m68k/translate.c | 109 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 5cc5e14bb6..52aa800f11 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -771,10 +771,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; @@ -785,7 +818,72 @@ 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->v1 = c->v2; + goto done; + } + 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(); @@ -833,10 +931,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); } From 36f0399d46f2ccf4f6e7451ba46b1e8d0e9ab341 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Aug 2015 07:59:24 -0700 Subject: [PATCH 23/23] target-m68k: Optimize gen_flush_flags Signed-off-by: Richard Henderson Signed-off-by: Laurent Vivier --- 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 52aa800f11..6c6173a09e 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -458,18 +458,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; }