ColdFire EMAC support.
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 29 May 2007 14:57:59 +0000 (14:57 +0000)
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 29 May 2007 14:57:59 +0000 (14:57 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2895 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-exec.c
target-m68k/cpu.h
target-m68k/helper.c
target-m68k/op.c
target-m68k/qregs.def
target-m68k/translate.c

index ea18b73..c3d99d4 100644 (file)
@@ -196,7 +196,9 @@ static inline TranslationBlock *tb_find_fast(void)
     cs_base = 0;
     pc = env->PC;
 #elif defined(TARGET_M68K)
-    flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S);
+    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
+            | (env->sr & SR_S)            /* Bit  13 */
+            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
     cs_base = 0;
     pc = env->pc;
 #elif defined(TARGET_SH4)
index a81b91d..acbb516 100644 (file)
@@ -71,6 +71,14 @@ typedef struct CPUM68KState {
     uint32_t fpsr;
     float_status fp_status;
 
+    uint64_t mactmp;
+    /* EMAC Hardware deals with 48-bit values composed of one 32-bit and
+       two 8-bit parts.  We store a single 64-bit value and
+       rearrange/extend this when changing modes.  */
+    uint64_t macc[4];
+    uint32_t macsr;
+    uint32_t mac_mask;
+
     /* Temporary storage for DIV helpers.  */
     uint32_t div1;
     uint32_t div2;
@@ -143,11 +151,22 @@ enum {
 #define SR_S  0x2000
 #define SR_T  0x8000
 
+#define MACSR_PAV0  0x100
+#define MACSR_OMC   0x080
+#define MACSR_SU    0x040
+#define MACSR_FI    0x020
+#define MACSR_RT    0x010
+#define MACSR_N     0x008
+#define MACSR_Z     0x004
+#define MACSR_V     0x002
+#define MACSR_EV    0x001
+
 typedef struct m68k_def_t m68k_def_t;
 
 int cpu_m68k_set_model(CPUM68KState *env, const char * name);
 
 void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
+void m68k_set_macsr(CPUM68KState *env, uint32_t val);
 
 #define M68K_FPCR_PREC (1 << 6)
 
index 12e3f78..bdbc1de 100644 (file)
@@ -69,7 +69,6 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name)
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_C);
         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
-        m68k_set_feature(env, M68K_FEATURE_CF_MAC);
         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
         break;
     case M68K_CPUID_ANY:
@@ -77,7 +76,8 @@ int cpu_m68k_set_model(CPUM68KState *env, const char * name)
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
         m68k_set_feature(env, M68K_FEATURE_CF_ISA_C);
         m68k_set_feature(env, M68K_FEATURE_CF_FPU);
-        m68k_set_feature(env, M68K_FEATURE_CF_MAC);
+        /* MAC and EMAC are mututally exclusive, so pick EMAC.
+           It's mostly backwards compatible.  */
         m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
         m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
         break;
@@ -227,6 +227,40 @@ void helper_movec(CPUM68KState *env, int reg, uint32_t val)
     }
 }
 
+void m68k_set_macsr(CPUM68KState *env, uint32_t val)
+{
+    uint32_t acc;
+    int8_t exthigh;
+    uint8_t extlow;
+    uint64_t regval;
+    int i;
+    if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
+        for (i = 0; i < 4; i++) {
+            regval = env->macc[i];
+            exthigh = regval >> 40;
+            if (env->macsr & MACSR_FI) {
+                acc = regval >> 8;
+                extlow = regval;
+            } else {
+                acc = regval;
+                extlow = regval >> 32;
+            }
+            if (env->macsr & MACSR_FI) {
+                regval = (((uint64_t)acc) << 8) | extlow;
+                regval |= ((int64_t)exthigh) << 40;
+            } else if (env->macsr & MACSR_SU) {
+                regval = acc | (((int64_t)extlow) << 32);
+                regval |= ((int64_t)exthigh) << 40;
+            } else {
+                regval = acc | (((uint64_t)extlow) << 32);
+                regval |= ((uint64_t)(uint8_t)exthigh) << 40;
+            }
+            env->macc[i] = regval;
+        }
+    }
+    env->macsr = val;
+}
+
 /* MMU */
 
 /* TODO: This will need fixing once the MMU is implemented.  */
index d483488..febfe03 100644 (file)
@@ -285,6 +285,16 @@ OP(shr_cc)
     FORCE_RET();
 }
 
+OP(sar32)
+{
+    int32_t op2 = get_op(PARAM2);
+    uint32_t op3 = get_op(PARAM3);
+    uint32_t result;
+    result = op2 >> op3;
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
 OP(sar_cc)
 {
     int32_t op1 = get_op(PARAM1);
@@ -651,3 +661,410 @@ OP(movec)
 #define MEMSUFFIX _kernel
 #include "op_mem.h"
 #endif
+
+/* MAC unit.  */
+/* TODO: The MAC instructions use 64-bit arithmetic fairly extensively.
+   This results in fairly large ops (and sometimes other issues) on 32-bit
+   hosts.  Maybe move most of them into helpers.  */
+OP(macmuls)
+{
+    uint32_t op1 = get_op(PARAM1);
+    uint32_t op2 = get_op(PARAM2);
+    int64_t product;
+    int64_t res;
+
+    product = (uint64_t)op1 * op2;
+    res = (product << 24) >> 24;
+    if (res != product) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            if (product < 0)
+                res = ~(1ll << 50);
+            else
+                res = 1ll << 50;
+        }
+    }
+    env->mactmp = res;
+    FORCE_RET();
+}
+
+OP(macmulu)
+{
+    uint32_t op1 = get_op(PARAM1);
+    uint32_t op2 = get_op(PARAM2);
+    uint64_t product;
+
+    product = (uint64_t)op1 * op2;
+    if (product & (0xffffffull << 40)) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            product = 1ll << 50;
+        } else {
+            product &= ((1ull << 40) - 1);
+        }
+    }
+    env->mactmp = product;
+    FORCE_RET();
+}
+
+OP(macmulf)
+{
+    int32_t op1 = get_op(PARAM1);
+    int32_t op2 = get_op(PARAM2);
+    uint64_t product;
+    uint32_t remainder;
+
+    product = (uint64_t)op1 * op2;
+    if (env->macsr & MACSR_RT) {
+        remainder = product & 0xffffff;
+        product >>= 24;
+        if (remainder > 0x800000)
+            product++;
+        else if (remainder == 0x800000)
+            product += (product & 1);
+    } else {
+        product >>= 24;
+    }
+    env->mactmp = product;
+    FORCE_RET();
+}
+
+OP(macshl)
+{
+    env->mactmp <<= 1;
+}
+
+OP(macshr)
+{
+    env->mactmp >>= 1;
+}
+
+OP(macadd)
+{
+    int acc = PARAM1;
+    env->macc[acc] += env->mactmp;
+    FORCE_RET();
+}
+
+OP(macsub)
+{
+    int acc = PARAM1;
+    env->macc[acc] -= env->mactmp;
+    FORCE_RET();
+}
+
+OP(macsats)
+{
+    int acc = PARAM1;
+    int64_t sum;
+    int64_t result;
+
+    sum = env->macc[acc];
+    result = (sum << 16) >> 16;
+    if (result != sum) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            /* The result is saturated to 32 bits, despite overflow occuring
+               at 48 bits.  Seems weird, but that's what the hardware docs
+               say.  */
+            result = (result >> 63) ^ 0x7fffffff;
+        }
+    }
+    env->macc[acc] = result;
+    FORCE_RET();
+}
+
+OP(macsatu)
+{
+    int acc = PARAM1;
+    uint64_t sum;
+
+    sum = env->macc[acc];
+    if (sum & (0xffffull << 48)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            if (sum > (1ull << 53))
+                sum = 0;
+            else
+                sum = (1ull << 48) - 1;
+        } else {
+            sum &= ((1ull << 48) - 1);
+        }
+    }
+    FORCE_RET();
+}
+
+OP(macsatf)
+{
+    int acc = PARAM1;
+    int64_t sum;
+    int64_t result;
+
+    sum = env->macc[acc];
+    result = (sum << 16) >> 16;
+    if (result != sum) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            result = (result >> 63) ^ 0x7fffffffffffll;
+        }
+    }
+    env->macc[acc] = result;
+    FORCE_RET();
+}
+
+OP(mac_clear_flags)
+{
+    env->macsr &= ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV);
+}
+
+OP(mac_set_flags)
+{
+    int acc = PARAM1;
+    uint64_t val;
+    val = env->macc[acc];
+    if (val == 0)
+        env->macsr |= MACSR_Z;
+    else if (val & (1ull << 47));
+        env->macsr |= MACSR_N;
+    if (env->macsr & (MACSR_PAV0 << acc)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_FI) {
+        val = ((int64_t)val) >> 40;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else if (env->macsr & MACSR_SU) {
+        val = ((int64_t)val) >> 32;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else {
+        if ((val >> 32) != 0)
+            env->macsr |= MACSR_EV;
+    }
+    FORCE_RET();
+}
+
+OP(get_macf)
+{
+    int acc = PARAM2;
+    int64_t val;
+    int rem;
+    uint32_t result;
+
+    val = env->macc[acc];
+    if (env->macsr & MACSR_SU) {
+        /* 16-bit rounding.  */
+        rem = val & 0xffffff;
+        val = (val >> 24) & 0xffffu;
+        if (rem > 0x800000)
+            val++;
+        else if (rem == 0x800000)
+            val += (val & 1);
+    } else if (env->macsr & MACSR_RT) {
+        /* 32-bit rounding.  */
+        rem = val & 0xff;
+        val >>= 8;
+        if (rem > 0x80)
+            val++;
+        else if (rem == 0x80)
+            val += (val & 1);
+    } else {
+        /* No rounding.  */
+        val >>= 8;
+    }
+    if (env->macsr & MACSR_OMC) {
+        /* Saturate.  */
+        if (env->macsr & MACSR_SU) {
+            if (val != (uint16_t) val) {
+                result = ((val >> 63) ^ 0x7fff) & 0xffff;
+            } else {
+                result = val & 0xffff;
+            }
+        } else {
+            if (val != (uint32_t)val) {
+                result = ((uint32_t)(val >> 63) & 0x7fffffff);
+            } else {
+                result = (uint32_t)val;
+            }
+        }
+    } else {
+        /* No saturation.  */
+        if (env->macsr & MACSR_SU) {
+            result = val & 0xffff;
+        } else {
+            result = (uint32_t)val;
+        }
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(get_maci)
+{
+    int acc = PARAM2;
+    set_op(PARAM1, (uint32_t)env->macc[acc]);
+    FORCE_RET();
+}
+
+OP(get_macs)
+{
+    int acc = PARAM2;
+    int64_t val = env->macc[acc];
+    uint32_t result;
+    if (val == (int32_t)val) {
+        result = (int32_t)val;
+    } else {
+        result = (val >> 61) ^ 0x7fffffff;
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(get_macu)
+{
+    int acc = PARAM2;
+    uint64_t val = env->macc[acc];
+    uint32_t result;
+    if ((val >> 32) == 0) {
+        result = (uint32_t)val;
+    } else {
+        result = 0xffffffffu;
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(clear_mac)
+{
+    int acc = PARAM1;
+
+    env->macc[acc] = 0;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(move_mac)
+{
+    int dest = PARAM1;
+    int src = PARAM2;
+    uint32_t mask;
+    env->macc[dest] = env->macc[src];
+    mask = MACSR_PAV0 << dest;
+    if (env->macsr & (MACSR_PAV0 << src))
+        env->macsr |= mask;
+    else
+        env->macsr &= ~mask;
+    FORCE_RET();
+}
+
+OP(get_mac_extf)
+{
+    uint32_t val;
+    int acc = PARAM2;
+    val = env->macc[acc] & 0x00ff;
+    val = (env->macc[acc] >> 32) & 0xff00;
+    val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
+    val |= (env->macc[acc + 1] >> 16) & 0xff000000;
+    set_op(PARAM1, val);
+    FORCE_RET();
+}
+
+OP(get_mac_exti)
+{
+    uint32_t val;
+    int acc = PARAM2;
+    val = (env->macc[acc] >> 32) & 0xffff;
+    val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
+    set_op(PARAM1, val);
+    FORCE_RET();
+}
+
+OP(set_macf)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    env->macc[acc] = ((int64_t)val) << 8;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_macs)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    env->macc[acc] = val;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_macu)
+{
+    int acc = PARAM2;
+    uint32_t val = get_op(PARAM1);
+    env->macc[acc] = val;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_mac_extf)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    int64_t res;
+    int32_t tmp;
+    res = env->macc[acc] & 0xffffffff00ull;
+    tmp = (int16_t)(val & 0xff00);
+    res |= ((int64_t)tmp) << 32;
+    res |= val & 0xff;
+    env->macc[acc] = res;
+    res = env->macc[acc + 1] & 0xffffffff00ull;
+    tmp = (val & 0xff000000);
+    res |= ((int64_t)tmp) << 16;
+    res |= (val >> 16) & 0xff;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_mac_exts)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    int64_t res;
+    int32_t tmp;
+    res = (uint32_t)env->macc[acc];
+    tmp = (int16_t)val;
+    res |= ((int64_t)tmp) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    tmp = val & 0xffff0000;
+    res |= (int64_t)tmp << 16;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_mac_extu)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    uint64_t res;
+    res = (uint32_t)env->macc[acc];
+    res |= ((uint64_t)(val & 0xffff)) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    res |= (uint64_t)(val & 0xffff0000) << 16;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_macsr)
+{
+    m68k_set_macsr(env, get_op(PARAM1));
+}
index 08e7e85..bf568a5 100644 (file)
@@ -33,3 +33,5 @@ DEFO32(CC_X, cc_x)
 DEFO32(DIV1, div1)
 DEFO32(DIV2, div2)
 DEFO32(EXCEPTION, exception_index)
+DEFO32(MACSR, macsr)
+DEFO32(MAC_MASK, mac_mask)
index 7c91760..1d32e8f 100644 (file)
@@ -2433,6 +2433,279 @@ DISAS_INSN(fsave)
     qemu_assert(0, "FSAVE not implemented");
 }
 
+static inline int gen_mac_extract_word(DisasContext *s, int val, int upper)
+{
+    int tmp = gen_new_qreg(QMODE_I32);
+    if (s->env->macsr & MACSR_FI) {
+        if (upper)
+            gen_op_and32(tmp, val, gen_im32(0xffff0000));
+        else
+            gen_op_shl32(tmp, val, gen_im32(16));
+    } else if (s->env->macsr & MACSR_SU) {
+        if (upper)
+            gen_op_sar32(tmp, val, gen_im32(16));
+        else
+            gen_op_ext16s32(tmp, val);
+    } else {
+        if (upper)
+            gen_op_shr32(tmp, val, gen_im32(16));
+        else
+            gen_op_ext16u32(tmp, val);
+    }
+    return tmp;
+}
+
+DISAS_INSN(mac)
+{
+    int rx;
+    int ry;
+    uint16_t ext;
+    int acc;
+    int l1;
+    int tmp;
+    int addr;
+    int loadval;
+    int dual;
+    int saved_flags = -1;
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
+    dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
+    if (insn & 0x30) {
+        /* MAC with load.  */
+        tmp = gen_lea(s, insn, OS_LONG);
+        addr = gen_new_qreg(QMODE_I32);
+        gen_op_and32(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 = -1;
+        rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    }
+
+    gen_op_mac_clear_flags();
+    l1 = -1;
+    if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
+        /* Skip the multiply if we know we will ignore it.  */
+        l1 = gen_new_label();
+        tmp = gen_new_qreg(QMODE_I32);
+        gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8)));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+
+    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_op_macmulf(rx, ry);
+    } else {
+        if (s->env->macsr & MACSR_SU)
+            gen_op_macmuls(rx, ry);
+        else
+            gen_op_macmulu(rx, ry);
+        switch ((ext >> 9) & 3) {
+        case 1:
+            gen_op_macshl();
+            break;
+        case 3:
+            gen_op_macshr();
+            break;
+        }
+    }
+
+    if (dual) {
+        /* Save the overflow flag from the multiply.  */
+        saved_flags = gen_new_qreg(QMODE_I32);
+        gen_op_mov32(saved_flags, QREG_MACSR);
+    }
+
+    if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
+        /* Skip the accumulate if the value is already saturated.  */
+        l1 = gen_new_label();
+        tmp = gen_new_qreg(QMODE_I32);
+        gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+
+    if (insn & 0x100)
+        gen_op_macsub(acc);
+    else
+        gen_op_macadd(acc);
+
+    if (s->env->macsr & MACSR_FI)
+        gen_op_macsatf(acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_op_macsats(acc);
+    else
+        gen_op_macsatu(acc);
+
+    if (l1 != -1)
+        gen_set_label(l1);
+
+    if (dual) {
+        /* Dual accumulate variant.  */
+        acc = (ext >> 2) & 3;
+        /* Restore the overflow flag from the multiplier.  */
+        gen_op_mov32(QREG_MACSR, saved_flags);
+        if ((s->env->macsr & MACSR_OMC) != 0) {
+            /* Skip the accumulate if the value is already saturated.  */
+            l1 = gen_new_label();
+            tmp = gen_new_qreg(QMODE_I32);
+            gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+            gen_op_jmp_nz32(tmp, l1);
+        }
+        if (ext & 2)
+            gen_op_macsub(acc);
+        else
+            gen_op_macadd(acc);
+        if (s->env->macsr & MACSR_FI)
+            gen_op_macsatf(acc);
+        else if (s->env->macsr & MACSR_SU)
+            gen_op_macsats(acc);
+        else
+            gen_op_macsatu(acc);
+        if (l1 != -1)
+            gen_set_label(l1);
+    }
+    gen_op_mac_set_flags(acc);
+
+    if (insn & 0x30) {
+        int rw;
+        rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        gen_op_mov32(rw, loadval);
+        /* FIXME: Should address writeback happen with the masked or
+           unmasked value?  */
+        switch ((insn >> 3) & 7) {
+        case 3: /* Post-increment.  */
+            gen_op_add32(AREG(insn, 0), addr, gen_im32(4));
+            break;
+        case 4: /* Pre-decrement.  */
+            gen_op_mov32(AREG(insn, 0), addr);
+        }
+    }
+}
+
+DISAS_INSN(from_mac)
+{
+    int rx;
+    int acc;
+
+    rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = (insn >> 9) & 3;
+    if (s->env->macsr & MACSR_FI) {
+        gen_op_get_macf(rx, acc);
+    } else if ((s->env->macsr & MACSR_OMC) == 0) {
+        gen_op_get_maci(rx, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_op_get_macs(rx, acc);
+    } else {
+        gen_op_get_macu(rx, acc);
+    }
+    if (insn & 0x40)
+        gen_op_clear_mac(acc);
+}
+
+DISAS_INSN(move_mac)
+{
+    int src;
+    int dest;
+    src = insn & 3;
+    dest = (insn >> 9) & 3;
+    gen_op_move_mac(dest, src);
+    gen_op_mac_clear_flags();
+    gen_op_mac_set_flags(dest);
+}
+
+DISAS_INSN(from_macsr)
+{
+    int reg;
+
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    gen_op_mov32(reg, QREG_MACSR);
+}
+
+DISAS_INSN(from_mask)
+{
+    int reg;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    gen_op_mov32(reg, QREG_MAC_MASK);
+}
+
+DISAS_INSN(from_mext)
+{
+    int reg;
+    int acc;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = (insn & 0x400) ? 2 : 0;
+    if (s->env->macsr & MACSR_FI)
+        gen_op_get_mac_extf(reg, acc);
+    else
+        gen_op_get_mac_exti(reg, acc);
+}
+
+DISAS_INSN(macsr_to_ccr)
+{
+    gen_op_mov32(QREG_CC_X, gen_im32(0));
+    gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf));
+    s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(to_mac)
+{
+    int acc;
+    int val;
+    acc = (insn >>9) & 3;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    if (s->env->macsr & MACSR_FI) {
+        gen_op_set_macf(val, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_op_set_macs(val, acc);
+    } else {
+        gen_op_set_macu(val, acc);
+    }
+    gen_op_mac_clear_flags();
+    gen_op_mac_set_flags(acc);
+}
+
+DISAS_INSN(to_macsr)
+{
+    int val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_op_set_macsr(val);
+    gen_lookup_tb(s);
+}
+
+DISAS_INSN(to_mask)
+{
+    int val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000));
+}
+
+DISAS_INSN(to_mext)
+{
+    int val;
+    int acc;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    acc = (insn & 0x400) ? 2 : 0;
+    if (s->env->macsr & MACSR_FI)
+        gen_op_set_mac_extf(val, acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_op_set_mac_exts(val, acc);
+    else
+        gen_op_set_mac_extu(val, acc);
+}
+
 static disas_proc opcode_table[65536];
 
 static void
@@ -2545,7 +2818,20 @@ void register_m68k_insns (CPUM68KState *env)
     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 */