Include assert.h from qemu-common.h
[qemu] / target-m68k / translate.c
index eff3286..422f0a4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  m68k translation
- * 
+ *
  *  Copyright (c) 2005-2007 CodeSourcery
  *  Written by Paul Brook
  *
@@ -16,7 +16,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #include <stdarg.h>
 #include <stdlib.h>
 #include "cpu.h"
 #include "exec-all.h"
 #include "disas.h"
-#include "m68k-qreg.h"
+#include "tcg-op.h"
+#include "qemu-log.h"
+
+#include "helpers.h"
+#define GEN_HELPER 1
+#include "helpers.h"
 
 //#define DEBUG_DISPATCH 1
 
+/* Fake floating point.  */
+#define tcg_gen_mov_f64 tcg_gen_mov_i64
+#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
+#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
+
+#define DEFO32(name, offset) static TCGv QREG_##name;
+#define DEFO64(name, offset) static TCGv_i64 QREG_##name;
+#define DEFF64(name, offset) static TCGv_i64 QREG_##name;
+#include "qregs.def"
+#undef DEFO32
+#undef DEFO64
+#undef DEFF64
+
+static TCGv_ptr cpu_env;
+
+static char cpu_reg_names[3*8*3 + 5*4];
+static TCGv cpu_dregs[8];
+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 MACREG(acc) cpu_macc[acc]
+#define QREG_SP cpu_aregs[7]
+
+static TCGv NULL_QREG;
+#define IS_NULL_QREG(t) (TCGV_EQUAL(t, NULL_QREG))
+/* Used to distinguish stores from bad addressing modes.  */
+static TCGv store_dummy;
+
+#include "gen-icount.h"
+
+void m68k_tcg_init(void)
+{
+    char *p;
+    int i;
+
+#define DEFO32(name,  offset) QREG_##name = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, offset), #name);
+#define DEFO64(name,  offset) QREG_##name = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, offset), #name);
+#define DEFF64(name,  offset) DEFO64(name, offset)
+#include "qregs.def"
+#undef DEFO32
+#undef DEFO64
+#undef DEFF64
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    p = cpu_reg_names;
+    for (i = 0; i < 8; i++) {
+        sprintf(p, "D%d", i);
+        cpu_dregs[i] = tcg_global_mem_new(TCG_AREG0,
+                                          offsetof(CPUM68KState, dregs[i]), p);
+        p += 3;
+        sprintf(p, "A%d", i);
+        cpu_aregs[i] = tcg_global_mem_new(TCG_AREG0,
+                                          offsetof(CPUM68KState, aregs[i]), p);
+        p += 3;
+        sprintf(p, "F%d", i);
+        cpu_fregs[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                          offsetof(CPUM68KState, fregs[i]), p);
+        p += 3;
+    }
+    for (i = 0; i < 4; i++) {
+        sprintf(p, "ACC%d", i);
+        cpu_macc[i] = tcg_global_mem_new_i64(TCG_AREG0,
+                                         offsetof(CPUM68KState, macc[i]), p);
+        p += 5;
+    }
+
+    NULL_QREG = tcg_global_mem_new(TCG_AREG0, -4, "NULL");
+    store_dummy = tcg_global_mem_new(TCG_AREG0, -8, "NULL");
+
+#define GEN_HELPER 2
+#include "helpers.h"
+}
+
 static inline void qemu_assert(int cond, const char *msg)
 {
     if (!cond) {
@@ -42,6 +125,8 @@ static inline void qemu_assert(int cond, const char *msg)
 
 /* internal defines */
 typedef struct DisasContext {
+    CPUM68KState *env;
+    target_ulong insn_pc; /* Start of the current instruction.  */
     target_ulong pc;
     int is_jmp;
     int cc_op;
@@ -49,6 +134,9 @@ typedef struct DisasContext {
     uint32_t fpcr;
     struct TranslationBlock *tb;
     int singlestep_enabled;
+    int is_mem;
+    TCGv_i64 mactmp;
+    int done_mac;
 } DisasContext;
 
 #define DISAS_JUMP_NEXT 4
@@ -64,76 +152,19 @@ typedef struct DisasContext {
 static void *gen_throws_exception;
 #define gen_last_qop NULL
 
-static uint16_t *gen_opc_ptr;
-static uint32_t *gen_opparam_ptr;
-extern FILE *logfile;
-extern int loglevel;
-
-enum {
-#define DEF(s, n, copy_size) INDEX_op_ ## s,
-#include "opc.h"
-#undef DEF
-    NB_OPS,
-};
-
-#include "gen-op.h"
-
-#if defined(CONFIG_USER_ONLY)
-#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
-#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
-#else
-#define gen_st(s, name, addr, val) do { \
-    if (IS_USER(s)) \
-        gen_op_st##name##_user(addr, val); \
-    else \
-        gen_op_st##name##_kernel(addr, val); \
-    } while (0)
-#define gen_ld(s, name, val, addr) do { \
-    if (IS_USER(s)) \
-        gen_op_ld##name##_user(val, addr); \
-    else \
-        gen_op_ld##name##_kernel(val, addr); \
-    } while (0)
-#endif
-
-#include "op-hacks.h"
-
 #define OS_BYTE 0
 #define OS_WORD 1
 #define OS_LONG 2
 #define OS_SINGLE 4
 #define OS_DOUBLE 5
 
-#define DREG(insn, pos) (((insn >> pos) & 7) + QREG_D0)
-#define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0)
-#define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0)
-
-#define M68K_INSN_CF_A    (1 << 0)
-#define M68K_INSN_CF_B    (1 << 1)
-#define M68K_INSN_CF_C    (1 << 2)
-#define M68K_INSN_CF_MAC  (1 << 3)
-#define M68K_INSN_CF_EMAC (1 << 4)
-#define M68K_INSN_CF_FPU  (1 << 5)
-
-struct m68k_def_t {
-    const char * name;
-    uint32_t insns;
-};
-
-static m68k_def_t m68k_cpu_defs[] = {
-    {"m5206", M68K_INSN_CF_A},
-    {"cfv4e", M68K_INSN_CF_A | M68K_INSN_CF_B | M68K_INSN_CF_C
-            | M68K_INSN_CF_MAC | M68K_INSN_CF_EMAC | M68K_INSN_CF_FPU},
-    {NULL, 0}, 
-};
-
 typedef void (*disas_proc)(DisasContext *, uint16_t);
 
 #ifdef DEBUG_DISPATCH
 #define DISAS_INSN(name) \
   static void real_disas_##name (DisasContext *s, uint16_t insn); \
   static void disas_##name (DisasContext *s, uint16_t insn) { \
-    if (logfile) fprintf(logfile, "Dispatch " #name "\n"); \
+    qemu_log("Dispatch " #name "\n"); \
     real_disas_##name(s, insn); } \
   static void real_disas_##name (DisasContext *s, uint16_t insn)
 #else
@@ -141,37 +172,33 @@ typedef void (*disas_proc)(DisasContext *, uint16_t);
   static void disas_##name (DisasContext *s, uint16_t insn)
 #endif
 
+/* FIXME: Remove this.  */
+#define gen_im32(val) tcg_const_i32(val)
+
 /* Generate a load from the specified address.  Narrow values are
    sign extended to full register width.  */
-static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
+static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
 {
-    int tmp;
+    TCGv tmp;
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tmp = tcg_temp_new_i32();
     switch(opsize) {
     case OS_BYTE:
-        tmp = gen_new_qreg(QMODE_I32);
         if (sign)
-            gen_ld(s, 8s32, tmp, addr);
+            tcg_gen_qemu_ld8s(tmp, addr, index);
         else
-            gen_ld(s, 8u32, tmp, addr);
+            tcg_gen_qemu_ld8u(tmp, addr, index);
         break;
     case OS_WORD:
-        tmp = gen_new_qreg(QMODE_I32);
         if (sign)
-            gen_ld(s, 16s32, tmp, addr);
+            tcg_gen_qemu_ld16s(tmp, addr, index);
         else
-            gen_ld(s, 16u32, tmp, addr);
+            tcg_gen_qemu_ld16u(tmp, addr, index);
         break;
     case OS_LONG:
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_ld(s, 32, tmp, addr);
-        break;
     case OS_SINGLE:
-        tmp = gen_new_qreg(QMODE_F32);
-        gen_ld(s, f32, tmp, addr);
-        break;
-    case OS_DOUBLE:
-        tmp  = gen_new_qreg(QMODE_F64);
-        gen_ld(s, f64, tmp, addr);
+        tcg_gen_qemu_ld32u(tmp, addr, index);
         break;
     default:
         qemu_assert(0, "bad load size");
@@ -180,24 +207,32 @@ static inline int gen_load(DisasContext * s, int opsize, int addr, int sign)
     return tmp;
 }
 
+static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr)
+{
+    TCGv_i64 tmp;
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tmp = tcg_temp_new_i64();
+    tcg_gen_qemu_ldf64(tmp, addr, index);
+    gen_throws_exception = gen_last_qop;
+    return tmp;
+}
+
 /* Generate a store.  */
-static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
+static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
 {
+    int index = IS_USER(s);
+    s->is_mem = 1;
     switch(opsize) {
     case OS_BYTE:
-        gen_st(s, 8, addr, val);
+        tcg_gen_qemu_st8(val, addr, index);
         break;
     case OS_WORD:
-        gen_st(s, 16, addr, val);
+        tcg_gen_qemu_st16(val, addr, index);
         break;
     case OS_LONG:
-        gen_st(s, 32, addr, val);
-        break;
     case OS_SINGLE:
-        gen_st(s, f32, addr, val);
-        break;
-    case OS_DOUBLE:
-        gen_st(s, f64, addr, val);
+        tcg_gen_qemu_st32(val, addr, index);
         break;
     default:
         qemu_assert(0, "bad store size");
@@ -205,50 +240,33 @@ static inline void gen_store(DisasContext *s, int opsize, int addr, int val)
     gen_throws_exception = gen_last_qop;
 }
 
+static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val)
+{
+    int index = IS_USER(s);
+    s->is_mem = 1;
+    tcg_gen_qemu_stf64(val, addr, index);
+    gen_throws_exception = gen_last_qop;
+}
+
+typedef enum {
+    EA_STORE,
+    EA_LOADU,
+    EA_LOADS
+} ea_what;
+
 /* Generate an unsigned load if VAL is 0 a signed load if val is -1,
    otherwise generate a store.  */
-static int gen_ldst(DisasContext *s, int opsize, int addr, int val)
+static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
+                     ea_what what)
 {
-    if (val > 0) {
+    if (what == EA_STORE) {
         gen_store(s, opsize, addr, val);
-        return 0;
+        return store_dummy;
     } else {
-        return gen_load(s, opsize, addr, val != 0);
+        return gen_load(s, opsize, addr, what == EA_LOADS);
     }
 }
 
-/* Handle a base + index + displacement effective addresss.  A base of
-   -1 means pc-relative.  */
-static int gen_lea_indexed(DisasContext *s, int opsize, int base)
-{
-    int scale;
-    uint32_t offset;
-    uint16_t ext;
-    int add;
-    int tmp;
-
-    offset = s->pc;
-    ext = lduw_code(s->pc);
-    s->pc += 2;
-    tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);
-    /* ??? Check W/L bit.  */
-    scale = (ext >> 9) & 3;
-    if (scale == 0) {
-        add = tmp;
-    } else {
-        add = gen_new_qreg(QMODE_I32);
-        gen_op_shl32(add, tmp, gen_im32(scale));
-    }
-    tmp = gen_new_qreg(QMODE_I32);
-    if (base != -1) {
-        gen_op_add32(tmp, base, gen_im32((int8_t)ext));
-        gen_op_add32(tmp, tmp, add);
-    } else {
-        gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));
-    }
-    return tmp;
-}
-
 /* Read a 32-bit immediate constant.  */
 static inline uint32_t read_im32(DisasContext *s)
 {
@@ -260,12 +278,133 @@ static inline uint32_t read_im32(DisasContext *s)
     return im;
 }
 
+/* Calculate and address index.  */
+static TCGv gen_addr_index(uint16_t ext, TCGv tmp)
+{
+    TCGv add;
+    int scale;
+
+    add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
+    if ((ext & 0x800) == 0) {
+        tcg_gen_ext16s_i32(tmp, add);
+        add = tmp;
+    }
+    scale = (ext >> 9) & 3;
+    if (scale != 0) {
+        tcg_gen_shli_i32(tmp, add, scale);
+        add = tmp;
+    }
+    return add;
+}
+
+/* Handle a base + index + displacement effective addresss.
+   A NULL_QREG base means pc-relative.  */
+static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base)
+{
+    uint32_t offset;
+    uint16_t ext;
+    TCGv add;
+    TCGv tmp;
+    uint32_t bd, od;
+
+    offset = s->pc;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
+        return NULL_QREG;
+
+    if (ext & 0x100) {
+        /* full extension word format */
+        if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
+            return NULL_QREG;
+
+        if ((ext & 0x30) > 0x10) {
+            /* base displacement */
+            if ((ext & 0x30) == 0x20) {
+                bd = (int16_t)lduw_code(s->pc);
+                s->pc += 2;
+            } else {
+                bd = read_im32(s);
+            }
+        } else {
+            bd = 0;
+        }
+        tmp = tcg_temp_new();
+        if ((ext & 0x44) == 0) {
+            /* pre-index */
+            add = gen_addr_index(ext, tmp);
+        } else {
+            add = NULL_QREG;
+        }
+        if ((ext & 0x80) == 0) {
+            /* base not suppressed */
+            if (IS_NULL_QREG(base)) {
+                base = gen_im32(offset + bd);
+                bd = 0;
+            }
+            if (!IS_NULL_QREG(add)) {
+                tcg_gen_add_i32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+        }
+        if (!IS_NULL_QREG(add)) {
+            if (bd != 0) {
+                tcg_gen_addi_i32(tmp, add, bd);
+                add = tmp;
+            }
+        } else {
+            add = gen_im32(bd);
+        }
+        if ((ext & 3) != 0) {
+            /* memory indirect */
+            base = gen_load(s, OS_LONG, add, 0);
+            if ((ext & 0x44) == 4) {
+                add = gen_addr_index(ext, tmp);
+                tcg_gen_add_i32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+            if ((ext & 3) > 1) {
+                /* outer displacement */
+                if ((ext & 3) == 2) {
+                    od = (int16_t)lduw_code(s->pc);
+                    s->pc += 2;
+                } else {
+                    od = read_im32(s);
+                }
+            } else {
+                od = 0;
+            }
+            if (od != 0) {
+                tcg_gen_addi_i32(tmp, add, od);
+                add = tmp;
+            }
+        }
+    } else {
+        /* brief extension word format */
+        tmp = tcg_temp_new();
+        add = gen_addr_index(ext, tmp);
+        if (!IS_NULL_QREG(base)) {
+            tcg_gen_add_i32(tmp, add, base);
+            if ((int8_t)ext)
+                tcg_gen_addi_i32(tmp, tmp, (int8_t)ext);
+        } else {
+            tcg_gen_addi_i32(tmp, add, offset + (int8_t)ext);
+        }
+        add = tmp;
+    }
+    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)
-        gen_op_mov32(QREG_CC_OP, gen_im32(s->cc_op));
+        tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
 }
 
 /* Evaluate all the CC flags.  */
@@ -273,10 +412,23 @@ static inline void gen_flush_flags(DisasContext *s)
 {
     if (s->cc_op == CC_OP_FLAGS)
         return;
-    gen_op_flush_flags(s->cc_op);
+    gen_flush_cc_op(s);
+    gen_helper_flush_flags(cpu_env, QREG_CC_OP);
     s->cc_op = CC_OP_FLAGS;
 }
 
+static void gen_logic_cc(DisasContext *s, TCGv val)
+{
+    tcg_gen_mov_i32(QREG_CC_DEST, val);
+    s->cc_op = 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);
+}
+
 static inline int opsize_bytes(int opsize)
 {
     switch (opsize) {
@@ -287,32 +439,31 @@ static inline int opsize_bytes(int opsize)
     case OS_DOUBLE: return 8;
     default:
         qemu_assert(0, "bad operand size");
+        return 0;
     }
 }
 
 /* Assign value to a register.  If the width is less than the register width
    only the low part of the register is set.  */
-static void gen_partset_reg(int opsize, int reg, int val)
+static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
 {
-    int tmp;
+    TCGv tmp;
     switch (opsize) {
     case OS_BYTE:
-        gen_op_and32(reg, reg, gen_im32(0xffffff00));
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, val, gen_im32(0xff));
-        gen_op_or32(reg, reg, tmp);
+        tcg_gen_andi_i32(reg, reg, 0xffffff00);
+        tmp = tcg_temp_new();
+        tcg_gen_ext8u_i32(tmp, val);
+        tcg_gen_or_i32(reg, reg, tmp);
         break;
     case OS_WORD:
-        gen_op_and32(reg, reg, gen_im32(0xffff0000));
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, val, gen_im32(0xffff));
-        gen_op_or32(reg, reg, tmp);
+        tcg_gen_andi_i32(reg, reg, 0xffff0000);
+        tmp = tcg_temp_new();
+        tcg_gen_ext16u_i32(tmp, val);
+        tcg_gen_or_i32(reg, reg, tmp);
         break;
     case OS_LONG:
-        gen_op_mov32(reg, val);
-        break;
     case OS_SINGLE:
-        gen_op_pack_32_f32(reg, val);
+        tcg_gen_mov_i32(reg, val);
         break;
     default:
         qemu_assert(0, "Bad operand size");
@@ -321,31 +472,28 @@ static void gen_partset_reg(int opsize, int reg, int val)
 }
 
 /* Sign or zero extend a value.  */
-static inline int gen_extend(int val, int opsize, int sign)
+static inline TCGv gen_extend(TCGv val, int opsize, int sign)
 {
-    int tmp;
+    TCGv tmp;
 
     switch (opsize) {
     case OS_BYTE:
-        tmp = gen_new_qreg(QMODE_I32);
+        tmp = tcg_temp_new();
         if (sign)
-            gen_op_ext8s32(tmp, val);
+            tcg_gen_ext8s_i32(tmp, val);
         else
-            gen_op_ext8u32(tmp, val);
+            tcg_gen_ext8u_i32(tmp, val);
         break;
     case OS_WORD:
-        tmp = gen_new_qreg(QMODE_I32);
+        tmp = tcg_temp_new();
         if (sign)
-            gen_op_ext16s32(tmp, val);
+            tcg_gen_ext16s_i32(tmp, val);
         else
-            gen_op_ext16u32(tmp, val);
+            tcg_gen_ext16u_i32(tmp, val);
         break;
     case OS_LONG:
-        tmp = val;
-        break;
     case OS_SINGLE:
-        tmp = gen_new_qreg(QMODE_F32);
-        gen_op_pack_f32_32(tmp, val);
+        tmp = val;
         break;
     default:
         qemu_assert(0, "Bad operand size");
@@ -354,41 +502,38 @@ static inline int gen_extend(int val, int opsize, int sign)
 }
 
 /* Generate code for an "effective address".  Does not adjust the base
-   register for autoincrememnt addressing modes.  */
-static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
+   register for autoincrement addressing modes.  */
+static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize)
 {
-    int reg;
-    int tmp;
+    TCGv reg;
+    TCGv tmp;
     uint16_t ext;
     uint32_t offset;
 
-    reg = insn & 7;
     switch ((insn >> 3) & 7) {
     case 0: /* Data register direct.  */
     case 1: /* Address register direct.  */
-        /* ??? generate bad addressing mode fault.  */
-        qemu_assert(0, "invalid addressing mode");
+        return NULL_QREG;
     case 2: /* Indirect register */
     case 3: /* Indirect postincrement.  */
-        reg += QREG_A0;
-        return reg;
+        return AREG(insn, 0);
     case 4: /* Indirect predecrememnt.  */
-        reg += QREG_A0;
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_sub32(tmp, reg, gen_im32(opsize_bytes(opsize)));
+        reg = AREG(insn, 0);
+        tmp = tcg_temp_new();
+        tcg_gen_subi_i32(tmp, reg, opsize_bytes(opsize));
         return tmp;
     case 5: /* Indirect displacement.  */
-        reg += QREG_A0;
-        tmp = gen_new_qreg(QMODE_I32);
+        reg = AREG(insn, 0);
+        tmp = tcg_temp_new();
         ext = lduw_code(s->pc);
         s->pc += 2;
-        gen_op_add32(tmp, reg, gen_im32((int16_t)ext));
+        tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
         return tmp;
     case 6: /* Indirect index + displacement.  */
-        reg += QREG_A0;
+        reg = AREG(insn, 0);
         return gen_lea_indexed(s, opsize, reg);
     case 7: /* Other */
-        switch (reg) {
+        switch (insn & 7) {
         case 0: /* Absolute short.  */
             offset = ldsw_code(s->pc);
             s->pc += 2;
@@ -397,120 +542,122 @@ static int gen_lea(DisasContext *s, uint16_t insn, int opsize)
             offset = read_im32(s);
             return gen_im32(offset);
         case 2: /* pc displacement  */
-            tmp = gen_new_qreg(QMODE_I32);
+            tmp = tcg_temp_new();
             offset = s->pc;
             offset += ldsw_code(s->pc);
             s->pc += 2;
             return gen_im32(offset);
         case 3: /* pc index+displacement.  */
-            return gen_lea_indexed(s, opsize, -1);
+            return gen_lea_indexed(s, opsize, NULL_QREG);
         case 4: /* Immediate.  */
         default:
-            /* ??? generate bad addressing mode fault.  */
-            qemu_assert(0, "invalid addressing mode");
+            return NULL_QREG;
         }
     }
     /* Should never happen.  */
-    return -1;
+    return NULL_QREG;
 }
 
 /* Helper function for gen_ea. Reuse the computed address between the
    for read/write operands.  */
-static inline int gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
-                              int val, int *addrp)
+static inline TCGv gen_ea_once(DisasContext *s, uint16_t insn, int opsize,
+                              TCGv val, TCGv *addrp, ea_what what)
 {
-    int tmp;
+    TCGv tmp;
 
-    if (addrp && val > 0) {
+    if (addrp && what == EA_STORE) {
         tmp = *addrp;
     } else {
         tmp = gen_lea(s, insn, opsize);
+        if (IS_NULL_QREG(tmp))
+            return tmp;
         if (addrp)
             *addrp = tmp;
     }
-    return gen_ldst(s, opsize, tmp, val);
+    return gen_ldst(s, opsize, tmp, val, what);
 }
 
 /* Generate code to load/store a value ito/from an EA.  If VAL > 0 this is
    a write otherwise it is a read (0 == sign extend, -1 == zero extend).
    ADDRP is non-null for readwrite operands.  */
-static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
-                  int *addrp)
+static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val,
+                   TCGv *addrp, ea_what what)
 {
-    int reg;
-    int result;
+    TCGv reg;
+    TCGv result;
     uint32_t offset;
 
-    reg = insn & 7;
     switch ((insn >> 3) & 7) {
     case 0: /* Data register direct.  */
-        reg += QREG_D0;
-        if (val > 0) {
+        reg = DREG(insn, 0);
+        if (what == EA_STORE) {
             gen_partset_reg(opsize, reg, val);
-            return 0;
+            return store_dummy;
         } else {
-            return gen_extend(reg, opsize, val);
+            return gen_extend(reg, opsize, what == EA_LOADS);
         }
     case 1: /* Address register direct.  */
-        reg += QREG_A0;
-        if (val > 0) {
-            gen_op_mov32(reg, val);
-            return 0;
+        reg = AREG(insn, 0);
+        if (what == EA_STORE) {
+            tcg_gen_mov_i32(reg, val);
+            return store_dummy;
         } else {
-            return gen_extend(reg, opsize, val);
+            return gen_extend(reg, opsize, what == EA_LOADS);
         }
     case 2: /* Indirect register */
-        reg += QREG_A0;
-        return gen_ldst(s, opsize, reg, val);
+        reg = AREG(insn, 0);
+        return gen_ldst(s, opsize, reg, val, what);
     case 3: /* Indirect postincrement.  */
-        reg += QREG_A0;
-        result = gen_ldst(s, opsize, reg, val);
+        reg = AREG(insn, 0);
+        result = gen_ldst(s, opsize, reg, val, what);
         /* ??? This is not exception safe.  The instruction may still
            fault after this point.  */
-        if (val > 0 || !addrp)
-            gen_op_add32(reg, reg, gen_im32(opsize_bytes(opsize)));
+        if (what == EA_STORE || !addrp)
+            tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
         return result;
     case 4: /* Indirect predecrememnt.  */
         {
-            int tmp;
-            if (addrp && val > 0) {
+            TCGv tmp;
+            if (addrp && what == EA_STORE) {
                 tmp = *addrp;
             } else {
                 tmp = gen_lea(s, insn, opsize);
+                if (IS_NULL_QREG(tmp))
+                    return tmp;
                 if (addrp)
                     *addrp = tmp;
             }
-            result = gen_ldst(s, opsize, tmp, val);
+            result = gen_ldst(s, opsize, tmp, val, what);
             /* ??? This is not exception safe.  The instruction may still
                fault after this point.  */
-            if (val > 0 || !addrp) {
-                reg += QREG_A0;
-                gen_op_mov32(reg, tmp);
+            if (what == EA_STORE || !addrp) {
+                reg = AREG(insn, 0);
+                tcg_gen_mov_i32(reg, tmp);
             }
         }
         return result;
     case 5: /* Indirect displacement.  */
     case 6: /* Indirect index + displacement.  */
-        return gen_ea_once(s, insn, opsize, val, addrp);
+        return gen_ea_once(s, insn, opsize, val, addrp, what);
     case 7: /* Other */
-        switch (reg) {
+        switch (insn & 7) {
         case 0: /* Absolute short.  */
         case 1: /* Absolute long.  */
         case 2: /* pc displacement  */
         case 3: /* pc index+displacement.  */
-            return gen_ea_once(s, insn, opsize, val, addrp);
+            return gen_ea_once(s, insn, opsize, val, addrp, what);
         case 4: /* Immediate.  */
             /* Sign extend values for consistency.  */
             switch (opsize) {
             case OS_BYTE:
-                if (val)
+                if (what == EA_LOADS)
                     offset = ldsb_code(s->pc + 1);
                 else
                     offset = ldub_code(s->pc + 1);
                 s->pc += 2;
                 break;
             case OS_WORD:
-                if (val)
+                if (what == EA_LOADS)
                     offset = ldsw_code(s->pc);
                 else
                     offset = lduw_code(s->pc);
@@ -522,121 +669,112 @@ static int gen_ea(DisasContext *s, uint16_t insn, int opsize, int val,
             default:
                 qemu_assert(0, "Bad immediate operand");
             }
-            return gen_im32(offset);
+            return tcg_const_i32(offset);
         default:
-            qemu_assert(0, "invalid addressing mode");
+            return NULL_QREG;
         }
     }
     /* Should never happen.  */
-    return -1;
-}
-
-static void gen_logic_cc(DisasContext *s, int val)
-{
-    gen_op_logic_cc(val);
-    s->cc_op = CC_OP_LOGIC;
+    return NULL_QREG;
 }
 
+/* This generates a conditional branch, clobbering all temporaries.  */
 static void gen_jmpcc(DisasContext *s, int cond, int l1)
 {
-    int tmp;
+    TCGv tmp;
 
+    /* TODO: Optimize compare/branch pairs rather than always flushing
+       flag state to CC_OP_FLAGS.  */
     gen_flush_flags(s);
     switch (cond) {
     case 0: /* T */
-        gen_op_jmp(l1);
+        tcg_gen_br(l1);
         break;
     case 1: /* F */
         break;
     case 2: /* HI (!C && !Z) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
-        gen_op_jmp_z32(tmp, l1);
+        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;
     case 3: /* LS (C || Z) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C | CCF_Z));
-        gen_op_jmp_nz32(tmp, l1);
+        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);
         break;
     case 4: /* CC (!C) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
-        gen_op_jmp_z32(tmp, l1);
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_C));
-        gen_op_jmp_nz32(tmp, l1);
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_C);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
         break;
     case 6: /* NE (!Z) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
-        gen_op_jmp_z32(tmp, l1);
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
-        gen_op_jmp_nz32(tmp, l1);
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_Z);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
         break;
     case 8: /* VC (!V) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
-        gen_op_jmp_z32(tmp, l1);
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
-        gen_op_jmp_nz32(tmp, l1);
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_V);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
         break;
     case 10: /* PL (!N) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
-        gen_op_jmp_z32(tmp, l1);
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_N));
-        gen_op_jmp_nz32(tmp, l1);
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_CC_DEST, CCF_N);
+        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, l1);
         break;
     case 12: /* GE (!(N ^ V)) */
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
-        gen_op_xor32(tmp, tmp, QREG_CC_DEST);
-        gen_op_and32(tmp, tmp, gen_im32(CCF_V));
-        gen_op_jmp_z32(tmp, l1);
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
-        gen_op_xor32(tmp, tmp, QREG_CC_DEST);
-        gen_op_and32(tmp, tmp, gen_im32(CCF_V));
-        gen_op_jmp_nz32(tmp, l1);
+        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);
         break;
     case 14: /* GT (!(Z || (N ^ V))) */
-        {
-            int l2;
-            l2 = gen_new_label();
-            tmp = gen_new_qreg(QMODE_I32);
-            gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
-            gen_op_jmp_nz32(tmp, l2);
-            tmp = gen_new_qreg(QMODE_I32);
-            gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
-            gen_op_xor32(tmp, tmp, QREG_CC_DEST);
-            gen_op_and32(tmp, tmp, gen_im32(CCF_V));
-            gen_op_jmp_nz32(tmp, l2);
-            gen_op_jmp(l1);
-            gen_set_label(l2);
-        }
+        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 = gen_new_qreg(QMODE_I32);
-        gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_Z));
-        gen_op_jmp_nz32(tmp, l1);
-        tmp = gen_new_qreg(QMODE_I32);
-        gen_op_shr32(tmp, QREG_CC_DEST, gen_im32(2));
-        gen_op_xor32(tmp, tmp, QREG_CC_DEST);
-        gen_op_and32(tmp, tmp, gen_im32(CCF_V));
-        gen_op_jmp_nz32(tmp, l1);
+        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);
         break;
     default:
         /* Should ever happen.  */
@@ -648,14 +786,16 @@ DISAS_INSN(scc)
 {
     int l1;
     int cond;
-    int reg;
+    TCGv reg;
 
     l1 = gen_new_label();
     cond = (insn >> 8) & 0xf;
     reg = DREG(insn, 0);
-    gen_op_and32(reg, reg, gen_im32(0xffffff00));
+    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);
-    gen_op_or32(reg, reg, gen_im32(0xff));
+    tcg_gen_ori_i32(reg, reg, 0xff);
     gen_set_label(l1);
 }
 
@@ -663,43 +803,70 @@ DISAS_INSN(scc)
 static void gen_lookup_tb(DisasContext *s)
 {
     gen_flush_cc_op(s);
-    gen_op_mov32(QREG_PC, gen_im32(s->pc));
+    tcg_gen_movi_i32(QREG_PC, s->pc);
     s->is_jmp = DISAS_UPDATE;
 }
 
-/* Generate a jump to to the address in qreg DEST.  */
-static void gen_jmp(DisasContext *s, int dest)
+/* Generate a jump to an immediate address.  */
+static void gen_jmp_im(DisasContext *s, uint32_t dest)
 {
     gen_flush_cc_op(s);
-    gen_op_mov32(QREG_PC, dest);
+    tcg_gen_movi_i32(QREG_PC, dest);
+    s->is_jmp = DISAS_JUMP;
+}
+
+/* Generate a jump to the address in qreg DEST.  */
+static void gen_jmp(DisasContext *s, TCGv dest)
+{
+    gen_flush_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);
-    gen_jmp(s, gen_im32(where));
-    gen_op_raise_exception(nr);
+    gen_jmp_im(s, where);
+    gen_helper_raise_exception(tcg_const_i32(nr));
 }
 
+static inline void gen_addr_fault(DisasContext *s)
+{
+    gen_exception(s, s->insn_pc, EXCP_ADDRESS);
+}
+
+#define SRC_EA(result, opsize, op_sign, addrp) do { \
+    result = gen_ea(s, insn, opsize, NULL_QREG, addrp, op_sign ? EA_LOADS : EA_LOADU); \
+    if (IS_NULL_QREG(result)) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
+#define DEST_EA(insn, opsize, val, addrp) do { \
+    TCGv ea_result = gen_ea(s, insn, opsize, val, addrp, EA_STORE); \
+    if (IS_NULL_QREG(ea_result)) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
 /* Generate a jump to an immediate address.  */
 static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
 {
     TranslationBlock *tb;
 
     tb = s->tb;
-    if (__builtin_expect (s->singlestep_enabled, 0)) {
+    if (unlikely(s->singlestep_enabled)) {
         gen_exception(s, dest, EXCP_DEBUG);
     } else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
                (s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
-        gen_op_goto_tb(0, n, (long)tb);
-        gen_op_mov32(QREG_PC, gen_im32(dest));
-        gen_op_mov32(QREG_T0, gen_im32((long)tb + n));
-        gen_op_exit_tb();
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_i32(QREG_PC, dest);
+        tcg_gen_exit_tb((long)tb + n);
     } else {
-        gen_jmp(s, gen_im32(dest));
-        gen_op_mov32(QREG_T0, gen_im32(0));
-        gen_op_exit_tb();
+        gen_jmp_im(s, dest);
+        tcg_gen_exit_tb(0);
     }
     s->is_jmp = DISAS_TB_JUMP;
 }
@@ -723,61 +890,60 @@ DISAS_INSN(undef)
 
 DISAS_INSN(mulw)
 {
-    int reg;
-    int tmp;
-    int src;
+    TCGv reg;
+    TCGv tmp;
+    TCGv src;
     int sign;
 
     sign = (insn & 0x100) != 0;
     reg = DREG(insn, 9);
-    tmp = gen_new_qreg(QMODE_I32);
+    tmp = tcg_temp_new();
     if (sign)
-        gen_op_ext16s32(tmp, reg);
+        tcg_gen_ext16s_i32(tmp, reg);
     else
-        gen_op_ext16u32(tmp, reg);
-    src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
-    gen_op_mul32(tmp, tmp, src);
-    gen_op_mov32(reg, tmp);
+        tcg_gen_ext16u_i32(tmp, reg);
+    SRC_EA(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);
 }
 
 DISAS_INSN(divw)
 {
-    int reg;
-    int tmp;
-    int src;
+    TCGv reg;
+    TCGv tmp;
+    TCGv src;
     int sign;
 
     sign = (insn & 0x100) != 0;
     reg = DREG(insn, 9);
     if (sign) {
-        gen_op_ext16s32(QREG_DIV1, reg);
+        tcg_gen_ext16s_i32(QREG_DIV1, reg);
     } else {
-        gen_op_ext16u32(QREG_DIV1, reg);
+        tcg_gen_ext16u_i32(QREG_DIV1, reg);
     }
-    src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
-    gen_op_mov32(QREG_DIV2, src);
+    SRC_EA(src, OS_WORD, sign, NULL);
+    tcg_gen_mov_i32(QREG_DIV2, src);
     if (sign) {
-        gen_op_divs(1);
+        gen_helper_divs(cpu_env, tcg_const_i32(1));
     } else {
-        gen_op_divu(1);
+        gen_helper_divu(cpu_env, tcg_const_i32(1));
     }
 
-    tmp = gen_new_qreg(QMODE_I32);
-    src = gen_new_qreg(QMODE_I32);
-    gen_op_ext16u32(tmp, QREG_DIV1);
-    gen_op_shl32(src, QREG_DIV2, gen_im32(16));
-    gen_op_or32(reg, tmp, src);
-    gen_op_flags_set();
+    tmp = tcg_temp_new();
+    src = tcg_temp_new();
+    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;
 }
 
 DISAS_INSN(divl)
 {
-    int num;
-    int den;
-    int reg;
+    TCGv num;
+    TCGv den;
+    TCGv reg;
     uint16_t ext;
 
     ext = lduw_code(s->pc);
@@ -788,58 +954,57 @@ DISAS_INSN(divl)
     }
     num = DREG(ext, 12);
     reg = DREG(ext, 0);
-    gen_op_mov32(QREG_DIV1, num);
-    den = gen_ea(s, insn, OS_LONG, 0, NULL);
-    gen_op_mov32(QREG_DIV2, den);
+    tcg_gen_mov_i32(QREG_DIV1, num);
+    SRC_EA(den, OS_LONG, 0, NULL);
+    tcg_gen_mov_i32(QREG_DIV2, den);
     if (ext & 0x0800) {
-        gen_op_divs(2);
+        gen_helper_divs(cpu_env, tcg_const_i32(0));
     } else {
-        gen_op_divu(2);
+        gen_helper_divu(cpu_env, tcg_const_i32(0));
     }
-    if (num == reg) {
+    if ((ext & 7) == ((ext >> 12) & 7)) {
         /* div */
-        gen_op_mov32 (reg, QREG_DIV1);
+        tcg_gen_mov_i32 (reg, QREG_DIV1);
     } else {
         /* rem */
-        gen_op_mov32 (reg, QREG_DIV2);
+        tcg_gen_mov_i32 (reg, QREG_DIV2);
     }
-    gen_op_flags_set();
     s->cc_op = CC_OP_FLAGS;
 }
 
 DISAS_INSN(addsub)
 {
-    int reg;
-    int dest;
-    int src;
-    int tmp;
-    int addr;
+    TCGv reg;
+    TCGv dest;
+    TCGv src;
+    TCGv tmp;
+    TCGv addr;
     int add;
 
     add = (insn & 0x4000) != 0;
     reg = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
+    dest = tcg_temp_new();
     if (insn & 0x100) {
-        tmp = gen_ea(s, insn, OS_LONG, 0, &addr);
+        SRC_EA(tmp, OS_LONG, 0, &addr);
         src = reg;
     } else {
         tmp = reg;
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
+        SRC_EA(src, OS_LONG, 0, NULL);
     }
     if (add) {
-        gen_op_add32(dest, tmp, src);
-        gen_op_update_xflag_lt(dest, src);
+        tcg_gen_add_i32(dest, tmp, src);
+        gen_helper_xflag_lt(QREG_CC_X, dest, src);
         s->cc_op = CC_OP_ADD;
     } else {
-        gen_op_update_xflag_lt(tmp, src);
-        gen_op_sub32(dest, tmp, src);
+        gen_helper_xflag_lt(QREG_CC_X, tmp, src);
+        tcg_gen_sub_i32(dest, tmp, src);
         s->cc_op = CC_OP_SUB;
     }
-    gen_op_update_cc_add(dest, src);
+    gen_update_cc_add(dest, src);
     if (insn & 0x100) {
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
-        gen_op_mov32(reg, dest);
+        tcg_gen_mov_i32(reg, dest);
     }
 }
 
@@ -847,131 +1012,101 @@ DISAS_INSN(addsub)
 /* Reverse the order of the bits in REG.  */
 DISAS_INSN(bitrev)
 {
-    int val;
-    int tmp1;
-    int tmp2;
-    int reg;
-
-    val = gen_new_qreg(QMODE_I32);
-    tmp1 = gen_new_qreg(QMODE_I32);
-    tmp2 = gen_new_qreg(QMODE_I32);
+    TCGv reg;
     reg = DREG(insn, 0);
-    gen_op_mov32(val, reg);
-    /* Reverse bits within each nibble.  */
-    gen_op_shl32(tmp1, val, gen_im32(3));
-    gen_op_and32(tmp1, tmp1, gen_im32(0x88888888));
-    gen_op_shl32(tmp2, val, gen_im32(1));
-    gen_op_and32(tmp2, tmp2, gen_im32(0x44444444));
-    gen_op_or32(tmp1, tmp1, tmp2);
-    gen_op_shr32(tmp2, val, gen_im32(1));
-    gen_op_and32(tmp2, tmp2, gen_im32(0x22222222));
-    gen_op_or32(tmp1, tmp1, tmp2);
-    gen_op_shr32(tmp2, val, gen_im32(3));
-    gen_op_and32(tmp2, tmp2, gen_im32(0x11111111));
-    gen_op_or32(tmp1, tmp1, tmp2);
-    /* Reverse nibbles withing bytes.  */
-    gen_op_shl32(val, tmp1, gen_im32(4));
-    gen_op_and32(val, val, gen_im32(0xf0f0f0f0));
-    gen_op_shr32(tmp2, tmp1, gen_im32(4));
-    gen_op_and32(tmp2, tmp2, gen_im32(0x0f0f0f0f));
-    gen_op_or32(val, val, tmp2);
-    /* Reverse bytes.  */
-    gen_op_bswap32(reg, val);
-    gen_op_mov32(reg, val);
+    gen_helper_bitrev(reg, reg);
 }
 
 DISAS_INSN(bitop_reg)
 {
     int opsize;
     int op;
-    int src1;
-    int src2;
-    int tmp;
-    int addr;
-    int dest;
+    TCGv src1;
+    TCGv src2;
+    TCGv tmp;
+    TCGv addr;
+    TCGv dest;
 
     if ((insn & 0x38) != 0)
         opsize = OS_BYTE;
     else
         opsize = OS_LONG;
     op = (insn >> 6) & 3;
-    src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
     src2 = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
+    dest = tcg_temp_new();
 
     gen_flush_flags(s);
-    tmp = gen_new_qreg(QMODE_I32);
+    tmp = tcg_temp_new();
     if (opsize == OS_BYTE)
-        gen_op_and32(tmp, src2, gen_im32(7));
+        tcg_gen_andi_i32(tmp, src2, 7);
     else
-        gen_op_and32(tmp, src2, gen_im32(31));
+        tcg_gen_andi_i32(tmp, src2, 31);
     src2 = tmp;
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_shl32(tmp, gen_im32(1), src2);
-
-    gen_op_btest(src1, 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);
     switch (op) {
     case 1: /* bchg */
-        gen_op_xor32(dest, src1, tmp);
+        tcg_gen_xor_i32(dest, src1, tmp);
         break;
     case 2: /* bclr */
-        gen_op_not32(tmp, tmp);
-        gen_op_and32(dest, src1, tmp);
+        tcg_gen_not_i32(tmp, tmp);
+        tcg_gen_and_i32(dest, src1, tmp);
         break;
     case 3: /* bset */
-        gen_op_or32(dest, src1, tmp);
+        tcg_gen_or_i32(dest, src1, tmp);
         break;
     default: /* btst */
         break;
     }
     if (op)
-        gen_ea(s, insn, opsize, dest, &addr);
+        DEST_EA(insn, opsize, dest, &addr);
 }
 
 DISAS_INSN(sats)
 {
-    int reg;
-    int tmp;
-    int l1;
-
+    TCGv reg;
     reg = DREG(insn, 0);
-    tmp = gen_new_qreg(QMODE_I32);
     gen_flush_flags(s);
-    gen_op_and32(tmp, QREG_CC_DEST, gen_im32(CCF_V));
-    l1 = gen_new_label();
-    gen_op_jmp_z32(tmp, l1);
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_shr32(tmp, reg, gen_im32(31));
-    gen_op_xor32(tmp, tmp, gen_im32(0x80000000));
-    gen_op_mov32(reg, tmp);
-    gen_set_label(l1);
-    gen_logic_cc(s, tmp);
+    gen_helper_sats(reg, reg, QREG_CC_DEST);
+    gen_logic_cc(s, reg);
 }
 
-static void gen_push(DisasContext *s, int val)
+static void gen_push(DisasContext *s, TCGv val)
 {
-    int tmp;
+    TCGv tmp;
 
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_sub32(tmp, QREG_SP, gen_im32(4));
+    tmp = tcg_temp_new();
+    tcg_gen_subi_i32(tmp, QREG_SP, 4);
     gen_store(s, OS_LONG, tmp, val);
-    gen_op_mov32(QREG_SP, tmp);
+    tcg_gen_mov_i32(QREG_SP, tmp);
 }
 
 DISAS_INSN(movem)
 {
-    int addr;
+    TCGv addr;
     int i;
     uint16_t mask;
-    int reg;
-    int tmp;
+    TCGv reg;
+    TCGv tmp;
     int is_load;
 
     mask = lduw_code(s->pc);
     s->pc += 2;
     tmp = gen_lea(s, insn, OS_LONG);
-    addr = gen_new_qreg(QMODE_I32);
-    gen_op_mov32(addr, tmp);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    addr = tcg_temp_new();
+    tcg_gen_mov_i32(addr, tmp);
     is_load = ((insn & 0x0400) != 0);
     for (i = 0; i < 16; i++, mask >>= 1) {
         if (mask & 1) {
@@ -981,12 +1116,12 @@ DISAS_INSN(movem)
                 reg = AREG(i, 0);
             if (is_load) {
                 tmp = gen_load(s, OS_LONG, addr, 0);
-                gen_op_mov32(reg, tmp);
+                tcg_gen_mov_i32(reg, tmp);
             } else {
                 gen_store(s, OS_LONG, addr, reg);
             }
             if (mask != 1)
-                gen_op_add32(addr, addr, gen_im32(4));
+                tcg_gen_addi_i32(addr, addr, 4);
         }
     }
 }
@@ -995,12 +1130,11 @@ DISAS_INSN(bitop_im)
 {
     int opsize;
     int op;
-    int src1;
+    TCGv src1;
     uint32_t mask;
     int bitnum;
-    int tmp;
-    int addr;
-    int dest;
+    TCGv tmp;
+    TCGv addr;
 
     if ((insn & 0x38) != 0)
         opsize = OS_BYTE;
@@ -1015,104 +1149,110 @@ DISAS_INSN(bitop_im)
         return;
     }
 
-    src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
 
     gen_flush_flags(s);
-    tmp = gen_new_qreg(QMODE_I32);
     if (opsize == OS_BYTE)
         bitnum &= 7;
     else
         bitnum &= 31;
     mask = 1 << bitnum;
 
-    gen_op_btest(src1, gen_im32(mask));
-    if (op)
-        dest = gen_new_qreg(QMODE_I32);
+    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
-        dest = -1;
-
-    switch (op) {
-    case 1: /* bchg */
-        gen_op_xor32(dest, src1, gen_im32(mask));
-        break;
-    case 2: /* bclr */
-        gen_op_and32(dest, src1, gen_im32(~mask));
-        break;
-    case 3: /* bset */
-        gen_op_or32(dest, src1, gen_im32(mask));
-        break;
-    default: /* btst */
-        break;
+        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);
+    if (op) {
+        switch (op) {
+        case 1: /* bchg */
+            tcg_gen_xori_i32(tmp, src1, mask);
+            break;
+        case 2: /* bclr */
+            tcg_gen_andi_i32(tmp, src1, ~mask);
+            break;
+        case 3: /* bset */
+            tcg_gen_ori_i32(tmp, src1, mask);
+            break;
+        default: /* btst */
+            break;
+        }
+        DEST_EA(insn, opsize, tmp, &addr);
     }
-    if (op)
-        gen_ea(s, insn, opsize, dest, &addr);
 }
 
 DISAS_INSN(arith_im)
 {
     int op;
-    int src1;
-    int dest;
-    int src2;
-    int addr;
+    uint32_t im;
+    TCGv src1;
+    TCGv dest;
+    TCGv addr;
 
     op = (insn >> 9) & 7;
-    src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr);
-    src2 = gen_im32(read_im32(s));
-    dest = gen_new_qreg(QMODE_I32);
+    SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
+    im = read_im32(s);
+    dest = tcg_temp_new();
     switch (op) {
     case 0: /* ori */
-        gen_op_or32(dest, src1, src2);
+        tcg_gen_ori_i32(dest, src1, im);
         gen_logic_cc(s, dest);
         break;
     case 1: /* andi */
-        gen_op_and32(dest, src1, src2);
+        tcg_gen_andi_i32(dest, src1, im);
         gen_logic_cc(s, dest);
         break;
     case 2: /* subi */
-        gen_op_mov32(dest, src1);
-        gen_op_update_xflag_lt(dest, src2);
-        gen_op_sub32(dest, dest, src2);
-        gen_op_update_cc_add(dest, src2);
+        tcg_gen_mov_i32(dest, src1);
+        gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
+        tcg_gen_subi_i32(dest, dest, im);
+        gen_update_cc_add(dest, gen_im32(im));
         s->cc_op = CC_OP_SUB;
         break;
     case 3: /* addi */
-        gen_op_mov32(dest, src1);
-        gen_op_add32(dest, dest, src2);
-        gen_op_update_cc_add(dest, src2);
-        gen_op_update_xflag_lt(dest, src2);
+        tcg_gen_mov_i32(dest, src1);
+        tcg_gen_addi_i32(dest, dest, im);
+        gen_update_cc_add(dest, gen_im32(im));
+        gen_helper_xflag_lt(QREG_CC_X, dest, gen_im32(im));
         s->cc_op = CC_OP_ADD;
         break;
     case 5: /* eori */
-        gen_op_xor32(dest, src1, src2);
+        tcg_gen_xori_i32(dest, src1, im);
         gen_logic_cc(s, dest);
         break;
     case 6: /* cmpi */
-        gen_op_mov32(dest, src1);
-        gen_op_sub32(dest, dest, src2);
-        gen_op_update_cc_add(dest, src2);
+        tcg_gen_mov_i32(dest, src1);
+        tcg_gen_subi_i32(dest, dest, im);
+        gen_update_cc_add(dest, gen_im32(im));
         s->cc_op = CC_OP_SUB;
         break;
     default:
         abort();
     }
     if (op != 6) {
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     }
 }
 
 DISAS_INSN(byterev)
 {
-    int reg;
+    TCGv reg;
 
     reg = DREG(insn, 0);
-    gen_op_bswap32(reg, reg);
+    tcg_gen_bswap32_i32(reg, reg);
 }
 
 DISAS_INSN(move)
 {
-    int src;
-    int dest;
+    TCGv src;
+    TCGv dest;
     int op;
     int opsize;
 
@@ -1129,18 +1269,18 @@ DISAS_INSN(move)
     default:
         abort();
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, 1, NULL);
     op = (insn >> 6) & 7;
     if (op == 1) {
         /* movea */
         /* The value will already have been sign extended.  */
         dest = AREG(insn, 9);
-        gen_op_mov32(dest, src);
+        tcg_gen_mov_i32(dest, src);
     } else {
         /* normal move */
         uint16_t dest_ea;
         dest_ea = ((insn >> 9) & 7) | (op << 3);
-        gen_ea(s, dest_ea, opsize, src, NULL);
+        DEST_EA(dest_ea, opsize, src, NULL);
         /* This will be correct because loads sign extend.  */
         gen_logic_cc(s, src);
     }
@@ -1148,35 +1288,25 @@ DISAS_INSN(move)
 
 DISAS_INSN(negx)
 {
-    int reg;
-    int dest;
-    int tmp;
+    TCGv reg;
 
     gen_flush_flags(s);
     reg = DREG(insn, 0);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (dest, gen_im32(0));
-    gen_op_subx_cc(dest, reg);
-    /* !Z is sticky.  */
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (tmp, QREG_CC_DEST);
-    gen_op_update_cc_add(dest, reg);
-    gen_op_mov32(reg, dest);
-    s->cc_op = CC_OP_DYNAMIC;
-    gen_flush_flags(s);
-    gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
-    gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
-    s->cc_op = CC_OP_FLAGS;
+    gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg);
 }
 
 DISAS_INSN(lea)
 {
-    int reg;
-    int tmp;
+    TCGv reg;
+    TCGv tmp;
 
     reg = AREG(insn, 9);
     tmp = gen_lea(s, insn, OS_LONG);
-    gen_op_mov32(reg, tmp);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
+    tcg_gen_mov_i32(reg, tmp);
 }
 
 DISAS_INSN(clr)
@@ -1196,26 +1326,25 @@ DISAS_INSN(clr)
     default:
         abort();
     }
-    gen_ea (s, insn, opsize, gen_im32(0), NULL);
+    DEST_EA(insn, opsize, gen_im32(0), NULL);
     gen_logic_cc(s, gen_im32(0));
 }
 
-static int gen_get_ccr(DisasContext *s)
+static TCGv gen_get_ccr(DisasContext *s)
 {
-    int dest;
+    TCGv dest;
 
     gen_flush_flags(s);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_get_xflag(dest);
-    gen_op_shl32(dest, dest, gen_im32(4));
-    gen_op_or32(dest, dest, QREG_CC_DEST);
+    dest = tcg_temp_new();
+    tcg_gen_shli_i32(dest, QREG_CC_X, 4);
+    tcg_gen_or_i32(dest, dest, QREG_CC_DEST);
     return dest;
 }
 
 DISAS_INSN(move_from_ccr)
 {
-    int reg;
-    int ccr;
+    TCGv reg;
+    TCGv ccr;
 
     ccr = gen_get_ccr(s);
     reg = DREG(insn, 0);
@@ -1224,45 +1353,43 @@ DISAS_INSN(move_from_ccr)
 
 DISAS_INSN(neg)
 {
-    int reg;
-    int src1;
+    TCGv reg;
+    TCGv src1;
 
     reg = DREG(insn, 0);
-    src1 = gen_new_qreg(QMODE_I32);
-    gen_op_mov32(src1, reg);
-    gen_op_neg32(reg, src1);
+    src1 = tcg_temp_new();
+    tcg_gen_mov_i32(src1, reg);
+    tcg_gen_neg_i32(reg, src1);
     s->cc_op = CC_OP_SUB;
-    gen_op_update_cc_add(reg, src1);
-    gen_op_update_xflag_lt(gen_im32(0), src1);
+    gen_update_cc_add(reg, src1);
+    gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1);
     s->cc_op = CC_OP_SUB;
 }
 
 static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
 {
-    gen_op_logic_cc(gen_im32(val & 0xf));
-    gen_op_update_xflag_tst(gen_im32((val & 0x10) >> 4));
+    tcg_gen_movi_i32(QREG_CC_DEST, val & 0xf);
+    tcg_gen_movi_i32(QREG_CC_X, (val & 0x10) >> 4);
     if (!ccr_only) {
-        gen_op_mov32(QREG_SR, gen_im32(val & 0xff00));
+        gen_helper_set_sr(cpu_env, tcg_const_i32(val & 0xff00));
     }
 }
 
 static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
 {
-    int src1;
-    int reg;
+    TCGv tmp;
+    TCGv reg;
 
     s->cc_op = CC_OP_FLAGS;
     if ((insn & 0x38) == 0)
       {
-        src1 = gen_new_qreg(QMODE_I32);
+        tmp = tcg_temp_new();
         reg = DREG(insn, 0);
-        gen_op_and32(src1, reg, gen_im32(0xf));
-        gen_op_logic_cc(src1);
-        gen_op_shr32(src1, reg, gen_im32(4));
-        gen_op_and32(src1, src1, gen_im32(1));
-        gen_op_update_xflag_tst(src1);
+        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_op_and32(QREG_SR, reg, gen_im32(0xff00));
+            gen_helper_set_sr(cpu_env, reg);
         }
       }
     else if ((insn & 0x3f) == 0x3c)
@@ -1283,63 +1410,64 @@ DISAS_INSN(move_to_ccr)
 
 DISAS_INSN(not)
 {
-    int reg;
+    TCGv reg;
 
     reg = DREG(insn, 0);
-    gen_op_not32(reg, reg);
+    tcg_gen_not_i32(reg, reg);
     gen_logic_cc(s, reg);
 }
 
 DISAS_INSN(swap)
 {
-    int dest;
-    int src1;
-    int src2;
-    int reg;
+    TCGv src1;
+    TCGv src2;
+    TCGv reg;
 
-    dest = gen_new_qreg(QMODE_I32);
-    src1 = gen_new_qreg(QMODE_I32);
-    src2 = gen_new_qreg(QMODE_I32);
+    src1 = tcg_temp_new();
+    src2 = tcg_temp_new();
     reg = DREG(insn, 0);
-    gen_op_shl32(src1, reg, gen_im32(16));
-    gen_op_shr32(src2, reg, gen_im32(16));
-    gen_op_or32(dest, src1, src2);
-    gen_op_mov32(reg, dest);
-    gen_logic_cc(s, dest);
+    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);
 }
 
 DISAS_INSN(pea)
 {
-    int tmp;
+    TCGv tmp;
 
     tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
     gen_push(s, tmp);
 }
 
 DISAS_INSN(ext)
 {
-    int reg;
     int op;
-    int tmp;
+    TCGv reg;
+    TCGv tmp;
 
     reg = DREG(insn, 0);
     op = (insn >> 6) & 7;
-    tmp = gen_new_qreg(QMODE_I32);
+    tmp = tcg_temp_new();
     if (op == 3)
-        gen_op_ext16s32(tmp, reg);
+        tcg_gen_ext16s_i32(tmp, reg);
     else
-        gen_op_ext8s32(tmp, reg);
+        tcg_gen_ext8s_i32(tmp, reg);
     if (op == 2)
         gen_partset_reg(OS_WORD, reg, tmp);
     else
-      gen_op_mov32(reg, tmp);
+        tcg_gen_mov_i32(reg, tmp);
     gen_logic_cc(s, tmp);
 }
 
 DISAS_INSN(tst)
 {
     int opsize;
-    int tmp;
+    TCGv tmp;
 
     switch ((insn >> 6) & 3) {
     case 0: /* tst.b */
@@ -1354,7 +1482,7 @@ DISAS_INSN(tst)
     default:
         abort();
     }
-    tmp = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(tmp, opsize, 1, NULL);
     gen_logic_cc(s, tmp);
 }
 
@@ -1371,23 +1499,23 @@ DISAS_INSN(illegal)
 /* ??? This should be atomic.  */
 DISAS_INSN(tas)
 {
-    int dest;
-    int src1;
-    int addr;
+    TCGv dest;
+    TCGv src1;
+    TCGv addr;
 
-    dest = gen_new_qreg(QMODE_I32);
-    src1 = gen_ea(s, insn, OS_BYTE, -1, &addr);
+    dest = tcg_temp_new();
+    SRC_EA(src1, OS_BYTE, 1, &addr);
     gen_logic_cc(s, src1);
-    gen_op_or32(dest, src1, gen_im32(0x80));
-    gen_ea(s, insn, OS_BYTE, dest, &addr);
+    tcg_gen_ori_i32(dest, src1, 0x80);
+    DEST_EA(insn, OS_BYTE, dest, &addr);
 }
 
 DISAS_INSN(mull)
 {
     uint16_t ext;
-    int reg;
-    int src1;
-    int dest;
+    TCGv reg;
+    TCGv src1;
+    TCGv dest;
 
     /* The upper 32 bits of the product are discarded, so
        muls.l and mulu.l are functionally equivalent.  */
@@ -1398,10 +1526,10 @@ DISAS_INSN(mull)
         return;
     }
     reg = DREG(ext, 12);
-    src1 = gen_ea(s, insn, OS_LONG, 0, NULL);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_mul32(dest, src1, reg);
-    gen_op_mov32(reg, dest);
+    SRC_EA(src1, OS_LONG, 0, NULL);
+    dest = tcg_temp_new();
+    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);
 }
@@ -1409,32 +1537,32 @@ DISAS_INSN(mull)
 DISAS_INSN(link)
 {
     int16_t offset;
-    int reg;
-    int tmp;
+    TCGv reg;
+    TCGv tmp;
 
     offset = ldsw_code(s->pc);
     s->pc += 2;
     reg = AREG(insn, 0);
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_sub32(tmp, QREG_SP, gen_im32(4));
+    tmp = tcg_temp_new();
+    tcg_gen_subi_i32(tmp, QREG_SP, 4);
     gen_store(s, OS_LONG, tmp, reg);
-    if (reg != QREG_SP)
-        gen_op_mov32(reg, tmp);
-    gen_op_add32(QREG_SP, tmp, gen_im32(offset));
+    if ((insn & 7) != 7)
+        tcg_gen_mov_i32(reg, tmp);
+    tcg_gen_addi_i32(QREG_SP, tmp, offset);
 }
 
 DISAS_INSN(unlk)
 {
-    int src;
-    int reg;
-    int tmp;
+    TCGv src;
+    TCGv reg;
+    TCGv tmp;
 
-    src = gen_new_qreg(QMODE_I32);
+    src = tcg_temp_new();
     reg = AREG(insn, 0);
-    gen_op_mov32(src, reg);
+    tcg_gen_mov_i32(src, reg);
     tmp = gen_load(s, OS_LONG, src, 0);
-    gen_op_mov32(reg, tmp);
-    gen_op_add32(QREG_SP, src, gen_im32(4));
+    tcg_gen_mov_i32(reg, tmp);
+    tcg_gen_addi_i32(QREG_SP, src, 4);
 }
 
 DISAS_INSN(nop)
@@ -1443,20 +1571,24 @@ DISAS_INSN(nop)
 
 DISAS_INSN(rts)
 {
-    int tmp;
+    TCGv tmp;
 
     tmp = gen_load(s, OS_LONG, QREG_SP, 0);
-    gen_op_add32(QREG_SP, QREG_SP, gen_im32(4));
+    tcg_gen_addi_i32(QREG_SP, QREG_SP, 4);
     gen_jmp(s, tmp);
 }
 
 DISAS_INSN(jump)
 {
-    int tmp;
+    TCGv tmp;
 
     /* Load the target address first to ensure correct exception
        behavior.  */
     tmp = gen_lea(s, insn, OS_LONG);
+    if (IS_NULL_QREG(tmp)) {
+        gen_addr_fault(s);
+        return;
+    }
     if ((insn & 0x40) == 0) {
         /* jsr */
         gen_push(s, gen_im32(s->pc));
@@ -1466,40 +1598,40 @@ DISAS_INSN(jump)
 
 DISAS_INSN(addsubq)
 {
-    int src1;
-    int src2;
-    int dest;
+    TCGv src1;
+    TCGv src2;
+    TCGv dest;
     int val;
-    int addr;
+    TCGv addr;
 
-    src1 = gen_ea(s, insn, OS_LONG, 0, &addr);
+    SRC_EA(src1, OS_LONG, 0, &addr);
     val = (insn >> 9) & 7;
     if (val == 0)
         val = 8;
-    src2 = gen_im32(val);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_mov32(dest, src1);
+    dest = tcg_temp_new();
+    tcg_gen_mov_i32(dest, src1);
     if ((insn & 0x38) == 0x08) {
         /* Don't update condition codes if the destination is an
            address register.  */
         if (insn & 0x0100) {
-            gen_op_sub32(dest, dest, src2);
+            tcg_gen_subi_i32(dest, dest, val);
         } else {
-            gen_op_add32(dest, dest, src2);
+            tcg_gen_addi_i32(dest, dest, val);
         }
     } else {
+        src2 = gen_im32(val);
         if (insn & 0x0100) {
-            gen_op_update_xflag_lt(dest, src2);
-            gen_op_sub32(dest, dest, src2);
+            gen_helper_xflag_lt(QREG_CC_X, dest, src2);
+            tcg_gen_subi_i32(dest, dest, val);
             s->cc_op = CC_OP_SUB;
         } else {
-            gen_op_add32(dest, dest, src2);
-            gen_op_update_xflag_lt(dest, src2);
+            tcg_gen_addi_i32(dest, dest, val);
+            gen_helper_xflag_lt(QREG_CC_X, dest, src2);
             s->cc_op = CC_OP_ADD;
         }
-        gen_op_update_cc_add(dest, src2);
+        gen_update_cc_add(dest, src2);
     }
-    gen_ea(s, insn, OS_LONG, dest, &addr);
+    DEST_EA(insn, OS_LONG, dest, &addr);
 }
 
 DISAS_INSN(tpf)
@@ -1524,7 +1656,7 @@ DISAS_INSN(branch)
     uint32_t base;
     int op;
     int l1;
-    
+
     base = s->pc;
     op = (insn >> 8) & 0xf;
     offset = (int8_t)insn;
@@ -1554,88 +1686,74 @@ DISAS_INSN(branch)
 
 DISAS_INSN(moveq)
 {
-    int tmp;
+    uint32_t val;
 
-    tmp = gen_im32((int8_t)insn);
-    gen_op_mov32(DREG(insn, 9), tmp);
-    gen_logic_cc(s, tmp);
+    val = (int8_t)insn;
+    tcg_gen_movi_i32(DREG(insn, 9), val);
+    gen_logic_cc(s, tcg_const_i32(val));
 }
 
 DISAS_INSN(mvzs)
 {
     int opsize;
-    int src;
-    int reg;
+    TCGv src;
+    TCGv reg;
 
     if (insn & 0x40)
         opsize = OS_WORD;
     else
         opsize = OS_BYTE;
-    src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL);
+    SRC_EA(src, opsize, (insn & 0x80) == 0, NULL);
     reg = DREG(insn, 9);
-    gen_op_mov32(reg, src);
+    tcg_gen_mov_i32(reg, src);
     gen_logic_cc(s, src);
 }
 
 DISAS_INSN(or)
 {
-    int reg;
-    int dest;
-    int src;
-    int addr;
+    TCGv reg;
+    TCGv dest;
+    TCGv src;
+    TCGv addr;
 
     reg = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
+    dest = tcg_temp_new();
     if (insn & 0x100) {
-        src = gen_ea(s, insn, OS_LONG, 0, &addr);
-        gen_op_or32(dest, src, reg);
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        SRC_EA(src, OS_LONG, 0, &addr);
+        tcg_gen_or_i32(dest, src, reg);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
-        gen_op_or32(dest, src, reg);
-        gen_op_mov32(reg, dest);
+        SRC_EA(src, OS_LONG, 0, NULL);
+        tcg_gen_or_i32(dest, src, reg);
+        tcg_gen_mov_i32(reg, dest);
     }
     gen_logic_cc(s, dest);
 }
 
 DISAS_INSN(suba)
 {
-    int src;
-    int reg;
+    TCGv src;
+    TCGv reg;
 
-    src = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(src, OS_LONG, 0, NULL);
     reg = AREG(insn, 9);
-    gen_op_sub32(reg, reg, src);
+    tcg_gen_sub_i32(reg, reg, src);
 }
 
 DISAS_INSN(subx)
 {
-    int reg;
-    int src;
-    int dest;
-    int tmp;
+    TCGv reg;
+    TCGv src;
 
     gen_flush_flags(s);
     reg = DREG(insn, 9);
     src = DREG(insn, 0);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (dest, reg);
-    gen_op_subx_cc(dest, src);
-    /* !Z is sticky.  */
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (tmp, QREG_CC_DEST);
-    gen_op_update_cc_add(dest, src);
-    gen_op_mov32(reg, dest);
-    s->cc_op = CC_OP_DYNAMIC;
-    gen_flush_flags(s);
-    gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
-    gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
-    s->cc_op = CC_OP_FLAGS;
+    gen_helper_subx_cc(reg, cpu_env, reg, src);
 }
 
 DISAS_INSN(mov3q)
 {
-    int src;
+    TCGv src;
     int val;
 
     val = (insn >> 9) & 7;
@@ -1643,15 +1761,15 @@ DISAS_INSN(mov3q)
         val = -1;
     src = gen_im32(val);
     gen_logic_cc(s, src);
-    gen_ea(s, insn, OS_LONG, src, NULL);
+    DEST_EA(insn, OS_LONG, src, NULL);
 }
 
 DISAS_INSN(cmp)
 {
     int op;
-    int src;
-    int reg;
-    int dest;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
     int opsize;
 
     op = (insn >> 6) & 3;
@@ -1671,165 +1789,154 @@ DISAS_INSN(cmp)
     default:
         abort();
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, 1, NULL);
     reg = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_sub32(dest, reg, src);
-    gen_op_update_cc_add(dest, src);
+    dest = tcg_temp_new();
+    tcg_gen_sub_i32(dest, reg, src);
+    gen_update_cc_add(dest, src);
 }
 
 DISAS_INSN(cmpa)
 {
     int opsize;
-    int src;
-    int reg;
-    int dest;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
 
     if (insn & 0x100) {
         opsize = OS_LONG;
     } else {
         opsize = OS_WORD;
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, 1, NULL);
     reg = AREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_sub32(dest, reg, src);
-    gen_op_update_cc_add(dest, src);
+    dest = tcg_temp_new();
+    tcg_gen_sub_i32(dest, reg, src);
+    gen_update_cc_add(dest, src);
     s->cc_op = CC_OP_SUB;
 }
 
 DISAS_INSN(eor)
 {
-    int src;
-    int reg;
-    int dest;
-    int addr;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+    TCGv addr;
 
-    src = gen_ea(s, insn, OS_LONG, 0, &addr);
+    SRC_EA(src, OS_LONG, 0, &addr);
     reg = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_xor32(dest, src, reg);
+    dest = tcg_temp_new();
+    tcg_gen_xor_i32(dest, src, reg);
     gen_logic_cc(s, dest);
-    gen_ea(s, insn, OS_LONG, dest, &addr);
+    DEST_EA(insn, OS_LONG, dest, &addr);
 }
 
 DISAS_INSN(and)
 {
-    int src;
-    int reg;
-    int dest;
-    int addr;
+    TCGv src;
+    TCGv reg;
+    TCGv dest;
+    TCGv addr;
 
     reg = DREG(insn, 9);
-    dest = gen_new_qreg(QMODE_I32);
+    dest = tcg_temp_new();
     if (insn & 0x100) {
-        src = gen_ea(s, insn, OS_LONG, 0, &addr);
-        gen_op_and32(dest, src, reg);
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        SRC_EA(src, OS_LONG, 0, &addr);
+        tcg_gen_and_i32(dest, src, reg);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
-        gen_op_and32(dest, src, reg);
-        gen_op_mov32(reg, dest);
+        SRC_EA(src, OS_LONG, 0, NULL);
+        tcg_gen_and_i32(dest, src, reg);
+        tcg_gen_mov_i32(reg, dest);
     }
     gen_logic_cc(s, dest);
 }
 
 DISAS_INSN(adda)
 {
-    int src;
-    int reg;
+    TCGv src;
+    TCGv reg;
 
-    src = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(src, OS_LONG, 0, NULL);
     reg = AREG(insn, 9);
-    gen_op_add32(reg, reg, src);
+    tcg_gen_add_i32(reg, reg, src);
 }
 
 DISAS_INSN(addx)
 {
-    int reg;
-    int src;
-    int dest;
-    int tmp;
+    TCGv reg;
+    TCGv src;
 
     gen_flush_flags(s);
     reg = DREG(insn, 9);
     src = DREG(insn, 0);
-    dest = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (dest, reg);
-    gen_op_addx_cc(dest, src);
-    /* !Z is sticky.  */
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_mov32 (tmp, QREG_CC_DEST);
-    gen_op_update_cc_add(dest, src);
-    gen_op_mov32(reg, dest);
-    s->cc_op = CC_OP_DYNAMIC;
-    gen_flush_flags(s);
-    gen_op_or32(tmp, tmp, gen_im32(~CCF_Z));
-    gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, tmp);
+    gen_helper_addx_cc(reg, cpu_env, reg, src);
     s->cc_op = CC_OP_FLAGS;
 }
 
+/* TODO: This could be implemented without helper functions.  */
 DISAS_INSN(shift_im)
 {
-    int reg;
+    TCGv reg;
     int tmp;
+    TCGv shift;
 
     reg = DREG(insn, 0);
     tmp = (insn >> 9) & 7;
     if (tmp == 0)
-      tmp = 8;
+        tmp = 8;
+    shift = gen_im32(tmp);
+    /* No need to flush flags becuse we know we will set C flag.  */
     if (insn & 0x100) {
-        gen_op_shl_im_cc(reg, tmp);
-        s->cc_op = CC_OP_SHL;
+        gen_helper_shl_cc(reg, cpu_env, reg, shift);
     } else {
         if (insn & 8) {
-            gen_op_shr_im_cc(reg, tmp);
-            s->cc_op = CC_OP_SHR;
+            gen_helper_shr_cc(reg, cpu_env, reg, shift);
         } else {
-            gen_op_sar_im_cc(reg, tmp);
-            s->cc_op = CC_OP_SAR;
+            gen_helper_sar_cc(reg, cpu_env, reg, shift);
         }
     }
+    s->cc_op = CC_OP_SHIFT;
 }
 
 DISAS_INSN(shift_reg)
 {
-    int reg;
-    int src;
-    int tmp;
+    TCGv reg;
+    TCGv shift;
 
     reg = DREG(insn, 0);
-    src = DREG(insn, 9);
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_and32(tmp, src, gen_im32(63));
+    shift = DREG(insn, 9);
+    /* Shift by zero leaves C flag unmodified.   */
+    gen_flush_flags(s);
     if (insn & 0x100) {
-        gen_op_shl_cc(reg, tmp);
-        s->cc_op = CC_OP_SHL;
+        gen_helper_shl_cc(reg, cpu_env, reg, shift);
     } else {
         if (insn & 8) {
-            gen_op_shr_cc(reg, tmp);
-            s->cc_op = CC_OP_SHR;
+            gen_helper_shr_cc(reg, cpu_env, reg, shift);
         } else {
-            gen_op_sar_cc(reg, tmp);
-            s->cc_op = CC_OP_SAR;
+            gen_helper_sar_cc(reg, cpu_env, reg, shift);
         }
     }
+    s->cc_op = CC_OP_SHIFT;
 }
 
 DISAS_INSN(ff1)
 {
-    cpu_abort(NULL, "Unimplemented insn: ff1");
+    TCGv reg;
+    reg = DREG(insn, 0);
+    gen_logic_cc(s, reg);
+    gen_helper_ff1(reg, reg);
 }
 
-static int gen_get_sr(DisasContext *s)
+static TCGv gen_get_sr(DisasContext *s)
 {
-    int ccr;
-    int sr;
+    TCGv ccr;
+    TCGv sr;
 
     ccr = gen_get_ccr(s);
-    sr = gen_new_qreg(QMODE_I32);
-    gen_op_and32(sr, QREG_SR, gen_im32(0xffe0));
-    gen_op_or32(sr, sr, ccr);
+    sr = tcg_temp_new();
+    tcg_gen_andi_i32(sr, QREG_SR, 0xffe0);
+    tcg_gen_or_i32(sr, sr, ccr);
     return sr;
 }
 
@@ -1857,8 +1964,8 @@ DISAS_INSN(strldsr)
 
 DISAS_INSN(move_from_sr)
 {
-    int reg;
-    int sr;
+    TCGv reg;
+    TCGv sr;
 
     if (IS_USER(s)) {
         gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
@@ -1901,9 +2008,7 @@ DISAS_INSN(move_to_usp)
 
 DISAS_INSN(halt)
 {
-    gen_flush_cc_op(s);
-    gen_jmp(s, gen_im32(s->pc));
-    gen_op_halt();
+    gen_exception(s, s->pc, EXCP_HALT_INSN);
 }
 
 DISAS_INSN(stop)
@@ -1919,7 +2024,8 @@ DISAS_INSN(stop)
     s->pc += 2;
 
     gen_set_sr_im(s, ext, 0);
-    disas_halt(s, insn);
+    tcg_gen_movi_i32(QREG_HALTED, 1);
+    gen_exception(s, s->pc, EXCP_HLT);
 }
 
 DISAS_INSN(rte)
@@ -1934,7 +2040,7 @@ DISAS_INSN(rte)
 DISAS_INSN(movec)
 {
     uint16_t ext;
-    int reg;
+    TCGv reg;
 
     if (IS_USER(s)) {
         gen_exception(s, s->pc - 2, EXCP_PRIVILEGE);
@@ -1949,7 +2055,7 @@ DISAS_INSN(movec)
     } else {
         reg = DREG(ext, 12);
     }
-    gen_op_movec(gen_im32(ext & 0xfff), reg);
+    gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg);
     gen_lookup_tb(s);
 }
 
@@ -1996,11 +2102,14 @@ DISAS_INSN(trap)
 DISAS_INSN(fpu)
 {
     uint16_t ext;
+    int32_t offset;
     int opmode;
-    int src;
-    int dest;
-    int res;
+    TCGv_i64 src;
+    TCGv_i64 dest;
+    TCGv_i64 res;
+    TCGv tmp32;
     int round;
+    int set_dest;
     int opsize;
 
     ext = lduw_code(s->pc);
@@ -2013,37 +2122,60 @@ DISAS_INSN(fpu)
         goto undef;
     case 3: /* fmove out */
         src = FREG(ext, 7);
+        tmp32 = tcg_temp_new_i32();
         /* fmove */
         /* ??? TODO: Proper behavior on overflow.  */
         switch ((ext >> 10) & 7) {
         case 0:
             opsize = OS_LONG;
-            res = gen_new_qreg(QMODE_I32);
-            gen_op_f64_to_i32(res, src);
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
             break;
         case 1:
             opsize = OS_SINGLE;
-            res = gen_new_qreg(QMODE_F32);
-            gen_op_f64_to_f32(res, src);
+            gen_helper_f64_to_f32(tmp32, cpu_env, src);
             break;
         case 4:
             opsize = OS_WORD;
-            res = gen_new_qreg(QMODE_I32);
-            gen_op_f64_to_i32(res, src);
-            break;
-        case 5:
-            opsize = OS_DOUBLE;
-            res = src;
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
             break;
+        case 5: /* OS_DOUBLE */
+            tcg_gen_mov_i32(tmp32, AREG(insn, 0));
+            switch ((insn >> 3) & 7) {
+            case 2:
+            case 3:
+                break;
+            case 4:
+                tcg_gen_addi_i32(tmp32, tmp32, -8);
+                break;
+            case 5:
+                offset = ldsw_code(s->pc);
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            default:
+                goto undef;
+            }
+            gen_store64(s, tmp32, src);
+            switch ((insn >> 3) & 7) {
+            case 3:
+                tcg_gen_addi_i32(tmp32, tmp32, 8);
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            case 4:
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            }
+            tcg_temp_free_i32(tmp32);
+            return;
         case 6:
             opsize = OS_BYTE;
-            res = gen_new_qreg(QMODE_I32);
-            gen_op_f64_to_i32(res, src);
+            gen_helper_f64_to_i32(tmp32, cpu_env, src);
             break;
         default:
             goto undef;
         }
-        gen_ea(s, insn, opsize, res, NULL);
+        DEST_EA(insn, opsize, tmp32, NULL);
+        tcg_temp_free_i32(tmp32);
         return;
     case 4: /* fmove to control register.  */
         switch ((ext >> 10) & 7) {
@@ -2061,7 +2193,7 @@ DISAS_INSN(fpu)
         switch ((ext >> 10) & 7) {
         case 4: /* FPCR */
             /* Not implemented.  Always return zero.  */
-            res = gen_im32(0);
+            tmp32 = gen_im32(0);
             break;
         case 1: /* FPIAR */
         case 2: /* FPSR */
@@ -2070,41 +2202,45 @@ DISAS_INSN(fpu)
                       (ext >> 10) & 7);
             goto undef;
         }
-        gen_ea(s, insn, OS_LONG, res, NULL);
+        DEST_EA(insn, OS_LONG, tmp32, NULL);
         break;
-    case 6: /* fmovem */ 
+    case 6: /* fmovem */
     case 7:
         {
-        int addr;
-        uint16_t mask;
-        if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
-            goto undef;
-        src = gen_lea(s, insn, OS_LONG);
-        addr = gen_new_qreg(QMODE_I32);
-        gen_op_mov32(addr, src);
-        mask = 0x80;
-        dest = QREG_F0;
-        while (mask) {
-            if (ext & mask) {
-                if (ext & (1 << 13)) {
-                    /* store */
-                    gen_st(s, f64, addr, dest);
-                } else {
-                    /* load */
-                    gen_ld(s, f64, dest, addr);
+            TCGv addr;
+            uint16_t mask;
+            int i;
+            if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
+                goto undef;
+            tmp32 = gen_lea(s, insn, OS_LONG);
+            if (IS_NULL_QREG(tmp32)) {
+                gen_addr_fault(s);
+                return;
+            }
+            addr = tcg_temp_new_i32();
+            tcg_gen_mov_i32(addr, tmp32);
+            mask = 0x80;
+            for (i = 0; i < 8; i++) {
+                if (ext & mask) {
+                    s->is_mem = 1;
+                    dest = FREG(i, 0);
+                    if (ext & (1 << 13)) {
+                        /* store */
+                        tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
+                    } else {
+                        /* load */
+                        tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
+                    }
+                    if (ext & (mask - 1))
+                        tcg_gen_addi_i32(addr, addr, 8);
                 }
-                if (ext & (mask - 1))
-                    gen_op_add32(addr, addr, gen_im32(8));
+                mask >>= 1;
             }
-            mask >>= 1;
-            dest++;
-        }
+            tcg_temp_free_i32(addr);
         }
         return;
     }
     if (ext & (1 << 14)) {
-        int tmp;
-
         /* Source effective address.  */
         switch ((ext >> 10) & 7) {
         case 0: opsize = OS_LONG; break;
@@ -2115,19 +2251,52 @@ DISAS_INSN(fpu)
         default:
             goto undef;
         }
-        tmp = gen_ea(s, insn, opsize, -1, NULL);
         if (opsize == OS_DOUBLE) {
-            src = tmp;
+            tmp32 = tcg_temp_new_i32();
+            tcg_gen_mov_i32(tmp32, AREG(insn, 0));
+            switch ((insn >> 3) & 7) {
+            case 2:
+            case 3:
+                break;
+            case 4:
+                tcg_gen_addi_i32(tmp32, tmp32, -8);
+                break;
+            case 5:
+                offset = ldsw_code(s->pc);
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            case 7:
+                offset = ldsw_code(s->pc);
+                offset += s->pc - 2;
+                s->pc += 2;
+                tcg_gen_addi_i32(tmp32, tmp32, offset);
+                break;
+            default:
+                goto undef;
+            }
+            src = gen_load64(s, tmp32);
+            switch ((insn >> 3) & 7) {
+            case 3:
+                tcg_gen_addi_i32(tmp32, tmp32, 8);
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            case 4:
+                tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+                break;
+            }
+            tcg_temp_free_i32(tmp32);
         } else {
-            src = gen_new_qreg(QMODE_F64);
+            SRC_EA(tmp32, opsize, 1, NULL);
+            src = tcg_temp_new_i64();
             switch (opsize) {
             case OS_LONG:
             case OS_WORD:
             case OS_BYTE:
-                gen_op_i32_to_f64(src, tmp);
+                gen_helper_i32_to_f64(src, cpu_env, tmp32);
                 break;
             case OS_SINGLE:
-                gen_op_f32_to_f64(src, tmp);
+                gen_helper_f32_to_f64(src, cpu_env, tmp32);
                 break;
             }
         }
@@ -2136,56 +2305,60 @@ DISAS_INSN(fpu)
         src = FREG(ext, 10);
     }
     dest = FREG(ext, 7);
-    res = gen_new_qreg(QMODE_F64);
+    res = tcg_temp_new_i64();
     if (opmode != 0x3a)
-        gen_op_movf64(res, dest);
+        tcg_gen_mov_f64(res, dest);
     round = 1;
+    set_dest = 1;
     switch (opmode) {
     case 0: case 0x40: case 0x44: /* fmove */
-        gen_op_movf64(res, src);
+        tcg_gen_mov_f64(res, src);
         break;
     case 1: /* fint */
-        gen_op_iround_f64(res, src);
+        gen_helper_iround_f64(res, cpu_env, src);
         round = 0;
         break;
     case 3: /* fintrz */
-        gen_op_itrunc_f64(res, src);
+        gen_helper_itrunc_f64(res, cpu_env, src);
         round = 0;
         break;
     case 4: case 0x41: case 0x45: /* fsqrt */
-        gen_op_sqrtf64(res, src);
+        gen_helper_sqrt_f64(res, cpu_env, src);
         break;
     case 0x18: case 0x58: case 0x5c: /* fabs */
-        gen_op_absf64(res, src);
+        gen_helper_abs_f64(res, src);
         break;
     case 0x1a: case 0x5a: case 0x5e: /* fneg */
-        gen_op_chsf64(res, src);
+        gen_helper_chs_f64(res, src);
         break;
     case 0x20: case 0x60: case 0x64: /* fdiv */
-        gen_op_divf64(res, res, src);
+        gen_helper_div_f64(res, cpu_env, res, src);
         break;
     case 0x22: case 0x62: case 0x66: /* fadd */
-        gen_op_addf64(res, res, src);
+        gen_helper_add_f64(res, cpu_env, res, src);
         break;
     case 0x23: case 0x63: case 0x67: /* fmul */
-        gen_op_mulf64(res, res, src);
+        gen_helper_mul_f64(res, cpu_env, res, src);
         break;
     case 0x28: case 0x68: case 0x6c: /* fsub */
-        gen_op_subf64(res, res, src);
+        gen_helper_sub_f64(res, cpu_env, res, src);
         break;
     case 0x38: /* fcmp */
-        gen_op_sub_cmpf64(res, res, src);
-        dest = 0;
+        gen_helper_sub_cmp_f64(res, cpu_env, res, src);
+        set_dest = 0;
         round = 0;
         break;
     case 0x3a: /* ftst */
-        gen_op_movf64(res, src);
-        dest = 0;
+        tcg_gen_mov_f64(res, src);
+        set_dest = 0;
         round = 0;
         break;
     default:
         goto undef;
     }
+    if (ext & (1 << 14)) {
+        tcg_temp_free_i64(src);
+    }
     if (round) {
         if (opmode & 0x40) {
             if ((opmode & 0x4) != 0)
@@ -2195,18 +2368,19 @@ DISAS_INSN(fpu)
         }
     }
     if (round) {
-        int tmp;
-
-        tmp = gen_new_qreg(QMODE_F32);
-        gen_op_f64_to_f32(tmp, res);
-        gen_op_f32_to_f64(res, tmp);
-    } 
-    gen_op_fp_result(res);
-    if (dest) {
-        gen_op_movf64(dest, res);
+        TCGv tmp = tcg_temp_new_i32();
+        gen_helper_f64_to_f32(tmp, cpu_env, res);
+        gen_helper_f32_to_f64(res, cpu_env, tmp);
+        tcg_temp_free_i32(tmp);
+    }
+    tcg_gen_mov_f64(QREG_FP_RESULT, res);
+    if (set_dest) {
+        tcg_gen_mov_f64(dest, res);
     }
+    tcg_temp_free_i64(res);
     return;
 undef:
+    /* FIXME: Is this right for offset addressing modes?  */
     s->pc -= 2;
     disas_undef_fpu(s, insn);
 }
@@ -2215,8 +2389,7 @@ DISAS_INSN(fbcc)
 {
     uint32_t offset;
     uint32_t addr;
-    int flag;
-    int zero;
+    TCGv flag;
     int l1;
 
     addr = s->pc;
@@ -2229,73 +2402,58 @@ DISAS_INSN(fbcc)
 
     l1 = gen_new_label();
     /* TODO: Raise BSUN exception.  */
-    flag = gen_new_qreg(QMODE_I32);
-    zero = gen_new_qreg(QMODE_F64);
-    gen_op_zerof64(zero);
-    gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero);
+    flag = tcg_temp_new();
+    gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT);
     /* Jump to l1 if condition is true.  */
     switch (insn & 0xf) {
     case 0: /* f */
         break;
     case 1: /* eq (=0) */
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
         break;
     case 2: /* ogt (=1) */
-        gen_op_sub32(flag, flag, gen_im32(1));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(1), l1);
         break;
     case 3: /* oge (=0 or =1) */
-        gen_op_jmp_z32(flag, l1);
-        gen_op_sub32(flag, flag, gen_im32(1));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_LEU, flag, tcg_const_i32(1), l1);
         break;
     case 4: /* olt (=-1) */
-        gen_op_jmp_s32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(0), l1);
         break;
     case 5: /* ole (=-1 or =0) */
-        gen_op_jmp_s32(flag, l1);
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_LE, flag, tcg_const_i32(0), l1);
         break;
     case 6: /* ogl (=-1 or =1) */
-        gen_op_jmp_s32(flag, l1);
-        gen_op_sub32(flag, flag, gen_im32(1));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_andi_i32(flag, flag, 1);
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
         break;
     case 7: /* or (=2) */
-        gen_op_sub32(flag, flag, gen_im32(2));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
         break;
     case 8: /* un (<2) */
-        gen_op_sub32(flag, flag, gen_im32(2));
-        gen_op_jmp_s32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1);
         break;
     case 9: /* ueq (=0 or =2) */
-        gen_op_jmp_z32(flag, l1);
-        gen_op_sub32(flag, flag, gen_im32(2));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_andi_i32(flag, flag, 1);
+        tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
         break;
     case 10: /* ugt (>0) */
-        /* ??? Add jmp_gtu.  */
-        gen_op_sub32(flag, flag, gen_im32(1));
-        gen_op_jmp_ns32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_GT, flag, tcg_const_i32(0), l1);
         break;
     case 11: /* uge (>=0) */
-        gen_op_jmp_ns32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_GE, flag, tcg_const_i32(0), l1);
         break;
     case 12: /* ult (=-1 or =2) */
-        gen_op_jmp_s32(flag, l1);
-        gen_op_sub32(flag, flag, gen_im32(2));
-        gen_op_jmp_z32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_GEU, flag, tcg_const_i32(2), l1);
         break;
     case 13: /* ule (!=1) */
-        gen_op_sub32(flag, flag, gen_im32(1));
-        gen_op_jmp_nz32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(1), l1);
         break;
     case 14: /* ne (!=0) */
-        gen_op_jmp_nz32(flag, l1);
+        tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
         break;
     case 15: /* t */
-        gen_op_mov32(flag, gen_im32(1));
+        tcg_gen_br(l1);
         break;
     }
     gen_jmp_tb(s, 0, s->pc);
@@ -2315,450 +2473,536 @@ DISAS_INSN(fsave)
     qemu_assert(0, "FSAVE not implemented");
 }
 
-static disas_proc opcode_table[65536];
-
-static void
-register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
+static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
 {
-  int i;
-  int from;
-  int to;
-
-  /* Sanity check.  All set bits must be included in the mask.  */
-  if (opcode & ~mask)
-      abort();
-  /* This could probably be cleverer.  For now just optimize the case where
-     the top bits are known.  */
-  /* Find the first zero bit in the mask.  */
-  i = 0x8000;
-  while ((i & mask) != 0)
-      i >>= 1;
-  /* Iterate over all combinations of this and lower bits.  */
-  if (i == 0)
-      i = 1;
-  else
-      i <<= 1;
-  from = opcode & ~(i - 1);
-  to = from + i;
-  for (i = from; i < to; i++) {
-      if ((i & mask) == opcode)
-          opcode_table[i] = proc;
-  }
+    TCGv tmp = tcg_temp_new();
+    if (s->env->macsr & MACSR_FI) {
+        if (upper)
+            tcg_gen_andi_i32(tmp, val, 0xffff0000);
+        else
+            tcg_gen_shli_i32(tmp, val, 16);
+    } else if (s->env->macsr & MACSR_SU) {
+        if (upper)
+            tcg_gen_sari_i32(tmp, val, 16);
+        else
+            tcg_gen_ext16s_i32(tmp, val);
+    } else {
+        if (upper)
+            tcg_gen_shri_i32(tmp, val, 16);
+        else
+            tcg_gen_ext16u_i32(tmp, val);
+    }
+    return tmp;
 }
 
-/* Register m68k opcode handlers.  Order is important.
-   Later insn override earlier ones.  */
-static void
-register_m68k_insns (m68k_def_t *def)
-{
-    uint32_t iflags;
-
-    iflags = def->insns;
-#define INSN(name, opcode, mask, isa) \
-    if (iflags & M68K_INSN_##isa) \
-        register_opcode(disas_##name, 0x##opcode, 0x##mask)
-    INSN(undef,     0000, 0000, CF_A);
-    INSN(arith_im,  0080, fff8, CF_A);
-    INSN(bitrev,    00c0, fff8, CF_C);
-    INSN(bitop_reg, 0100, f1c0, CF_A);
-    INSN(bitop_reg, 0140, f1c0, CF_A);
-    INSN(bitop_reg, 0180, f1c0, CF_A);
-    INSN(bitop_reg, 01c0, f1c0, CF_A);
-    INSN(arith_im,  0280, fff8, CF_A);
-    INSN(byterev,   02c0, fff8, CF_A);
-    INSN(arith_im,  0480, fff8, CF_A);
-    INSN(ff1,       04c0, fff8, CF_C);
-    INSN(arith_im,  0680, fff8, CF_A);
-    INSN(bitop_im,  0800, ffc0, CF_A);
-    INSN(bitop_im,  0840, ffc0, CF_A);
-    INSN(bitop_im,  0880, ffc0, CF_A);
-    INSN(bitop_im,  08c0, ffc0, CF_A);
-    INSN(arith_im,  0a80, fff8, CF_A);
-    INSN(arith_im,  0c00, ff38, CF_A);
-    INSN(move,      1000, f000, CF_A);
-    INSN(move,      2000, f000, CF_A);
-    INSN(move,      3000, f000, CF_A);
-    INSN(strldsr,   40e7, ffff, CF_A);
-    INSN(negx,      4080, fff8, CF_A);
-    INSN(move_from_sr, 40c0, fff8, CF_A);
-    INSN(lea,       41c0, f1c0, CF_A);
-    INSN(clr,       4200, ff00, CF_A);
-    INSN(undef,     42c0, ffc0, CF_A);
-    INSN(move_from_ccr, 42c0, fff8, CF_A);
-    INSN(neg,       4480, fff8, CF_A);
-    INSN(move_to_ccr, 44c0, ffc0, CF_A);
-    INSN(not,       4680, fff8, CF_A);
-    INSN(move_to_sr, 46c0, ffc0, CF_A);
-    INSN(pea,       4840, ffc0, CF_A);
-    INSN(swap,      4840, fff8, CF_A);
-    INSN(movem,     48c0, fbc0, CF_A);
-    INSN(ext,       4880, fff8, CF_A);
-    INSN(ext,       48c0, fff8, CF_A);
-    INSN(ext,       49c0, fff8, CF_A);
-    INSN(tst,       4a00, ff00, CF_A);
-    INSN(tas,       4ac0, ffc0, CF_B);
-    INSN(halt,      4ac8, ffff, CF_A);
-    INSN(pulse,     4acc, ffff, CF_A);
-    INSN(illegal,   4afc, ffff, CF_A);
-    INSN(mull,      4c00, ffc0, CF_A);
-    INSN(divl,      4c40, ffc0, CF_A);
-    INSN(sats,      4c80, fff8, CF_B);
-    INSN(trap,      4e40, fff0, CF_A);
-    INSN(link,      4e50, fff8, CF_A);
-    INSN(unlk,      4e58, fff8, CF_A);
-    INSN(move_to_usp, 4e60, fff8, CF_B);
-    INSN(move_from_usp, 4e68, fff8, CF_B);
-    INSN(nop,       4e71, ffff, CF_A);
-    INSN(stop,      4e72, ffff, CF_A);
-    INSN(rte,       4e73, ffff, CF_A);
-    INSN(rts,       4e75, ffff, CF_A);
-    INSN(movec,     4e7b, ffff, CF_A);
-    INSN(jump,      4e80, ffc0, CF_A);
-    INSN(jump,      4ec0, ffc0, CF_A);
-    INSN(addsubq,   5180, f1c0, CF_A);
-    INSN(scc,       50c0, f0f8, CF_A);
-    INSN(addsubq,   5080, f1c0, CF_A);
-    INSN(tpf,       51f8, fff8, CF_A);
-    INSN(branch,    6000, f000, CF_A);
-    INSN(moveq,     7000, f100, CF_A);
-    INSN(mvzs,      7100, f100, CF_B);
-    INSN(or,        8000, f000, CF_A);
-    INSN(divw,      80c0, f0c0, CF_A);
-    INSN(addsub,    9000, f000, CF_A);
-    INSN(subx,      9180, f1f8, CF_A);
-    INSN(suba,      91c0, f1c0, CF_A);
-    INSN(undef_mac, a000, f000, CF_A);
-    INSN(mov3q,     a140, f1c0, CF_B);
-    INSN(cmp,       b000, f1c0, CF_B); /* cmp.b */
-    INSN(cmp,       b040, f1c0, CF_B); /* cmp.w */
-    INSN(cmpa,      b0c0, f1c0, CF_B); /* cmpa.w */
-    INSN(cmp,       b080, f1c0, CF_A);
-    INSN(cmpa,      b1c0, f1c0, CF_A);
-    INSN(eor,       b180, f1c0, CF_A);
-    INSN(and,       c000, f000, CF_A);
-    INSN(mulw,      c0c0, f0c0, CF_A);
-    INSN(addsub,    d000, f000, CF_A);
-    INSN(addx,      d180, f1f8, CF_A);
-    INSN(adda,      d1c0, f1c0, CF_A);
-    INSN(shift_im,  e080, f0f0, CF_A);
-    INSN(shift_reg, e0a0, f0f0, CF_A);
-    INSN(undef_fpu, f000, f000, CF_A);
-    INSN(fpu,       f200, ffc0, CF_FPU);
-    INSN(fbcc,      f280, ffc0, CF_FPU);
-    INSN(frestore,  f340, ffc0, CF_FPU);
-    INSN(fsave,     f340, ffc0, CF_FPU);
-    INSN(intouch,   f340, ffc0, CF_A);
-    INSN(cpushl,    f428, ff38, CF_A);
-    INSN(wddata,    fb00, ff00, CF_A);
-    INSN(wdebug,    fbc0, ffc0, CF_A);
-#undef INSN
+static void gen_mac_clear_flags(void)
+{
+    tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR,
+                     ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV));
 }
 
-/* ??? 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(CPUState * env, DisasContext *s)
+DISAS_INSN(mac)
 {
-    uint16_t insn;
+    TCGv rx;
+    TCGv ry;
+    uint16_t ext;
+    int acc;
+    TCGv tmp;
+    TCGv addr;
+    TCGv loadval;
+    int dual;
+    TCGv saved_flags;
 
-    insn = lduw_code(s->pc);
+    if (!s->done_mac) {
+        s->mactmp = tcg_temp_new_i64();
+        s->done_mac = 1;
+    }
+
+    ext = lduw_code(s->pc);
     s->pc += 2;
 
-    opcode_table[insn](s, insn);
-}
+    acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
+    dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
+    if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
+        disas_undef(s, insn);
+        return;
+    }
+    if (insn & 0x30) {
+        /* MAC with load.  */
+        tmp = gen_lea(s, insn, OS_LONG);
+        addr = tcg_temp_new();
+        tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK);
+        /* Load the value now to ensure correct exception behavior.
+           Perform writeback after reading the MAC inputs.  */
+        loadval = gen_load(s, OS_LONG, addr, 0);
+
+        acc ^= 1;
+        rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
+        ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
+    } else {
+        loadval = addr = NULL_QREG;
+        rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    }
 
+    gen_mac_clear_flags();
 #if 0
-/* Save the result of a floating point operation.  */
-static void expand_op_fp_result(qOP *qop)
-{
-    gen_op_movf64(QREG_FP_RESULT, qop->args[0]);
-}
+    l1 = -1;
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
+        /* Skip the multiply if we know we will ignore it.  */
+        l1 = gen_new_label();
+        tmp = tcg_temp_new();
+        tcg_gen_andi_i32(tmp, QREG_MACSR, 1 << (acc + 8));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+#endif
 
-/* Dummy op to indicate that the flags have been set.  */
-static void expand_op_flags_set(qOP *qop)
-{
-}
+    if ((ext & 0x0800) == 0) {
+        /* Word.  */
+        rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
+        ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
+    }
+    if (s->env->macsr & MACSR_FI) {
+        gen_helper_macmulf(s->mactmp, cpu_env, rx, ry);
+    } else {
+        if (s->env->macsr & MACSR_SU)
+            gen_helper_macmuls(s->mactmp, cpu_env, rx, ry);
+        else
+            gen_helper_macmulu(s->mactmp, cpu_env, rx, ry);
+        switch ((ext >> 9) & 3) {
+        case 1:
+            tcg_gen_shli_i64(s->mactmp, s->mactmp, 1);
+            break;
+        case 3:
+            tcg_gen_shri_i64(s->mactmp, s->mactmp, 1);
+            break;
+        }
+    }
 
-/* Convert the confition codes into CC_OP_FLAGS format.  */
-static void expand_op_flush_flags(qOP *qop)
-{
-    int cc_opreg;
+    if (dual) {
+        /* Save the overflow flag from the multiply.  */
+        saved_flags = tcg_temp_new();
+        tcg_gen_mov_i32(saved_flags, QREG_MACSR);
+    } else {
+        saved_flags = NULL_QREG;
+    }
 
-    if (qop->args[0] == CC_OP_DYNAMIC)
-        cc_opreg = QREG_CC_OP;
+#if 0
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
+        /* Skip the accumulate if the value is already saturated.  */
+        l1 = gen_new_label();
+        tmp = tcg_temp_new();
+        gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+#endif
+
+    if (insn & 0x100)
+        tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
     else
-        cc_opreg = gen_im32(qop->args[0]);
-    gen_op_helper32(QREG_NULL, cc_opreg, HELPER_flush_flags);
-}
+        tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
 
-/* Set CC_DEST after a logical or direct flag setting operation.  */
-static void expand_op_logic_cc(qOP *qop)
-{
-    gen_op_mov32(QREG_CC_DEST, qop->args[0]);
-}
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
+    else if (s->env->macsr & MACSR_SU)
+        gen_helper_macsats(cpu_env, tcg_const_i32(acc));
+    else
+        gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
 
-/* Set CC_SRC and CC_DEST after an arithmetic operation.  */
-static void expand_op_update_cc_add(qOP *qop)
-{
-    gen_op_mov32(QREG_CC_DEST, qop->args[0]);
-    gen_op_mov32(QREG_CC_SRC, qop->args[1]);
+#if 0
+    /* Disabled because conditional branches clobber temporary vars.  */
+    if (l1 != -1)
+        gen_set_label(l1);
+#endif
+
+    if (dual) {
+        /* Dual accumulate variant.  */
+        acc = (ext >> 2) & 3;
+        /* Restore the overflow flag from the multiplier.  */
+        tcg_gen_mov_i32(QREG_MACSR, saved_flags);
+#if 0
+        /* Disabled because conditional branches clobber temporary vars.  */
+        if ((s->env->macsr & MACSR_OMC) != 0) {
+            /* Skip the accumulate if the value is already saturated.  */
+            l1 = gen_new_label();
+            tmp = tcg_temp_new();
+            gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+            gen_op_jmp_nz32(tmp, l1);
+        }
+#endif
+        if (ext & 2)
+            tcg_gen_sub_i64(MACREG(acc), MACREG(acc), s->mactmp);
+        else
+            tcg_gen_add_i64(MACREG(acc), MACREG(acc), s->mactmp);
+        if (s->env->macsr & MACSR_FI)
+            gen_helper_macsatf(cpu_env, tcg_const_i32(acc));
+        else if (s->env->macsr & MACSR_SU)
+            gen_helper_macsats(cpu_env, tcg_const_i32(acc));
+        else
+            gen_helper_macsatu(cpu_env, tcg_const_i32(acc));
+#if 0
+        /* Disabled because conditional branches clobber temporary vars.  */
+        if (l1 != -1)
+            gen_set_label(l1);
+#endif
+    }
+    gen_helper_mac_set_flags(cpu_env, tcg_const_i32(acc));
+
+    if (insn & 0x30) {
+        TCGv rw;
+        rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        tcg_gen_mov_i32(rw, loadval);
+        /* FIXME: Should address writeback happen with the masked or
+           unmasked value?  */
+        switch ((insn >> 3) & 7) {
+        case 3: /* Post-increment.  */
+            tcg_gen_addi_i32(AREG(insn, 0), addr, 4);
+            break;
+        case 4: /* Pre-decrement.  */
+            tcg_gen_mov_i32(AREG(insn, 0), addr);
+        }
+    }
 }
 
-/* Update the X flag.  */
-static void expand_op_update_xflag(qOP *qop)
+DISAS_INSN(from_mac)
 {
-    int arg0;
-    int arg1;
+    TCGv rx;
+    TCGv_i64 acc;
+    int accnum;
 
-    arg0 = qop->args[0];
-    arg1 = qop->args[1];
-    if (arg1 == QREG_NULL) {
-        /* CC_X = arg0.  */
-        gen_op_mov32(QREG_CC_X, arg0);
+    rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    accnum = (insn >> 9) & 3;
+    acc = MACREG(accnum);
+    if (s->env->macsr & MACSR_FI) {
+        gen_helper_get_macf(rx, cpu_env, acc);
+    } else if ((s->env->macsr & MACSR_OMC) == 0) {
+        tcg_gen_trunc_i64_i32(rx, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_helper_get_macs(rx, acc);
     } else {
-        /* CC_X = arg0 < (unsigned)arg1.  */
-        gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
+        gen_helper_get_macu(rx, acc);
+    }
+    if (insn & 0x40) {
+        tcg_gen_movi_i64(acc, 0);
+        tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
     }
 }
 
-/* Set arg0 to the contents of the X flag.  */
-static void expand_op_get_xflag(qOP *qop)
+DISAS_INSN(move_mac)
 {
-    gen_op_mov32(qop->args[0], QREG_CC_X);
+    /* FIXME: This can be done without a helper.  */
+    int src;
+    TCGv dest;
+    src = insn & 3;
+    dest = tcg_const_i32((insn >> 9) & 3);
+    gen_helper_mac_move(cpu_env, dest, tcg_const_i32(src));
+    gen_mac_clear_flags();
+    gen_helper_mac_set_flags(cpu_env, dest);
 }
 
-/* Expand a shift by immediate.  The ISA only allows shifts by 1-8, so we
-   already know the shift is within range.  */
-static inline void expand_shift_im(qOP *qop, int right, int arith)
+DISAS_INSN(from_macsr)
 {
-    int val;
-    int reg;
-    int tmp;
-    int im;
-
-    reg = qop->args[0];
-    im = qop->args[1];
-    tmp = gen_im32(im);
-    val = gen_new_qreg(QMODE_I32);
-    gen_op_mov32(val, reg);
-    gen_op_mov32(QREG_CC_DEST, val);
-    gen_op_mov32(QREG_CC_SRC, tmp);
-    if (right) {
-        if (arith) {
-            gen_op_sar32(reg, val, tmp);
-        } else {
-            gen_op_shr32(reg, val, tmp);
-        }
-        if (im == 1)
-            tmp = QREG_NULL;
-        else
-            tmp = gen_im32(im - 1);
-    } else {
-        gen_op_shl32(reg, val, tmp);
-        tmp = gen_im32(32 - im);
-    }
-    if (tmp != QREG_NULL)
-        gen_op_shr32(val, val, tmp);
-    gen_op_and32(QREG_CC_X, val, gen_im32(1));
+    TCGv reg;
+
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    tcg_gen_mov_i32(reg, QREG_MACSR);
 }
 
-static void expand_op_shl_im_cc(qOP *qop)
+DISAS_INSN(from_mask)
 {
-    expand_shift_im(qop, 0, 0);
+    TCGv reg;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    tcg_gen_mov_i32(reg, QREG_MAC_MASK);
 }
 
-static void expand_op_shr_im_cc(qOP *qop)
+DISAS_INSN(from_mext)
 {
-    expand_shift_im(qop, 1, 0);
+    TCGv reg;
+    TCGv acc;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_get_mac_extf(reg, cpu_env, acc);
+    else
+        gen_helper_get_mac_exti(reg, cpu_env, acc);
 }
 
-static void expand_op_sar_im_cc(qOP *qop)
+DISAS_INSN(macsr_to_ccr)
 {
-    expand_shift_im(qop, 1, 1);
+    tcg_gen_movi_i32(QREG_CC_X, 0);
+    tcg_gen_andi_i32(QREG_CC_DEST, QREG_MACSR, 0xf);
+    s->cc_op = CC_OP_FLAGS;
 }
 
-/* Expand a shift by register.  */
-/* ??? This gives incorrect answers for shifts by 0 or >= 32 */
-static inline void expand_shift_reg(qOP *qop, int right, int arith)
+DISAS_INSN(to_mac)
 {
-    int val;
-    int reg;
-    int shift;
-    int tmp;
-
-    reg = qop->args[0];
-    shift = qop->args[1];
-    val = gen_new_qreg(QMODE_I32);
-    gen_op_mov32(val, reg);
-    gen_op_mov32(QREG_CC_DEST, val);
-    gen_op_mov32(QREG_CC_SRC, shift);
-    tmp = gen_new_qreg(QMODE_I32);
-    if (right) {
-        if (arith) {
-            gen_op_sar32(reg, val, shift);
-        } else {
-            gen_op_shr32(reg, val, shift);
-        }
-        gen_op_sub32(tmp, shift, gen_im32(1));
+    TCGv_i64 acc;
+    TCGv val;
+    int accnum;
+    accnum = (insn >> 9) & 3;
+    acc = MACREG(accnum);
+    SRC_EA(val, OS_LONG, 0, NULL);
+    if (s->env->macsr & MACSR_FI) {
+        tcg_gen_ext_i32_i64(acc, val);
+        tcg_gen_shli_i64(acc, acc, 8);
+    } else if (s->env->macsr & MACSR_SU) {
+        tcg_gen_ext_i32_i64(acc, val);
     } else {
-        gen_op_shl32(reg, val, shift);
-        gen_op_sub32(tmp, gen_im32(31), shift);
+        tcg_gen_extu_i32_i64(acc, val);
     }
-    gen_op_shl32(val, val, tmp);
-    gen_op_and32(QREG_CC_X, val, gen_im32(1));
+    tcg_gen_andi_i32(QREG_MACSR, QREG_MACSR, ~(MACSR_PAV0 << accnum));
+    gen_mac_clear_flags();
+    gen_helper_mac_set_flags(cpu_env, tcg_const_i32(accnum));
 }
 
-static void expand_op_shl_cc(qOP *qop)
+DISAS_INSN(to_macsr)
 {
-    expand_shift_reg(qop, 0, 0);
+    TCGv val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_helper_set_macsr(cpu_env, val);
+    gen_lookup_tb(s);
 }
 
-static void expand_op_shr_cc(qOP *qop)
+DISAS_INSN(to_mask)
 {
-    expand_shift_reg(qop, 1, 0);
+    TCGv val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000);
 }
 
-static void expand_op_sar_cc(qOP *qop)
+DISAS_INSN(to_mext)
 {
-    expand_shift_reg(qop, 1, 1);
+    TCGv val;
+    TCGv acc;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    acc = tcg_const_i32((insn & 0x400) ? 2 : 0);
+    if (s->env->macsr & MACSR_FI)
+        gen_helper_set_mac_extf(cpu_env, val, acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_helper_set_mac_exts(cpu_env, val, acc);
+    else
+        gen_helper_set_mac_extu(cpu_env, val, acc);
 }
 
-/* Set the Z flag to (arg0 & arg1) == 0.  */
-static void expand_op_btest(qOP *qop)
+static disas_proc opcode_table[65536];
+
+static void
+register_opcode (disas_proc proc, uint16_t opcode, uint16_t mask)
 {
-    int tmp;
-    int l1;
+  int i;
+  int from;
+  int to;
 
-    l1 = gen_new_label();
-    tmp = gen_new_qreg(QMODE_I32);
-    gen_op_and32(tmp, qop->args[0], qop->args[1]);
-    gen_op_and32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(~(uint32_t)CCF_Z));
-    gen_op_jmp_nz32(tmp, l1);
-    gen_op_or32(QREG_CC_DEST, QREG_CC_DEST, gen_im32(CCF_Z));
-    gen_op_label(l1);
-}
-
-/* arg0 += arg1 + CC_X */
-static void expand_op_addx_cc(qOP *qop)
-{
-    int arg0 = qop->args[0];
-    int arg1 = qop->args[1];
-    int l1, l2;
-    
-    gen_op_add32 (arg0, arg0, arg1);
-    l1 = gen_new_label();
-    l2 = gen_new_label();
-    gen_op_jmp_z32(QREG_CC_X, l1);
-    gen_op_add32(arg0, arg0, gen_im32(1));
-    gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX));
-    gen_op_set_leu32(QREG_CC_X, arg0, arg1);
-    gen_op_jmp(l2);
-    gen_set_label(l1);
-    gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD));
-    gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
-    gen_set_label(l2);
+  /* Sanity check.  All set bits must be included in the mask.  */
+  if (opcode & ~mask) {
+      fprintf(stderr,
+              "qemu internal error: bogus opcode definition %04x/%04x\n",
+              opcode, mask);
+      abort();
+  }
+  /* This could probably be cleverer.  For now just optimize the case where
+     the top bits are known.  */
+  /* Find the first zero bit in the mask.  */
+  i = 0x8000;
+  while ((i & mask) != 0)
+      i >>= 1;
+  /* Iterate over all combinations of this and lower bits.  */
+  if (i == 0)
+      i = 1;
+  else
+      i <<= 1;
+  from = opcode & ~(i - 1);
+  to = from + i;
+  for (i = from; i < to; i++) {
+      if ((i & mask) == opcode)
+          opcode_table[i] = proc;
+  }
 }
 
-/* arg0 -= arg1 + CC_X */
-static void expand_op_subx_cc(qOP *qop)
-{
-    int arg0 = qop->args[0];
-    int arg1 = qop->args[1];
-    int l1, l2;
-
-    l1 = gen_new_label();
-    l2 = gen_new_label();
-    gen_op_jmp_z32(QREG_CC_X, l1);
-    gen_op_set_leu32(QREG_CC_X, arg0, arg1);
-    gen_op_sub32(arg0, arg0, gen_im32(1));
-    gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX));
-    gen_op_jmp(l2);
-    gen_set_label(l1);
-    gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
-    gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB));
-    gen_set_label(l2);
-    gen_op_sub32 (arg0, arg0, arg1);
-}
-
-/* Expand target specific ops to generic qops.  */
-static void expand_target_qops(void)
-{
-    qOP *qop;
-    qOP *next;
-    int c;
-
-    /* Copy the list of qops, expanding target specific ops as we go.  */
-    qop = gen_first_qop;
-    gen_first_qop = NULL;
-    gen_last_qop = NULL;
-    for (; qop; qop = next) {
-        c = qop->opcode;
-        next = qop->next;
-        if (c < FIRST_TARGET_OP) {
-            qop->prev = gen_last_qop;
-            qop->next = NULL;
-            if (gen_last_qop)
-                gen_last_qop->next = qop;
-            else
-                gen_first_qop = qop;
-            gen_last_qop = qop;
-            continue;
-        }
-        switch (c) {
-#define DEF(name, nargs, barrier) \
-        case INDEX_op_##name: \
-            expand_op_##name(qop); \
-            break;
-#include "qop-target.def"
-#undef DEF
-        default:
-            cpu_abort(NULL, "Unexpanded target qop");
-        }
-    }
+/* Register m68k opcode handlers.  Order is important.
+   Later insn override earlier ones.  */
+void register_m68k_insns (CPUM68KState *env)
+{
+#define INSN(name, opcode, mask, feature) do { \
+    if (m68k_feature(env, M68K_FEATURE_##feature)) \
+        register_opcode(disas_##name, 0x##opcode, 0x##mask); \
+    } while(0)
+    INSN(undef,     0000, 0000, CF_ISA_A);
+    INSN(arith_im,  0080, fff8, CF_ISA_A);
+    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);
+    INSN(arith_im,  0280, fff8, CF_ISA_A);
+    INSN(byterev,   02c0, fff8, CF_ISA_APLUSC);
+    INSN(arith_im,  0480, fff8, CF_ISA_A);
+    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(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_ccr, 42c0, fff8, CF_ISA_A);
+    INSN(neg,       4480, fff8, CF_ISA_A);
+    INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
+    INSN(not,       4680, fff8, CF_ISA_A);
+    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);
+    INSN(tas,       4ac0, ffc0, CF_ISA_B);
+    INSN(halt,      4ac8, ffff, CF_ISA_A);
+    INSN(pulse,     4acc, ffff, CF_ISA_A);
+    INSN(illegal,   4afc, ffff, CF_ISA_A);
+    INSN(mull,      4c00, ffc0, CF_ISA_A);
+    INSN(divl,      4c40, ffc0, CF_ISA_A);
+    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);
+    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);
+    INSN(movec,     4e7b, ffff, CF_ISA_A);
+    INSN(jump,      4e80, ffc0, CF_ISA_A);
+    INSN(jump,      4ec0, ffc0, CF_ISA_A);
+    INSN(addsubq,   5180, f1c0, CF_ISA_A);
+    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);
+    /* Disable long branch instructions, then add back the ones we want.  */
+    INSN(undef,     60ff, f0ff, CF_ISA_A); /* 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(moveq,     7000, f100, CF_ISA_A);
+    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);
+    INSN(subx,      9180, f1f8, CF_ISA_A);
+    INSN(suba,      91c0, f1c0, CF_ISA_A);
+
+    INSN(undef_mac, a000, f000, CF_ISA_A);
+    INSN(mac,       a000, f100, CF_EMAC);
+    INSN(from_mac,  a180, f9b0, CF_EMAC);
+    INSN(move_mac,  a110, f9fc, CF_EMAC);
+    INSN(from_macsr,a980, f9f0, CF_EMAC);
+    INSN(from_mask, ad80, fff0, CF_EMAC);
+    INSN(from_mext, ab80, fbf0, CF_EMAC);
+    INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
+    INSN(to_mac,    a100, f9c0, CF_EMAC);
+    INSN(to_macsr,  a900, ffc0, CF_EMAC);
+    INSN(to_mext,   ab00, fbc0, CF_EMAC);
+    INSN(to_mask,   ad00, ffc0, CF_EMAC);
+
+    INSN(mov3q,     a140, f1c0, CF_ISA_B);
+    INSN(cmp,       b000, f1c0, CF_ISA_B); /* cmp.b */
+    INSN(cmp,       b040, f1c0, CF_ISA_B); /* cmp.w */
+    INSN(cmpa,      b0c0, f1c0, CF_ISA_B); /* cmpa.w */
+    INSN(cmp,       b080, f1c0, CF_ISA_A);
+    INSN(cmpa,      b1c0, f1c0, CF_ISA_A);
+    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);
+    INSN(addx,      d180, f1f8, CF_ISA_A);
+    INSN(adda,      d1c0, f1c0, CF_ISA_A);
+    INSN(shift_im,  e080, f0f0, CF_ISA_A);
+    INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
+    INSN(undef_fpu, f000, f000, CF_ISA_A);
+    INSN(fpu,       f200, ffc0, CF_FPU);
+    INSN(fbcc,      f280, ffc0, CF_FPU);
+    INSN(frestore,  f340, ffc0, CF_FPU);
+    INSN(fsave,     f340, ffc0, CF_FPU);
+    INSN(intouch,   f340, ffc0, CF_ISA_A);
+    INSN(cpushl,    f428, ff38, CF_ISA_A);
+    INSN(wddata,    fb00, ff00, CF_ISA_A);
+    INSN(wdebug,    fbc0, ffc0, CF_ISA_A);
+#undef INSN
 }
 
-/* ??? Implement this.  */
-static void
-optimize_flags(void)
+/* ??? 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(CPUState * env, DisasContext *s)
 {
+    uint16_t insn;
+
+    insn = lduw_code(s->pc);
+    s->pc += 2;
+
+    opcode_table[insn](s, insn);
 }
-#endif
 
 /* generate intermediate code for basic block 'tb'.  */
-static inline int
+static inline void
 gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
                                int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
     uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
     int j, lj;
     target_ulong pc_start;
     int pc_offset;
     int last_cc_op;
+    int num_insns;
+    int max_insns;
 
     /* generate intermediate code */
     pc_start = tb->pc;
-       
+
     dc->tb = tb;
 
-    gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
-    gen_opparam_ptr = gen_opparam_buf;
 
+    dc->env = env;
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->fpcr = env->fpcr;
     dc->user = (env->sr & SR_S) == 0;
-    nb_gen_labels = 0;
+    dc->is_mem = 0;
+    dc->done_mac = 0;
     lj = -1;
+    num_insns = 0;
+    max_insns = tb->cflags & CF_COUNT_MASK;
+    if (max_insns == 0)
+        max_insns = CF_COUNT_MASK;
+
+    gen_icount_start();
     do {
-        free_qreg = 0;
         pc_offset = dc->pc - pc_start;
         gen_throws_exception = NULL;
-        if (env->nb_breakpoints > 0) {
-            for(j = 0; j < env->nb_breakpoints; j++) {
-                if (env->breakpoints[j] == dc->pc) {
+        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
+            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
+                if (bp->pc == dc->pc) {
                     gen_exception(dc, dc->pc, EXCP_DEBUG);
                     dc->is_jmp = DISAS_JUMP;
                     break;
@@ -2776,20 +3020,29 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
             }
             gen_opc_pc[lj] = dc->pc;
             gen_opc_instr_start[lj] = 1;
+            gen_opc_icount[lj] = num_insns;
         }
+        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
+            gen_io_start();
         last_cc_op = dc->cc_op;
+        dc->insn_pc = dc->pc;
        disas_m68k_insn(env, dc);
+        num_insns++;
     } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
              !env->singlestep_enabled &&
-             (pc_offset) < (TARGET_PAGE_SIZE - 32));
+             !singlestep &&
+             (pc_offset) < (TARGET_PAGE_SIZE - 32) &&
+             num_insns < max_insns);
 
-    if (__builtin_expect(env->singlestep_enabled, 0)) {
+    if (tb->cflags & CF_LAST_IO)
+        gen_io_end();
+    if (unlikely(env->singlestep_enabled)) {
         /* Make sure the pc is updated, and raise a debug exception.  */
         if (!dc->is_jmp) {
             gen_flush_cc_op(dc);
-            gen_op_mov32(QREG_PC, gen_im32((long)dc->pc));
+            tcg_gen_movi_i32(QREG_PC, dc->pc);
         }
-        gen_op_raise_exception(EXCP_DEBUG);
+        gen_helper_raise_exception(tcg_const_i32(EXCP_DEBUG));
     } else {
         switch(dc->is_jmp) {
         case DISAS_NEXT:
@@ -2801,27 +3054,22 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
         case DISAS_UPDATE:
             gen_flush_cc_op(dc);
             /* indicate that the hash table must be used to find the next TB */
-            gen_op_mov32(QREG_T0, gen_im32(0));
-            gen_op_exit_tb();
+            tcg_gen_exit_tb(0);
             break;
         case DISAS_TB_JUMP:
             /* nothing more to generate */
             break;
         }
     }
+    gen_icount_end(tb, num_insns);
     *gen_opc_ptr = INDEX_op_end;
 
 #ifdef DEBUG_DISAS
-    if (loglevel & CPU_LOG_TB_IN_ASM) {
-        fprintf(logfile, "----------------\n");
-        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-        target_disas(logfile, pc_start, dc->pc - pc_start, 0);
-        fprintf(logfile, "\n");
-        if (loglevel & (CPU_LOG_TB_OP)) {
-            fprintf(logfile, "OP:\n");
-            dump_ops(gen_opc_buf, gen_opparam_buf);
-            fprintf(logfile, "\n");
-        }
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("----------------\n");
+        qemu_log("IN: %s\n", lookup_symbol(pc_start));
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\n");
     }
 #endif
     if (search_pc) {
@@ -2829,74 +3077,26 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
     } else {
         tb->size = dc->pc - pc_start;
+        tb->icount = num_insns;
     }
 
     //optimize_flags();
     //expand_target_qops();
-    return 0;
-}
-
-int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
-{
-    return gen_intermediate_code_internal(env, tb, 0);
-}
-
-int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
-{
-    return gen_intermediate_code_internal(env, tb, 1);
-}
-
-void cpu_reset(CPUM68KState *env)
-{
-    memset(env, 0, offsetof(CPUM68KState, breakpoints));
-#if !defined (CONFIG_USER_ONLY)
-    env->sr = 0x2700;
-#endif
-    /* ??? FP regs should be initialized to NaN.  */
-    env->cc_op = CC_OP_FLAGS;
-    /* TODO: We should set PC from the interrupt vector.  */
-    env->pc = 0;
-    tlb_flush(env, 1);
 }
 
-CPUM68KState *cpu_m68k_init(void)
+void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
 {
-    CPUM68KState *env;
-
-    env = malloc(sizeof(CPUM68KState));
-    if (!env)
-        return NULL;
-    cpu_exec_init(env);
-
-    cpu_reset(env);
-    return env;
+    gen_intermediate_code_internal(env, tb, 0);
 }
 
-void cpu_m68k_close(CPUM68KState *env)
+void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
 {
-    free(env);
+    gen_intermediate_code_internal(env, tb, 1);
 }
 
-int cpu_m68k_set_model(CPUM68KState *env, const char * name)
-{
-    m68k_def_t *def;
-
-    for (def = m68k_cpu_defs; def->name; def++) {
-        if (strcmp(def->name, name) == 0)
-            break;
-    }
-    if (!def->name)
-        return 1;
-
-    register_m68k_insns(def);
-
-    return 0;
-}
-
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
@@ -2908,13 +3108,18 @@ void cpu_dump_state(CPUState *env, FILE *f,
         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, u.d);
+                     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' : '-');
-    cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
+    cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
 }
 
+void gen_pc_load(CPUState *env, TranslationBlock *tb,
+                unsigned long searched_pc, int pc_pos, void *puc)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}