Commit 9f55925b authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-3.0-pull-request' into staging



Convert to TranslatorOps

I've updated the series to fix conflicts with:

21528149 target/m68k: Add trailing '\n' to qemu_log() call
07ea28b4 tcg: Pass tb and index to tcg_gen_exit_tb separately

# gpg: Signature made Mon 11 Jun 2018 11:48:52 BST
# gpg:                using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/m68k-for-3.0-pull-request:
  target/m68k: Merge disas_m68k_insn into m68k_tr_translate_insn
  target/m68k: Improve ending TB at page boundaries
  target/m68k: Convert to TranslatorOps
  target/m68k: Convert to DisasContextBase
  target/m68k: Rename DISAS_UPDATE and gen_lookup_tb
  target/m68k: Use lookup_and_goto_tb for DISAS_JUMP
  target/m68k: Remove DISAS_JUMP_NEXT as unused
  target/m68k: Replace DISAS_TB_JUMP with DISAS_NORETURN
  target/m68k: Use DISAS_NORETURN for exceptions

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents a7a7309c a56f36c1
Loading
Loading
Loading
Loading
+180 −176
Original line number Diff line number Diff line
@@ -111,14 +111,11 @@ void m68k_tcg_init(void)

/* internal defines */
typedef struct DisasContext {
    DisasContextBase base;
    CPUM68KState *env;
    target_ulong insn_pc; /* Start of the current instruction.  */
    target_ulong pc;
    int is_jmp;
    CCOp cc_op; /* Current CC operation */
    int cc_op_synced;
    struct TranslationBlock *tb;
    int singlestep_enabled;
    TCGv_i64 mactmp;
    int done_mac;
    int writeback_mask;
@@ -198,17 +195,15 @@ static void do_writebacks(DisasContext *s)

/* is_jmp field values */
#define DISAS_JUMP      DISAS_TARGET_0 /* only pc was modified dynamically */
#define DISAS_UPDATE    DISAS_TARGET_1 /* cpu state was modified dynamically */
#define DISAS_TB_JUMP   DISAS_TARGET_2 /* only pc was modified statically */
#define DISAS_JUMP_NEXT DISAS_TARGET_3
#define DISAS_EXIT      DISAS_TARGET_1 /* cpu state was modified dynamically */

#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s)   (!(s->tb->flags & TB_FLAGS_MSR_S))
#define SFC_INDEX(s) ((s->tb->flags & TB_FLAGS_SFC_S) ? \
#define IS_USER(s)   (!(s->base.tb->flags & TB_FLAGS_MSR_S))
#define SFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_SFC_S) ? \
                      MMU_KERNEL_IDX : MMU_USER_IDX)
#define DFC_INDEX(s) ((s->tb->flags & TB_FLAGS_DFC_S) ? \
#define DFC_INDEX(s) ((s->base.tb->flags & TB_FLAGS_DFC_S) ? \
                      MMU_KERNEL_IDX : MMU_USER_IDX)
#endif

@@ -280,7 +275,7 @@ static void gen_jmp_im(DisasContext *s, uint32_t dest)
{
    update_cc_op(s);
    tcg_gen_movi_i32(QREG_PC, dest);
    s->is_jmp = DISAS_JUMP;
    s->base.is_jmp = DISAS_JUMP;
}

/* Generate a jump to the address in qreg DEST.  */
@@ -288,26 +283,26 @@ static void gen_jmp(DisasContext *s, TCGv dest)
{
    update_cc_op(s);
    tcg_gen_mov_i32(QREG_PC, dest);
    s->is_jmp = DISAS_JUMP;
    s->base.is_jmp = DISAS_JUMP;
}

static void gen_raise_exception(int nr)
static void gen_exception(DisasContext *s, uint32_t dest, int nr)
{
    TCGv_i32 tmp = tcg_const_i32(nr);
    TCGv_i32 tmp;

    update_cc_op(s);
    tcg_gen_movi_i32(QREG_PC, dest);

    tmp = tcg_const_i32(nr);
    gen_helper_raise_exception(cpu_env, tmp);
    tcg_temp_free_i32(tmp);
}

static void gen_exception(DisasContext *s, uint32_t where, int nr)
{
    gen_jmp_im(s, where);
    gen_raise_exception(nr);
    s->base.is_jmp = DISAS_NORETURN;
}

static inline void gen_addr_fault(DisasContext *s)
{
    gen_exception(s, s->insn_pc, EXCP_ADDRESS);
    gen_exception(s, s->base.pc_next, EXCP_ADDRESS);
}

/* Generate a load from the specified address.  Narrow values are
@@ -1005,7 +1000,7 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
        break;
    case OS_EXTENDED:
        if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
            gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
            gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
            break;
        }
        tcg_gen_qemu_ld32u(tmp, addr, index);
@@ -1019,7 +1014,7 @@ static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
        /* unimplemented data type on 68040/ColdFire
         * FIXME if needed for another FPU
         */
        gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
        gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
        break;
    default:
        g_assert_not_reached();
@@ -1059,7 +1054,7 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
        break;
    case OS_EXTENDED:
        if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
            gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
            gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
            break;
        }
        tcg_gen_ld16u_i32(tmp, fp, offsetof(FPReg, l.upper));
@@ -1073,7 +1068,7 @@ static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp,
        /* unimplemented data type on 68040/ColdFire
         * FIXME if needed for another FPU
         */
        gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
        gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
        break;
    default:
        g_assert_not_reached();
@@ -1205,7 +1200,7 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
                break;
            case OS_EXTENDED:
                if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
                    gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
                    gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
                    break;
                }
                tmp = tcg_const_i32(read_im32(env, s) >> 16);
@@ -1219,7 +1214,7 @@ static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
                /* unimplemented data type on 68040/ColdFire
                 * FIXME if needed for another FPU
                 */
                gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
                gen_exception(s, s->base.pc_next, EXCP_FP_UNIMP);
                break;
            default:
                g_assert_not_reached();
@@ -1448,11 +1443,11 @@ static void gen_jmpcc(DisasContext *s, int cond, TCGLabel *l1)
}

/* Force a TB lookup after an instruction that changes the CPU state.  */
static void gen_lookup_tb(DisasContext *s)
static void gen_exit_tb(DisasContext *s)
{
    update_cc_op(s);
    tcg_gen_movi_i32(QREG_PC, s->pc);
    s->is_jmp = DISAS_UPDATE;
    s->base.is_jmp = DISAS_EXIT;
}

#define SRC_EA(env, result, opsize, op_sign, addrp) do {                \
@@ -1476,8 +1471,8 @@ static void gen_lookup_tb(DisasContext *s)
static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
{
#ifndef CONFIG_USER_ONLY
    return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
           (s->insn_pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
    return (s->base.pc_first & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)
        || (s->base.pc_next & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
#else
    return true;
#endif
@@ -1486,17 +1481,17 @@ static inline bool use_goto_tb(DisasContext *s, uint32_t dest)
/* Generate a jump to an immediate address.  */
static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
{
    if (unlikely(s->singlestep_enabled)) {
    if (unlikely(s->base.singlestep_enabled)) {
        gen_exception(s, dest, EXCP_DEBUG);
    } else if (use_goto_tb(s, dest)) {
        tcg_gen_goto_tb(n);
        tcg_gen_movi_i32(QREG_PC, dest);
        tcg_gen_exit_tb(s->tb, n);
        tcg_gen_exit_tb(s->base.tb, n);
    } else {
        gen_jmp_im(s, dest);
        tcg_gen_exit_tb(NULL, 0);
    }
    s->is_jmp = DISAS_TB_JUMP;
    s->base.is_jmp = DISAS_NORETURN;
}

DISAS_INSN(scc)
@@ -1543,12 +1538,12 @@ DISAS_INSN(dbcc)

DISAS_INSN(undef_mac)
{
    gen_exception(s, s->insn_pc, EXCP_LINEA);
    gen_exception(s, s->base.pc_next, EXCP_LINEA);
}

DISAS_INSN(undef_fpu)
{
    gen_exception(s, s->insn_pc, EXCP_LINEF);
    gen_exception(s, s->base.pc_next, EXCP_LINEF);
}

DISAS_INSN(undef)
@@ -1557,8 +1552,8 @@ DISAS_INSN(undef)
       for the 680x0 series, as well as those that are implemented
       but actually illegal for CPU32 or pre-68020.  */
    qemu_log_mask(LOG_UNIMP, "Illegal instruction: %04x @ %08x\n",
                  insn, s->insn_pc);
    gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED);
                  insn, s->base.pc_next);
    gen_exception(s, s->base.pc_next, EXCP_UNSUPPORTED);
}

DISAS_INSN(mulw)
@@ -1618,7 +1613,7 @@ DISAS_INSN(divl)

    if (ext & 0x400) {
        if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
            gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
            gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
            return;
        }

@@ -2312,7 +2307,7 @@ DISAS_INSN(arith_im)
            break;
        case OS_WORD:
            if (IS_USER(s)) {
                gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
                gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
                return;
            }
            src1 = gen_get_sr(s);
@@ -2481,7 +2476,7 @@ DISAS_INSN(cas2w)
                         (REG(ext1, 6) << 3) |
                         (REG(ext2, 0) << 6) |
                         (REG(ext1, 0) << 9));
    if (tb_cflags(s->tb) & CF_PARALLEL) {
    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
        gen_helper_exit_atomic(cpu_env);
    } else {
        gen_helper_cas2w(cpu_env, regs, addr1, addr2);
@@ -2531,7 +2526,7 @@ DISAS_INSN(cas2l)
                         (REG(ext1, 6) << 3) |
                         (REG(ext2, 0) << 6) |
                         (REG(ext1, 0) << 9));
    if (tb_cflags(s->tb) & CF_PARALLEL) {
    if (tb_cflags(s->base.tb) & CF_PARALLEL) {
        gen_helper_cas2l_parallel(cpu_env, regs, addr1, addr2);
    } else {
        gen_helper_cas2l(cpu_env, regs, addr1, addr2);
@@ -2722,7 +2717,7 @@ DISAS_INSN(swap)

DISAS_INSN(bkpt)
{
    gen_exception(s, s->insn_pc, EXCP_DEBUG);
    gen_exception(s, s->base.pc_next, EXCP_DEBUG);
}

DISAS_INSN(pea)
@@ -2775,7 +2770,7 @@ DISAS_INSN(pulse)

DISAS_INSN(illegal)
{
    gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
    gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
}

/* ??? This should be atomic.  */
@@ -2805,7 +2800,7 @@ DISAS_INSN(mull)

    if (ext & 0x400) {
        if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
            gen_exception(s, s->insn_pc, EXCP_UNSUPPORTED);
            gen_exception(s, s->base.pc_next, EXCP_UNSUPPORTED);
            return;
        }

@@ -2906,7 +2901,7 @@ DISAS_INSN(unlk)
DISAS_INSN(reset)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4377,7 +4372,7 @@ DISAS_INSN(chk)
        }
        /* fallthru */
    default:
        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
        gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
        return;
    }
    SRC_EA(env, src, opsize, 1, NULL);
@@ -4404,13 +4399,13 @@ DISAS_INSN(chk2)
        opsize = OS_LONG;
        break;
    default:
        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
        gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
        return;
    }

    ext = read_im16(env, s);
    if ((ext & 0x0800) == 0) {
        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
        gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
        return;
    }

@@ -4470,7 +4465,7 @@ DISAS_INSN(move16_reg)

    ext = read_im16(env, s);
    if ((ext & (1 << 15)) == 0) {
        gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
        gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
    }

    m68k_copy_line(AREG(ext, 12), AREG(insn, 0), index);
@@ -4532,7 +4527,7 @@ DISAS_INSN(move_from_sr)
    TCGv sr;

    if (IS_USER(s) && !m68k_feature(env, M68K_FEATURE_M68000)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    sr = gen_get_sr(s);
@@ -4549,7 +4544,7 @@ DISAS_INSN(moves)
    int extend;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4602,17 +4597,17 @@ DISAS_INSN(moves)
DISAS_INSN(move_to_sr)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    gen_move_to_sr(env, s, insn, false);
    gen_lookup_tb(s);
    gen_exit_tb(s);
}

DISAS_INSN(move_from_usp)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    tcg_gen_ld_i32(AREG(insn, 0), cpu_env,
@@ -4622,7 +4617,7 @@ DISAS_INSN(move_from_usp)
DISAS_INSN(move_to_usp)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    tcg_gen_st_i32(AREG(insn, 0), cpu_env,
@@ -4632,7 +4627,7 @@ DISAS_INSN(move_to_usp)
DISAS_INSN(halt)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4644,7 +4639,7 @@ DISAS_INSN(stop)
    uint16_t ext;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4658,10 +4653,10 @@ DISAS_INSN(stop)
DISAS_INSN(rte)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    gen_exception(s, s->insn_pc, EXCP_RTE);
    gen_exception(s, s->base.pc_next, EXCP_RTE);
}

DISAS_INSN(cf_movec)
@@ -4670,7 +4665,7 @@ DISAS_INSN(cf_movec)
    TCGv reg;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4682,7 +4677,7 @@ DISAS_INSN(cf_movec)
        reg = DREG(ext, 12);
    }
    gen_helper_cf_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
    gen_lookup_tb(s);
    gen_exit_tb(s);
}

DISAS_INSN(m68k_movec)
@@ -4691,7 +4686,7 @@ DISAS_INSN(m68k_movec)
    TCGv reg;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4707,13 +4702,13 @@ DISAS_INSN(m68k_movec)
    } else {
        gen_helper_m68k_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff));
    }
    gen_lookup_tb(s);
    gen_exit_tb(s);
}

DISAS_INSN(intouch)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    /* ICache fetch.  Implement as no-op.  */
@@ -4722,7 +4717,7 @@ DISAS_INSN(intouch)
DISAS_INSN(cpushl)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    /* Cache push/invalidate.  Implement as no-op.  */
@@ -4731,7 +4726,7 @@ DISAS_INSN(cpushl)
DISAS_INSN(cpush)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    /* Cache push/invalidate.  Implement as no-op.  */
@@ -4740,7 +4735,7 @@ DISAS_INSN(cpush)
DISAS_INSN(cinv)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    /* Invalidate cache line.  Implement as no-op.  */
@@ -4752,7 +4747,7 @@ DISAS_INSN(pflush)
    TCGv opmode;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -4766,7 +4761,7 @@ DISAS_INSN(ptest)
    TCGv is_read;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    is_read = tcg_const_i32((insn >> 5) & 1);
@@ -4777,7 +4772,7 @@ DISAS_INSN(ptest)

DISAS_INSN(wddata)
{
    gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
    gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
}

DISAS_INSN(wdebug)
@@ -4785,7 +4780,7 @@ DISAS_INSN(wdebug)
    M68kCPU *cpu = m68k_env_get_cpu(env);

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    /* TODO: Implement wdebug.  */
@@ -4795,7 +4790,7 @@ DISAS_INSN(wdebug)

DISAS_INSN(trap)
{
    gen_exception(s, s->insn_pc, EXCP_TRAP0 + (insn & 0xf));
    gen_exception(s, s->base.pc_next, EXCP_TRAP0 + (insn & 0xf));
}

static void gen_load_fcr(DisasContext *s, TCGv res, int reg)
@@ -4862,7 +4857,7 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
    switch (mode) {
    case 0: /* Dn */
        if (mask != M68K_FPIAR && mask != M68K_FPSR && mask != M68K_FPCR) {
            gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
            gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
            return;
        }
        if (is_write) {
@@ -4873,7 +4868,7 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
        return;
    case 1: /* An, only with FPIAR */
        if (mask != M68K_FPIAR) {
            gen_exception(s, s->insn_pc, EXCP_ILLEGAL);
            gen_exception(s, s->base.pc_next, EXCP_ILLEGAL);
            return;
        }
        if (is_write) {
@@ -5431,7 +5426,7 @@ DISAS_INSN(frestore)
    TCGv addr;

    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }
    if (m68k_feature(s->env, M68K_FEATURE_M68040)) {
@@ -5445,7 +5440,7 @@ DISAS_INSN(frestore)
DISAS_INSN(fsave)
{
    if (IS_USER(s)) {
        gen_exception(s, s->insn_pc, EXCP_PRIVILEGE);
        gen_exception(s, s->base.pc_next, EXCP_PRIVILEGE);
        return;
    }

@@ -5751,7 +5746,7 @@ DISAS_INSN(to_macsr)
    TCGv val;
    SRC_EA(env, val, OS_LONG, 0, NULL);
    gen_helper_set_macsr(cpu_env, val);
    gen_lookup_tb(s);
    gen_exit_tb(s);
}

DISAS_INSN(to_mask)
@@ -6054,121 +6049,130 @@ void register_m68k_insns (CPUM68KState *env)
#undef INSN
}

/* ??? Some of this implementation is not exception safe.  We should always
   write back the result to memory before setting the condition codes.  */
static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
static void m68k_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
{
    uint16_t insn = read_im16(env, s);
    opcode_table[insn](env, s, insn);
    do_writebacks(s);
    do_release(s);
}

/* generate intermediate code for basic block 'tb'.  */
void gen_intermediate_code(CPUState *cs, TranslationBlock *tb)
{
    CPUM68KState *env = cs->env_ptr;
    DisasContext dc1, *dc = &dc1;
    target_ulong pc_start;
    int pc_offset;
    int num_insns;
    int max_insns;

    /* generate intermediate code */
    pc_start = tb->pc;

    dc->tb = tb;
    DisasContext *dc = container_of(dcbase, DisasContext, base);
    CPUM68KState *env = cpu->env_ptr;

    dc->env = env;
    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
    dc->pc = dc->base.pc_first;
    dc->cc_op = CC_OP_DYNAMIC;
    dc->cc_op_synced = 1;
    dc->singlestep_enabled = cs->singlestep_enabled;
    dc->done_mac = 0;
    dc->writeback_mask = 0;
    num_insns = 0;
    max_insns = tb_cflags(tb) & CF_COUNT_MASK;
    if (max_insns == 0) {
        max_insns = CF_COUNT_MASK;
    init_release_array(dc);
}
    if (max_insns > TCG_MAX_INSNS) {
        max_insns = TCG_MAX_INSNS;

static void m68k_tr_tb_start(DisasContextBase *dcbase, CPUState *cpu)
{
}

    init_release_array(dc);
static void m68k_tr_insn_start(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);
    tcg_gen_insn_start(dc->base.pc_next, dc->cc_op);
}

    gen_tb_start(tb);
    do {
        pc_offset = dc->pc - pc_start;
        tcg_gen_insn_start(dc->pc, dc->cc_op);
        num_insns++;
static bool m68k_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cpu,
                                     const CPUBreakpoint *bp)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);

        if (unlikely(cpu_breakpoint_test(cs, dc->pc, BP_ANY))) {
            gen_exception(dc, dc->pc, EXCP_DEBUG);
            dc->is_jmp = DISAS_JUMP;
    gen_exception(dc, dc->base.pc_next, EXCP_DEBUG);
    /* The address covered by the breakpoint must be included in
       [tb->pc, tb->pc + tb->size) in order to for it to be
       properly cleared -- thus we increment the PC here so that
       the logic setting tb->size below does the right thing.  */
            dc->pc += 2;
            break;
    dc->base.pc_next += 2;

    return true;
}

        if (num_insns == max_insns && (tb_cflags(tb) & CF_LAST_IO)) {
            gen_io_start();
static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);
    CPUM68KState *env = cpu->env_ptr;
    uint16_t insn = read_im16(env, dc);

    opcode_table[insn](env, dc, insn);
    do_writebacks(dc);
    do_release(dc);

    dc->base.pc_next = dc->pc;

    if (dc->base.is_jmp == DISAS_NEXT) {
        /* Stop translation when the next insn might touch a new page.
         * This ensures that prefetch aborts at the right place.
         *
         * We cannot determine the size of the next insn without
         * completely decoding it.  However, the maximum insn size
         * is 32 bytes, so end if we do not have that much remaining.
         * This may produce several small TBs at the end of each page,
         * but they will all be linked with goto_tb.
         *
         * ??? ColdFire maximum is 4 bytes; MC68000's maximum is also
         * smaller than MC68020's.
         */
        target_ulong start_page_offset
            = dc->pc - (dc->base.pc_first & TARGET_PAGE_MASK);

        if (start_page_offset >= TARGET_PAGE_SIZE - 32) {
            dc->base.is_jmp = DISAS_TOO_MANY;
        }
    }
}

        dc->insn_pc = dc->pc;
	disas_m68k_insn(env, dc);
    } while (!dc->is_jmp && !tcg_op_buf_full() &&
             !cs->singlestep_enabled &&
             !singlestep &&
             (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
             num_insns < max_insns);
static void m68k_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu)
{
    DisasContext *dc = container_of(dcbase, DisasContext, base);

    if (tb_cflags(tb) & CF_LAST_IO)
        gen_io_end();
    if (unlikely(cs->singlestep_enabled)) {
        /* Make sure the pc is updated, and raise a debug exception.  */
        if (!dc->is_jmp) {
            update_cc_op(dc);
            tcg_gen_movi_i32(QREG_PC, dc->pc);
    if (dc->base.is_jmp == DISAS_NORETURN) {
        return;
    }
    if (dc->base.singlestep_enabled) {
        gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG));
    } else {
        switch(dc->is_jmp) {
        case DISAS_NEXT:
        return;
    }

    switch (dc->base.is_jmp) {
    case DISAS_TOO_MANY:
        update_cc_op(dc);
        gen_jmp_tb(dc, 0, dc->pc);
        break;
        default:
    case DISAS_JUMP:
        case DISAS_UPDATE:
            update_cc_op(dc);
            /* indicate that the hash table must be used to find the next TB */
            tcg_gen_exit_tb(NULL, 0);
        /* We updated CC_OP and PC in gen_jmp/gen_jmp_im.  */
        tcg_gen_lookup_and_goto_ptr();
        break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
    case DISAS_EXIT:
        /* We updated CC_OP and PC in gen_exit_tb, but also modified
           other state that may require returning to the main loop.  */
        tcg_gen_exit_tb(NULL, 0);
        break;
    default:
        g_assert_not_reached();
    }
}
    gen_tb_end(tb, num_insns);

#ifdef DEBUG_DISAS
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
        && qemu_log_in_addr_range(pc_start)) {
        qemu_log_lock();
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(cs, pc_start, dc->pc - pc_start);
        qemu_log("\n");
        qemu_log_unlock();
static void m68k_tr_disas_log(const DisasContextBase *dcbase, CPUState *cpu)
{
    qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first));
    log_target_disas(cpu, dcbase->pc_first, dcbase->tb->size);
}
#endif
    tb->size = dc->pc - pc_start;
    tb->icount = num_insns;

static const TranslatorOps m68k_tr_ops = {
    .init_disas_context = m68k_tr_init_disas_context,
    .tb_start           = m68k_tr_tb_start,
    .insn_start         = m68k_tr_insn_start,
    .breakpoint_check   = m68k_tr_breakpoint_check,
    .translate_insn     = m68k_tr_translate_insn,
    .tb_stop            = m68k_tr_tb_stop,
    .disas_log          = m68k_tr_disas_log,
};

void gen_intermediate_code(CPUState *cpu, TranslationBlock *tb)
{
    DisasContext dc;
    translator_loop(&m68k_tr_ops, &dc.base, cpu, tb);
}

static double floatx80_to_double(CPUM68KState *env, uint16_t high, uint64_t low)